+
+
+
+ ]]>
+
+
+
ES
+
+
+ `;
+ let serverResponse = {
+ 'body': xmlStr1,
+ }
+ const bidResponses = spec.interpretResponse(serverResponse, bidRequest);
+ expect(bidResponses.length).to.equal(0);
+ })
+ it('It should return a banner ad.', () => {
+ let serverResponse = {
+ 'body': xmlStr,
+ }
+ setCurrentURL('https://www.sports.com');
+ const bidResponses = spec.interpretResponse(serverResponse, bidRequest);
+ expect(bidResponses.length).greaterThan(0);
+ expect(bidResponses[0].mediaType).to.be.equal(BANNER);
+ expect(bidResponses[0].ad).not.to.be.null;
+ })
+ it('It should return a video ad.', () => {
+ let serverResponse = {
+ 'body': xmlStr,
+ }
+ setCurrentURL('https://www.sports.com');
+ bidRequest.bidRequest.mediaTypes = {
+ video: {
+ sizes: [
+ [300, 250],
+ [300, 600]
+ ]
+ }
+ }
+ const bidResponses = spec.interpretResponse(serverResponse, bidRequest);
+ expect(bidResponses.length).greaterThan(0);
+ expect(bidResponses[0].mediaType).to.be.equal(VIDEO);
+ expect(bidResponses[0].vastUrl).not.to.be.null;
+ })
+ });
+});
diff --git a/test/spec/modules/amxBidAdapter_spec.js b/test/spec/modules/amxBidAdapter_spec.js
index 984c443344d..21fa2e2617c 100644
--- a/test/spec/modules/amxBidAdapter_spec.js
+++ b/test/spec/modules/amxBidAdapter_spec.js
@@ -3,6 +3,7 @@ import { spec } from 'modules/amxBidAdapter.js';
import { createEidsArray } from 'modules/userId/eids.js';
import { BANNER, VIDEO } from 'src/mediaTypes.js';
import { config } from 'src/config.js';
+import { server } from 'test/mocks/xhr.js';
import * as utils from 'src/utils.js';
const sampleRequestId = '82c91e127a9b93e';
@@ -11,7 +12,7 @@ const sampleDisplayCRID = '78827819';
// minimal example vast
const sampleVideoAd = (addlImpression) =>
`
-
00:00:15 ${addlImpression}
+
00:00:15 ${addlImpression}
`.replace(/\n+/g, '');
const sampleFPD = {
@@ -37,7 +38,7 @@ const sampleBidderRequest = {
},
gppConsent: {
gppString: 'example',
- applicableSections: 'example'
+ applicableSections: 'example',
},
auctionId: null,
@@ -209,10 +210,12 @@ describe('AmxBidAdapter', () => {
describe('getUserSync', () => {
it('Will perform an iframe sync even if there is no server response..', () => {
const syncs = spec.getUserSyncs({ iframeEnabled: true });
- expect(syncs).to.eql([{
- type: 'iframe',
- url: 'https://prebid.a-mo.net/isyn?gdpr_consent=&gdpr=0&us_privacy=&gpp=&gpp_sid='
- }]);
+ expect(syncs).to.eql([
+ {
+ type: 'iframe',
+ url: 'https://prebid.a-mo.net/isyn?gdpr_consent=&gdpr=0&us_privacy=&gpp=&gpp_sid=',
+ },
+ ]);
});
it('will return valid syncs from a server response', () => {
@@ -276,8 +279,13 @@ describe('AmxBidAdapter', () => {
});
it('will attach additional referrer info data', () => {
- const { data } = spec.buildRequests([sampleBidRequestBase], sampleBidderRequest);
- expect(data.ri.r).to.equal(sampleBidderRequest.refererInfo.topmostLocation);
+ const { data } = spec.buildRequests(
+ [sampleBidRequestBase],
+ sampleBidderRequest
+ );
+ expect(data.ri.r).to.equal(
+ sampleBidderRequest.refererInfo.topmostLocation
+ );
expect(data.ri.t).to.equal(sampleBidderRequest.refererInfo.reachedTop);
expect(data.ri.l).to.equal(sampleBidderRequest.refererInfo.numIframes);
expect(data.ri.s).to.equal(sampleBidderRequest.refererInfo.stack);
@@ -315,7 +323,7 @@ describe('AmxBidAdapter', () => {
[sampleBidRequestBase],
sampleBidderRequest
);
- delete data.m; // don't deal with "m" in this test
+ delete data.m; // don't deal with 'm' in this test
expect(data.gs).to.equal(sampleBidderRequest.gdprConsent.gdprApplies);
expect(data.gc).to.equal(sampleBidderRequest.gdprConsent.consentString);
expect(data.usp).to.equal(sampleBidderRequest.uspConsent);
@@ -343,10 +351,8 @@ describe('AmxBidAdapter', () => {
});
it('will attach sync configuration', () => {
- const request = () => spec.buildRequests(
- [sampleBidRequestBase],
- sampleBidderRequest
- );
+ const request = () =>
+ spec.buildRequests([sampleBidRequestBase], sampleBidderRequest);
const setConfig = (filterSettings) =>
config.setConfig({
@@ -355,56 +361,73 @@ describe('AmxBidAdapter', () => {
syncDelay: 2300,
syncEnabled: true,
filterSettings,
- }
+ },
});
const test = (filterSettings) => {
setConfig(filterSettings);
return request().data.sync;
- }
+ };
const base = { d: 2300, l: 2, e: true };
- const tests = [[
- undefined,
- { ...base, t: 0 }
- ], [{
- image: {
- bidders: '*',
- filter: 'include'
- },
- iframe: {
- bidders: '*',
- filter: 'include'
- }
- }, { ...base, t: 3 }], [{
- image: {
- bidders: ['amx'],
- },
- iframe: {
- bidders: '*',
- filter: 'include'
- }
- }, { ...base, t: 3 }], [{
- image: {
- bidders: ['other'],
- },
- iframe: {
- bidders: '*'
- }
- }, { ...base, t: 2 }], [{
- image: {
- bidders: ['amx']
- },
- iframe: {
- bidders: ['amx'],
- filter: 'exclude'
- }
- }, { ...base, t: 1 }]]
+ const tests = [
+ [undefined, { ...base, t: 0 }],
+ [
+ {
+ image: {
+ bidders: '*',
+ filter: 'include',
+ },
+ iframe: {
+ bidders: '*',
+ filter: 'include',
+ },
+ },
+ { ...base, t: 3 },
+ ],
+ [
+ {
+ image: {
+ bidders: ['amx'],
+ },
+ iframe: {
+ bidders: '*',
+ filter: 'include',
+ },
+ },
+ { ...base, t: 3 },
+ ],
+ [
+ {
+ image: {
+ bidders: ['other'],
+ },
+ iframe: {
+ bidders: '*',
+ },
+ },
+ { ...base, t: 2 },
+ ],
+ [
+ {
+ image: {
+ bidders: ['amx'],
+ },
+ iframe: {
+ bidders: ['amx'],
+ filter: 'exclude',
+ },
+ },
+ { ...base, t: 1 },
+ ],
+ ];
for (let i = 0, l = tests.length; i < l; i++) {
const [result, expected] = tests[i];
- expect(test(result), `input: ${JSON.stringify(result)}`).to.deep.equal(expected);
+ expect(test(result), `input: ${JSON.stringify(result)}`).to.deep.equal(
+ expected
+ );
}
});
@@ -497,7 +520,15 @@ describe('AmxBidAdapter', () => {
it('can build a video request', () => {
const { data } = spec.buildRequests(
- [{ ...sampleBidRequestVideo, params: { ...sampleBidRequestVideo.params, adUnitId: 'custom-auid' } }],
+ [
+ {
+ ...sampleBidRequestVideo,
+ params: {
+ ...sampleBidRequestVideo.params,
+ adUnitId: 'custom-auid',
+ },
+ },
+ ],
sampleBidderRequest
);
expect(Object.keys(data.m).length).to.equal(1);
@@ -659,15 +690,49 @@ describe('AmxBidAdapter', () => {
});
it('will log an event for timeout', () => {
- spec.onTimeout({
- bidder: 'example',
- bidId: 'test-bid-id',
- adUnitCode: 'div-gpt-ad',
- timeout: 300,
- auctionId: utils.getUniqueIdentifierStr(),
+ // this will use sendBeacon..
+ spec.onTimeout([
+ {
+ bidder: 'example',
+ bidId: 'test-bid-id',
+ adUnitCode: 'div-gpt-ad',
+ ortb2: {
+ site: {
+ ref: 'https://example.com',
+ },
+ },
+ params: {
+ tagId: 'tag-id',
+ },
+ timeout: 300,
+ auctionId: utils.getUniqueIdentifierStr(),
+ },
+ ]);
+
+ const [request] = server.requests;
+ request.respond(204, {'Content-Type': 'text/html'}, null);
+ expect(request.url).to.equal('https://1x1.a-mo.net/e');
+
+ if (typeof Request !== 'undefined' && 'keepalive' in Request.prototype) {
+ expect(request.fetch.request.keepalive).to.equal(true);
+ }
+
+ const {c: common, e: events} = JSON.parse(request.requestBody)
+ expect(common).to.deep.equal({
+ V: '$prebid.version$',
+ vg: '$$PREBID_GLOBAL$$',
+ U: null,
+ re: 'https://example.com',
});
- expect(firedPixels.length).to.equal(1);
- expect(firedPixels[0]).to.match(/\/hbx\/g_pbto/);
+
+ expect(events.length).to.equal(1);
+ const [event] = events;
+ expect(event.n).to.equal('g_pbto')
+ expect(event.A).to.equal('example');
+ expect(event.mid).to.equal('tag-id');
+ expect(event.cn).to.equal(300);
+ expect(event.bid).to.equal('test-bid-id');
+ expect(event.a).to.equal('div-gpt-ad');
});
it('will log an event for prebid win', () => {
diff --git a/test/spec/modules/anyclipBidAdapter_spec.js b/test/spec/modules/anyclipBidAdapter_spec.js
new file mode 100644
index 00000000000..3de36f9fe06
--- /dev/null
+++ b/test/spec/modules/anyclipBidAdapter_spec.js
@@ -0,0 +1,160 @@
+import { expect } from 'chai';
+import { spec } from 'modules/anyclipBidAdapter.js';
+
+describe('anyclipBidAdapter', function () {
+ afterEach(function () {
+ global._anyclip = undefined;
+ });
+
+ let bid;
+
+ function mockBidRequest() {
+ return {
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [300, 250],
+ [728, 90],
+ [468, 60]
+ ]
+ }
+ },
+ bidder: 'anyclip',
+ params: {
+ publisherId: '12345',
+ supplyTagId: '-mptNo0BycUG4oCDgGrU'
+ }
+ };
+ };
+
+ describe('isBidRequestValid', function () {
+ this.beforeEach(function () {
+ bid = mockBidRequest();
+ });
+
+ it('should return true if all required fields are present', function () {
+ expect(spec.isBidRequestValid(bid)).to.be.true;
+ });
+ it('should return false if bidder does not correspond', function () {
+ bid.bidder = 'abc';
+ expect(spec.isBidRequestValid(bid)).to.be.false;
+ });
+ it('should return false if params object is missing', function () {
+ delete bid.params;
+ expect(spec.isBidRequestValid(bid)).to.be.false;
+ });
+ it('should return false if publisherId is missing from params', function () {
+ delete bid.params.publisherId;
+ expect(spec.isBidRequestValid(bid)).to.be.false;
+ });
+ it('should return false if supplyTagId is missing from params', function () {
+ delete bid.params.supplyTagId;
+ expect(spec.isBidRequestValid(bid)).to.be.false;
+ });
+ it('should return false if mediaTypes is missing', function () {
+ delete bid.mediaTypes;
+ expect(spec.isBidRequestValid(bid)).to.be.false;
+ });
+ it('should return false if banner is missing from mediaTypes ', function () {
+ delete bid.mediaTypes.banner;
+ expect(spec.isBidRequestValid(bid)).to.be.false;
+ });
+ it('should return false if sizes is missing from banner object', function () {
+ delete bid.mediaTypes.banner.sizes;
+ expect(spec.isBidRequestValid(bid)).to.be.false;
+ });
+ it('should return false if sizes is not an array', function () {
+ bid.mediaTypes.banner.sizes = 'test';
+ expect(spec.isBidRequestValid(bid)).to.be.false;
+ });
+ it('should return false if sizes is an empty array', function () {
+ bid.mediaTypes.banner.sizes = [];
+ expect(spec.isBidRequestValid(bid)).to.be.false;
+ });
+ });
+
+ describe('buildRequests', function () {
+ let bidderRequest = {
+ refererInfo: {
+ page: 'http://example.com',
+ domain: 'example.com',
+ },
+ timeout: 3000
+ };
+
+ this.beforeEach(function () {
+ bid = mockBidRequest();
+ Object.assign(bid, {
+ adUnitCode: '1',
+ transactionId: '123',
+ sizes: bid.mediaTypes.banner.sizes
+ });
+ });
+
+ it('when pubtag is not available, return undefined', function () {
+ expect(spec.buildRequests([bid], bidderRequest)).to.undefined;
+ });
+ it('when pubtag is available, creates a ServerRequest object with method, URL and data', function() {
+ global._anyclip = {
+ PubTag: function() {},
+ pubTag: {
+ requestBids: function() {}
+ }
+ };
+ expect(spec.buildRequests([bid], bidderRequest)).to.exist;
+ });
+ });
+
+ describe('interpretResponse', function() {
+ it('should return an empty array when parsing a no bid response', function () {
+ const response = {};
+ const request = {};
+ const bids = spec.interpretResponse(response, request);
+ expect(bids).to.have.lengthOf(0);
+ });
+ it('should return bids array', function() {
+ const response = {};
+ const request = {
+ bidRequest: {
+ bidId: 'test-bidId',
+ transactionId: '123'
+ }
+ };
+
+ global._anyclip = {
+ PubTag: function() {},
+ pubTag: {
+ getBids: function(transactionId) {
+ return {
+ adServer: {
+ bid: {
+ ad: 'test-ad',
+ creativeId: 'test-crId',
+ meta: {
+ advertiserDomains: ['anyclip.com']
+ },
+ width: 300,
+ height: 250,
+ ttl: 300
+ }
+ },
+ cpm: 1.23,
+ }
+ }
+ }
+ };
+ const bids = spec.interpretResponse(response, request);
+ expect(bids).to.have.lengthOf(1);
+ expect(bids[0].requestId).to.equal('test-bidId');
+ expect(bids[0].cpm).to.equal(1.23);
+ expect(bids[0].currency).to.equal('USD');
+ expect(bids[0].width).to.equal(300);
+ expect(bids[0].height).to.equal(250);
+ expect(bids[0].ad).to.equal('test-ad');
+ expect(bids[0].ttl).to.equal(300);
+ expect(bids[0].creativeId).to.equal('test-crId');
+ expect(bids[0].netRevenue).to.false;
+ expect(bids[0].meta.advertiserDomains[0]).to.equal('anyclip.com');
+ });
+ });
+});
diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js
index 193e8aa64f8..cc86a8a0aaa 100644
--- a/test/spec/modules/appnexusBidAdapter_spec.js
+++ b/test/spec/modules/appnexusBidAdapter_spec.js
@@ -343,7 +343,7 @@ describe('AppNexusAdapter', function () {
expect(payload.tags[0].hb_source).to.deep.equal(1);
});
- it('should include ORTB video values when video params were not set', function () {
+ it('should include ORTB video values when matching video params were not all set', function () {
let bidRequest = deepClone(bidRequests[0]);
bidRequest.params = {
placementId: '1234235',
@@ -377,6 +377,61 @@ describe('AppNexusAdapter', function () {
expect(payload.tags[0].video_frameworks).to.deep.equal([1, 4])
});
+ it('should include ORTB video values when video params is empty - case 1', function () {
+ let bidRequest = deepClone(bidRequests[0]);
+ bidRequest.mediaTypes = {
+ video: {
+ playerSize: [640, 480],
+ context: 'outstream',
+ placement: 3,
+ mimes: ['video/mp4'],
+ skip: 0,
+ minduration: 5,
+ api: [1, 5, 6],
+ playbackmethod: [2, 4]
+ }
+ };
+
+ const request = spec.buildRequests([bidRequest]);
+ const payload = JSON.parse(request.data);
+
+ expect(payload.tags[0].video).to.deep.equal({
+ minduration: 5,
+ playback_method: 2,
+ skippable: false,
+ context: 4
+ });
+ expect(payload.tags[0].video_frameworks).to.deep.equal([1, 4])
+ });
+
+ it('should include ORTB video values when video params is empty - case 2', function () {
+ let bidRequest = deepClone(bidRequests[0]);
+ bidRequest.mediaTypes = {
+ video: {
+ playerSize: [640, 480],
+ context: 'outstream',
+ plcmt: 2,
+ startdelay: -1,
+ mimes: ['video/mp4'],
+ skip: 1,
+ minduration: 5,
+ api: [1, 5, 6],
+ playbackmethod: [2, 4]
+ }
+ };
+
+ const request = spec.buildRequests([bidRequest]);
+ const payload = JSON.parse(request.data);
+
+ expect(payload.tags[0].video).to.deep.equal({
+ minduration: 5,
+ playback_method: 2,
+ skippable: true,
+ context: 9
+ });
+ expect(payload.tags[0].video_frameworks).to.deep.equal([1, 4])
+ });
+
it('should add video property when adUnit includes a renderer', function () {
const videoData = {
mediaTypes: {
@@ -1204,6 +1259,46 @@ describe('AppNexusAdapter', function () {
expect(payload.privacy.gpp_sid).to.deep.equal([7]);
});
+ it('should add dsa information to the request via bidderRequest.ortb2.regs.ext.dsa', function () {
+ let bidderRequest = {
+ 'bidderCode': 'appnexus',
+ 'auctionId': '1d1a030790a475',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'timeout': 3000,
+ 'ortb2': {
+ 'regs': {
+ 'ext': {
+ 'dsa': {
+ 'dsarequired': 1,
+ 'pubrender': 0,
+ 'datatopub': 1,
+ 'transparency': [{
+ 'domain': 'good-domain',
+ 'dsaparams': [1, 2]
+ }, {
+ 'domain': 'bad-setup',
+ 'dsaparams': ['1', 3]
+ }]
+ }
+ }
+ }
+ }
+ };
+ bidderRequest.bids = bidRequests;
+
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ const payload = JSON.parse(request.data);
+
+ expect(payload.dsa).to.exist;
+ expect(payload.dsa.dsarequired).to.equal(1);
+ expect(payload.dsa.pubrender).to.equal(0);
+ expect(payload.dsa.datatopub).to.equal(1);
+ expect(payload.dsa.transparency).to.deep.equal([{
+ 'domain': 'good-domain',
+ 'dsaparams': [1, 2]
+ }]);
+ });
+
it('supports sending hybrid mobile app parameters', function () {
let appRequest = Object.assign({},
bidRequests[0],
@@ -1575,6 +1670,15 @@ describe('AppNexusAdapter', function () {
'viewability': {
'config': ''
},
+ 'dsa': {
+ 'behalf': 'test-behalf',
+ 'paid': 'test-paid',
+ 'transparency': [{
+ 'domain': 'good-domain',
+ 'params': [1, 2, 3]
+ }],
+ 'adrender': 1
+ },
'rtb': {
'banner': {
'content': '',
@@ -1623,6 +1727,15 @@ describe('AppNexusAdapter', function () {
'nodes': [{
'bsid': '958'
}]
+ },
+ 'dsa': {
+ 'behalf': 'test-behalf',
+ 'paid': 'test-paid',
+ 'transparency': [{
+ 'domain': 'good-domain',
+ 'params': [1, 2, 3]
+ }],
+ 'adrender': 1
}
}
}
diff --git a/test/spec/modules/asoBidAdapter_spec.js b/test/spec/modules/asoBidAdapter_spec.js
index 88016d1902c..e317a8828e7 100644
--- a/test/spec/modules/asoBidAdapter_spec.js
+++ b/test/spec/modules/asoBidAdapter_spec.js
@@ -1,30 +1,30 @@
import {expect} from 'chai';
import {spec} from 'modules/asoBidAdapter.js';
-import {parseUrl} from 'src/utils.js';
-import {BANNER, VIDEO} from 'src/mediaTypes.js';
+import {BANNER, VIDEO, NATIVE} from 'src/mediaTypes.js';
+import {OUTSTREAM} from 'src/video.js';
+import {syncAddFPDToBidderRequest} from '../../helpers/fpd';
+import {parseUrl} from '../../../src/utils';
+
+import 'modules/priceFloors.js';
+import 'modules/consentManagement.js';
+import 'modules/consentManagementUsp.js';
describe('Adserver.Online bidding adapter', function () {
const bannerRequest = {
bidder: 'aso',
params: {
- zone: 1,
- attr: {
- keywords: ['a', 'b'],
- tags: ['t1', 't2']
- }
+ zone: 1
},
adUnitCode: 'adunit-banner',
+ bidId: 'bid-banner',
mediaTypes: {
- banner: {
+ [BANNER]: {
sizes: [
[300, 250],
[240, 400],
]
}
},
- bidId: 'bidid1',
- bidderRequestId: 'bidreq1',
- auctionId: 'auctionid1',
userIdAsEids: [{
source: 'src1',
uids: [
@@ -38,32 +38,67 @@ describe('Adserver.Online bidding adapter', function () {
const videoRequest = {
bidder: 'aso',
params: {
- zone: 2,
- video: {
- api: [2],
- maxduration: 30
- }
+ zone: 2
},
+ adUnitCode: 'adunit-video',
+ bidId: 'bid-video',
mediaTypes: {
- video: {
- context: 'outstream',
+ [VIDEO]: {
+ context: OUTSTREAM,
playerSize: [[640, 480]],
protocols: [1, 2],
mimes: ['video/mp4'],
}
+ }
+ };
+
+ const nativeOrtbRequest = {
+ assets: [
+ {
+ id: 0,
+ required: 1,
+ title: {
+ len: 140
+ }
+ },
+ {
+ id: 1,
+ required: 1,
+ img: {
+ type: 3,
+ w: 300,
+ h: 600
+ }
+ }]
+ };
+
+ const nativeRequest = {
+ bidder: 'aso',
+ params: {
+ zone: 3
+ },
+ adUnitCode: 'adunit-native',
+ bidId: 'bid-native',
+ mediaTypes: {
+ [NATIVE]: {
+ ortb: {
+ ...nativeOrtbRequest
+ }
+ }
},
- adUnitCode: 'adunit-video',
- bidId: 'bidid12',
- bidderRequestId: 'bidreq2',
- auctionId: 'auctionid12'
+ nativeOrtbRequest
};
const bidderRequest = {
refererInfo: {
- numIframes: 0,
+ page: 'https://example.com/page.html',
+ topmostLocation: 'https://example.com/page.html',
reachedTop: true,
- page: 'https://example.com',
- domain: 'example.com'
+ numIframes: 1,
+ stack: [
+ 'https://example.com/page.html',
+ 'https://example.com/iframe1.html'
+ ]
}
};
@@ -81,6 +116,14 @@ describe('Adserver.Online bidding adapter', function () {
}
};
+ const gdprNotApplies = {
+ gdprApplies: false,
+ consentString: '',
+ vendorData: {
+ purpose: {}
+ }
+ };
+
const uspConsent = 'usp_consent';
describe('isBidRequestValid', function () {
@@ -110,81 +153,121 @@ describe('Adserver.Online bidding adapter', function () {
});
});
- describe('buildRequests', function () {
- it('creates a valid banner request', function () {
- bannerRequest.getFloor = () => ({ currency: 'USD', floor: 0.5 });
+ describe('requests builder', function () {
+ it('should add bid floor', function () {
+ const bidRequest = Object.assign({}, bannerRequest);
+
+ bidRequest.getFloor = () => {
+ return {
+ currency: 'USD',
+ floor: 0.5
+ }
+ };
+
+ const payload = spec.buildRequests([bidRequest], bidderRequest)[0].data;
+
+ expect(payload.imp[0].bidfloor).to.equal(0.5);
+ expect(payload.imp[0].bidfloorcur).to.equal('USD');
+ });
+ it('endpoint is valid', function () {
const requests = spec.buildRequests([bannerRequest], bidderRequest);
expect(requests).to.have.lengthOf(1);
const request = requests[0];
expect(request).to.exist;
expect(request.method).to.equal('POST');
- const parsedRequestUrl = parseUrl(request.url);
- expect(parsedRequestUrl.hostname).to.equal('srv.aso1.net');
- expect(parsedRequestUrl.pathname).to.equal('/prebid/bidder');
+ const parsedUrl = parseUrl(request.url);
+ expect(parsedUrl.hostname).to.equal('srv.aso1.net');
+ expect(parsedUrl.pathname).to.equal('/prebid/bidder');
- const query = parsedRequestUrl.search;
+ const query = parsedUrl.search;
expect(query.pbjs).to.contain('$prebid.version$');
expect(query.zid).to.equal('1');
+ });
+ it('creates a valid banner request', function () {
+ const requests = spec.buildRequests([bannerRequest], syncAddFPDToBidderRequest(bidderRequest));
+ expect(requests).to.have.lengthOf(1);
+ const request = requests[0];
+
+ expect(request).to.exist;
expect(request.data).to.exist;
const payload = request.data;
- expect(payload.site).to.not.equal(null);
- expect(payload.site.ref).to.equal('');
- expect(payload.site.page).to.equal('https://example.com');
+ expect(payload.site).to.exist;
+ expect(payload.site.page).to.equal('https://example.com/page.html');
- expect(payload.device).to.not.equal(null);
+ expect(payload.device).to.exist;
expect(payload.device.w).to.equal(window.innerWidth);
expect(payload.device.h).to.equal(window.innerHeight);
expect(payload.imp).to.have.lengthOf(1);
expect(payload.imp[0].tagid).to.equal('adunit-banner');
- expect(payload.imp[0].banner).to.not.equal(null);
- expect(payload.imp[0].banner.w).to.equal(300);
- expect(payload.imp[0].banner.h).to.equal(250);
- expect(payload.imp[0].bidfloor).to.equal(0.5);
- expect(payload.imp[0].bidfloorcur).to.equal('USD');
+ expect(payload.imp[0].banner).to.not.null;
+ expect(payload.imp[0].banner.format).to.have.lengthOf(2);
+ expect(payload.imp[0].banner.format[0].w).to.equal(300);
+ expect(payload.imp[0].banner.format[0].h).to.equal(250);
+ expect(payload.imp[0].banner.format[1].w).to.equal(240);
+ expect(payload.imp[0].banner.format[1].h).to.equal(400);
});
- it('creates a valid video request', function () {
- const requests = spec.buildRequests([videoRequest], bidderRequest);
- expect(requests).to.have.lengthOf(1);
- const request = requests[0];
+ if (FEATURES.VIDEO) {
+ it('creates a valid video request', function () {
+ const requests = spec.buildRequests([videoRequest], syncAddFPDToBidderRequest(bidderRequest));
+ expect(requests).to.have.lengthOf(1);
+ const request = requests[0];
- expect(request).to.exist;
- expect(request.method).to.equal('POST');
- const parsedRequestUrl = parseUrl(request.url);
- expect(parsedRequestUrl.hostname).to.equal('srv.aso1.net');
- expect(parsedRequestUrl.pathname).to.equal('/prebid/bidder');
+ expect(request).to.exist;
+ expect(request.data).to.not.be.empty;
- const query = parsedRequestUrl.search;
- expect(query.pbjs).to.contain('$prebid.version$');
- expect(query.zid).to.equal('2');
+ const payload = request.data;
- expect(request.data).to.not.be.empty;
+ expect(payload.site).to.exist;
+ expect(payload.site.page).to.equal('https://example.com/page.html');
- const payload = request.data;
+ expect(payload.device).to.exist;
+ expect(payload.device.w).to.equal(window.innerWidth);
+ expect(payload.device.h).to.equal(window.innerHeight);
- expect(payload.site).to.not.equal(null);
- expect(payload.site.ref).to.equal('');
- expect(payload.site.page).to.equal('https://example.com');
+ expect(payload.imp).to.have.lengthOf(1);
- expect(payload.device).to.not.equal(null);
- expect(payload.device.w).to.equal(window.innerWidth);
- expect(payload.device.h).to.equal(window.innerHeight);
+ expect(payload.imp[0].tagid).to.equal('adunit-video');
+ expect(payload.imp[0].video).to.exist;
- expect(payload.imp).to.have.lengthOf(1);
+ expect(payload.imp[0].video.w).to.equal(640);
+ expect(payload.imp[0].video.h).to.equal(480);
+ expect(payload.imp[0].banner).to.not.exist;
+ });
+ }
- expect(payload.imp[0].tagid).to.equal('adunit-video');
- expect(payload.imp[0].video).to.not.equal(null);
- expect(payload.imp[0].video.w).to.equal(640);
- expect(payload.imp[0].video.h).to.equal(480);
- expect(payload.imp[0].banner).to.be.undefined;
- });
+ if (FEATURES.NATIVE) {
+ it('creates a valid native request', function () {
+ const requests = spec.buildRequests([nativeRequest], syncAddFPDToBidderRequest(bidderRequest));
+ expect(requests).to.have.lengthOf(1);
+ const request = requests[0];
+
+ expect(request).to.exist;
+ expect(request.data).to.not.be.empty;
+
+ const payload = request.data;
+
+ expect(payload.site).to.exist;
+ expect(payload.site.page).to.equal('https://example.com/page.html');
+
+ expect(payload.device).to.exist;
+ expect(payload.device.w).to.equal(window.innerWidth);
+ expect(payload.device.h).to.equal(window.innerHeight);
+
+ expect(payload.imp).to.have.lengthOf(1);
+
+ expect(payload.imp[0].tagid).to.equal('adunit-native');
+ expect(payload.imp[0].native).to.exist;
+ expect(payload.imp[0].native.request).to.exist;
+ });
+ }
});
describe('GDPR/USP compliance', function () {
@@ -192,7 +275,7 @@ describe('Adserver.Online bidding adapter', function () {
bidderRequest.gdprConsent = gdprConsent;
bidderRequest.uspConsent = uspConsent;
- const requests = spec.buildRequests([bannerRequest], bidderRequest);
+ const requests = spec.buildRequests([bannerRequest], syncAddFPDToBidderRequest(bidderRequest));
expect(requests).to.have.lengthOf(1);
const request = requests[0];
@@ -209,7 +292,7 @@ describe('Adserver.Online bidding adapter', function () {
bidderRequest.gdprConsent = null;
bidderRequest.uspConsent = null;
- const requests = spec.buildRequests([bannerRequest], bidderRequest);
+ const requests = spec.buildRequests([bannerRequest], syncAddFPDToBidderRequest(bidderRequest));
expect(requests).to.have.lengthOf(1);
const request = requests[0];
@@ -226,18 +309,21 @@ describe('Adserver.Online bidding adapter', function () {
describe('response handler', function () {
const bannerResponse = {
body: {
- id: 'auctionid1',
- bidid: 'bidid1',
seatbid: [{
bid: [
{
- impid: 'impid1',
+ impid: 'bid-banner',
price: 0.3,
crid: 321,
adm: '',
w: 300,
h: 250,
adomain: ['example.com'],
+ ext: {
+ prebid: {
+ type: 'banner'
+ }
+ }
}
]
}],
@@ -255,18 +341,48 @@ describe('Adserver.Online bidding adapter', function () {
const videoResponse = {
body: {
- id: 'auctionid2',
- bidid: 'bidid2',
seatbid: [{
bid: [
{
- impid: 'impid2',
+ impid: 'bid-video',
price: 0.5,
crid: 123,
adm: '',
adomain: ['example.com'],
w: 640,
h: 480,
+ ext: {
+ prebid: {
+ type: 'video'
+ }
+ }
+ }
+ ]
+ }],
+ cur: 'USD'
+ },
+ };
+
+ const nativeResponse = {
+ body: {
+ seatbid: [{
+ bid: [
+ {
+ impid: 'bid-native',
+ price: 0.5,
+ crid: 123,
+ adm: JSON.stringify({
+ assets: [
+ {id: 0, title: {text: 'Title'}},
+ {id: 1, img: {type: 3, url: 'https://img'}},
+ ],
+ }),
+ adomain: ['example.com'],
+ ext: {
+ prebid: {
+ type: 'native'
+ }
+ }
}
]
}],
@@ -275,47 +391,59 @@ describe('Adserver.Online bidding adapter', function () {
};
it('handles banner responses', function () {
- bannerRequest.bidRequest = {
- mediaType: BANNER
- };
- const result = spec.interpretResponse(bannerResponse, bannerRequest);
-
- expect(result).to.have.lengthOf(1);
-
- expect(result[0]).to.exist;
- expect(result[0].width).to.equal(300);
- expect(result[0].height).to.equal(250);
- expect(result[0].mediaType).to.equal(BANNER);
- expect(result[0].creativeId).to.equal(321);
- expect(result[0].cpm).to.be.within(0.1, 0.5);
- expect(result[0].ad).to.equal('');
- expect(result[0].currency).to.equal('USD');
- expect(result[0].netRevenue).to.equal(true);
- expect(result[0].ttl).to.equal(300);
- expect(result[0].dealId).to.not.exist;
- expect(result[0].meta.advertiserDomains[0]).to.equal('example.com');
+ const request = spec.buildRequests([bannerRequest], bidderRequest)[0];
+ const bids = spec.interpretResponse(bannerResponse, request);
+
+ expect(bids).to.have.lengthOf(1);
+
+ expect(bids[0]).to.exist;
+ expect(bids[0].width).to.equal(300);
+ expect(bids[0].height).to.equal(250);
+ expect(bids[0].mediaType).to.equal(BANNER);
+ expect(bids[0].creativeId).to.equal(321);
+ expect(bids[0].cpm).to.be.within(0.1, 0.5);
+ expect(bids[0].ad).to.equal('');
+ expect(bids[0].currency).to.equal('USD');
+ expect(bids[0].netRevenue).to.equal(true);
+ expect(bids[0].ttl).to.equal(300);
+ expect(bids[0].dealId).to.not.exist;
+ expect(bids[0].meta.advertiserDomains[0]).to.equal('example.com');
});
- it('handles video responses', function () {
- const request = {
- bidRequest: videoRequest
- };
- request.bidRequest.mediaType = VIDEO;
-
- const result = spec.interpretResponse(videoResponse, request);
- expect(result).to.have.lengthOf(1);
-
- expect(result[0].width).to.equal(640);
- expect(result[0].height).to.equal(480);
- expect(result[0].mediaType).to.equal(VIDEO);
- expect(result[0].creativeId).to.equal(123);
- expect(result[0].cpm).to.equal(0.5);
- expect(result[0].vastXml).to.equal('');
- expect(result[0].renderer).to.be.a('object');
- expect(result[0].currency).to.equal('USD');
- expect(result[0].netRevenue).to.equal(true);
- expect(result[0].ttl).to.equal(300);
- });
+ if (FEATURES.VIDEO) {
+ it('handles video responses', function () {
+ const request = spec.buildRequests([videoRequest], bidderRequest)[0];
+ const bids = spec.interpretResponse(videoResponse, request);
+ expect(bids).to.have.lengthOf(1);
+
+ expect(bids[0].width).to.equal(640);
+ expect(bids[0].height).to.equal(480);
+ expect(bids[0].mediaType).to.equal(VIDEO);
+ expect(bids[0].creativeId).to.equal(123);
+ expect(bids[0].cpm).to.equal(0.5);
+ expect(bids[0].vastXml).to.equal('');
+ expect(bids[0].currency).to.equal('USD');
+ expect(bids[0].netRevenue).to.equal(true);
+ expect(bids[0].ttl).to.equal(300);
+ });
+ }
+
+ if (FEATURES.NATIVE) {
+ it('handles native responses', function () {
+ const request = spec.buildRequests([nativeRequest], bidderRequest)[0];
+ const bids = spec.interpretResponse(nativeResponse, request);
+ expect(bids).to.have.lengthOf(1);
+
+ expect(bids[0].mediaType).to.equal(NATIVE);
+ expect(bids[0].creativeId).to.equal(123);
+ expect(bids[0].cpm).to.equal(0.5);
+ expect(bids[0].currency).to.equal('USD');
+ expect(bids[0].netRevenue).to.equal(true);
+ expect(bids[0].ttl).to.equal(300);
+
+ expect(bids[0].native.ortb.assets).to.have.lengthOf(2);
+ });
+ }
it('handles empty responses', function () {
const response = [];
@@ -331,11 +459,27 @@ describe('Adserver.Online bidding adapter', function () {
};
it('should return iframe sync option', function () {
- expect(spec.getUserSyncs(syncOptions, [bannerResponse], gdprConsent, uspConsent)[0].type).to.equal('iframe');
- expect(spec.getUserSyncs(syncOptions, [bannerResponse], gdprConsent, uspConsent)[0].url).to.equal(
- 'sync_url?gdpr=1&consents_str=consentString&consents=1%2C2&us_privacy=usp_consent&'
+ const syncs = spec.getUserSyncs(syncOptions, [bannerResponse], gdprConsent, uspConsent);
+ expect(syncs).to.have.lengthOf(1);
+ expect(syncs[0].type).to.equal('iframe');
+ expect(syncs[0].url).to.equal(
+ 'sync_url?gdpr=1&consents_str=consentString&consents=1%2C2&us_privacy=usp_consent'
);
});
+
+ it('should return iframe sync option - gdpr not applies', function () {
+ const syncs = spec.getUserSyncs(syncOptions, [bannerResponse], gdprNotApplies, uspConsent);
+ expect(syncs).to.have.lengthOf(1);
+
+ expect(syncs[0].url).to.equal(
+ 'sync_url?us_privacy=usp_consent'
+ );
+ });
+
+ it('should return no sync option', function () {
+ const syncs = spec.getUserSyncs(syncOptions, [videoResponse], gdprNotApplies, uspConsent);
+ expect(syncs).to.have.lengthOf(0);
+ });
});
});
});
diff --git a/test/spec/modules/asteriobidAnalyticsAdapter_spec.js b/test/spec/modules/asteriobidAnalyticsAdapter_spec.js
new file mode 100644
index 00000000000..9be6c1dedac
--- /dev/null
+++ b/test/spec/modules/asteriobidAnalyticsAdapter_spec.js
@@ -0,0 +1,151 @@
+import asteriobidAnalytics, {storage} from 'modules/asteriobidAnalyticsAdapter.js';
+import {expect} from 'chai';
+import {server} from 'test/mocks/xhr.js';
+import * as utils from 'src/utils.js';
+import {expectEvents} from '../../helpers/analytics.js';
+
+let events = require('src/events');
+let constants = require('src/constants.json');
+
+describe('AsterioBid Analytics Adapter', function () {
+ let bidWonEvent = {
+ 'bidderCode': 'appnexus',
+ 'width': 300,
+ 'height': 250,
+ 'adId': '1ebb82ec35375e',
+ 'mediaType': 'banner',
+ 'cpm': 0.5,
+ 'requestId': '1582271863760569973',
+ 'creative_id': '96846035',
+ 'creativeId': '96846035',
+ 'ttl': 60,
+ 'currency': 'USD',
+ 'netRevenue': true,
+ 'auctionId': '9c7b70b9-b6ab-4439-9e71-b7b382797c18',
+ 'responseTimestamp': 1537521629657,
+ 'requestTimestamp': 1537521629331,
+ 'bidder': 'appnexus',
+ 'adUnitCode': 'div-gpt-ad-1460505748561-0',
+ 'timeToRespond': 326,
+ 'size': '300x250',
+ 'status': 'rendered',
+ 'eventType': 'bidWon',
+ 'ad': 'some ad',
+ 'adUrl': 'ad url'
+ };
+
+ describe('AsterioBid Analytic tests', function () {
+ beforeEach(function () {
+ sinon.stub(events, 'getEvents').returns([]);
+ });
+
+ afterEach(function () {
+ asteriobidAnalytics.disableAnalytics();
+ events.getEvents.restore();
+ });
+
+ it('support custom endpoint', function () {
+ let custom_url = 'custom url';
+ asteriobidAnalytics.enableAnalytics({
+ provider: 'asteriobid',
+ options: {
+ url: custom_url,
+ bundleId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
+ }
+ });
+
+ expect(asteriobidAnalytics.getOptions().url).to.equal(custom_url);
+ });
+
+ it('bid won event', function() {
+ let bundleId = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
+ asteriobidAnalytics.enableAnalytics({
+ provider: 'asteriobid',
+ options: {
+ bundleId: bundleId
+ }
+ });
+
+ events.emit(constants.EVENTS.BID_WON, bidWonEvent);
+ asteriobidAnalytics.flush();
+
+ expect(server.requests.length).to.equal(1);
+ expect(server.requests[0].url).to.equal('https://endpt.asteriobid.com/endpoint');
+ expect(server.requests[0].requestBody.substring(0, 2)).to.equal('1:');
+
+ const pmEvents = JSON.parse(server.requests[0].requestBody.substring(2));
+ expect(pmEvents.pageViewId).to.exist;
+ expect(pmEvents.bundleId).to.equal(bundleId);
+ expect(pmEvents.ver).to.equal(1);
+ expect(pmEvents.events.length).to.equal(1);
+ expect(pmEvents.events[0].eventType).to.equal('bidWon');
+ expect(pmEvents.events[0].ad).to.be.undefined;
+ expect(pmEvents.events[0].adUrl).to.be.undefined;
+ });
+
+ it('track event without errors', function () {
+ sinon.spy(asteriobidAnalytics, 'track');
+
+ asteriobidAnalytics.enableAnalytics({
+ provider: 'asteriobid',
+ options: {
+ bundleId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
+ }
+ });
+
+ expectEvents().to.beTrackedBy(asteriobidAnalytics.track);
+ });
+ });
+
+ describe('build utm tag data', function () {
+ let getDataFromLocalStorageStub;
+ this.timeout(4000)
+ beforeEach(function () {
+ getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage');
+ getDataFromLocalStorageStub.withArgs('pm_utm_source').returns('utm_source');
+ getDataFromLocalStorageStub.withArgs('pm_utm_medium').returns('utm_medium');
+ getDataFromLocalStorageStub.withArgs('pm_utm_campaign').returns('utm_camp');
+ getDataFromLocalStorageStub.withArgs('pm_utm_term').returns('');
+ getDataFromLocalStorageStub.withArgs('pm_utm_content').returns('');
+ });
+ afterEach(function () {
+ getDataFromLocalStorageStub.restore();
+ asteriobidAnalytics.disableAnalytics()
+ });
+ it('should build utm data from local storage', function () {
+ asteriobidAnalytics.enableAnalytics({
+ provider: 'asteriobid',
+ options: {
+ bundleId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
+ }
+ });
+
+ const pmEvents = JSON.parse(server.requests[0].requestBody.substring(2));
+
+ expect(pmEvents.utmTags.utm_source).to.equal('utm_source');
+ expect(pmEvents.utmTags.utm_medium).to.equal('utm_medium');
+ expect(pmEvents.utmTags.utm_campaign).to.equal('utm_camp');
+ expect(pmEvents.utmTags.utm_term).to.equal('');
+ expect(pmEvents.utmTags.utm_content).to.equal('');
+ });
+ });
+
+ describe('build page info', function () {
+ afterEach(function () {
+ asteriobidAnalytics.disableAnalytics()
+ });
+ it('should build page info', function () {
+ asteriobidAnalytics.enableAnalytics({
+ provider: 'asteriobid',
+ options: {
+ bundleId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
+ }
+ });
+
+ const pmEvents = JSON.parse(server.requests[0].requestBody.substring(2));
+
+ expect(pmEvents.pageInfo.domain).to.equal(window.location.hostname);
+ expect(pmEvents.pageInfo.referrerDomain).to.equal(utils.parseUrl(document.referrer).hostname);
+ });
+ });
+});
diff --git a/test/spec/modules/automatadAnalyticsAdapter_spec.js b/test/spec/modules/automatadAnalyticsAdapter_spec.js
index e591f7e8e95..a7dd28a8dc0 100644
--- a/test/spec/modules/automatadAnalyticsAdapter_spec.js
+++ b/test/spec/modules/automatadAnalyticsAdapter_spec.js
@@ -6,6 +6,18 @@ import spec, {self as exports} from 'modules/automatadAnalyticsAdapter.js';
import CONSTANTS from 'src/constants.json';
import { expect } from 'chai';
+const obj = {
+ auctionInitHandler: (args) => {},
+ bidResponseHandler: (args) => {},
+ bidderDoneHandler: (args) => {},
+ bidWonHandler: (args) => {},
+ noBidHandler: (args) => {},
+ auctionDebugHandler: (args) => {},
+ bidderTimeoutHandler: (args) => {},
+ bidRequestedHandler: (args) => {},
+ bidRejectedHandler: (args) => {}
+}
+
const {
AUCTION_DEBUG,
BID_REQUESTED,
@@ -117,20 +129,10 @@ describe('Automatad Analytics Adapter', () => {
describe('Behaviour of the adapter when the sdk has loaded', () => {
before(() => {
spec.enableAnalytics(CONFIG_WITH_DEBUG);
- const obj = {
- auctionInitHandler: (args) => {},
- bidResponseHandler: (args) => {},
- bidderDoneHandler: (args) => {},
- bidWonHandler: (args) => {},
- noBidHandler: (args) => {},
- auctionDebugHandler: (args) => {},
- bidderTimeoutHandler: (args) => {},
- bidRequestedHandler: (args) => {},
- bidRejectedHandler: (args) => {}
- }
global.window.atmtdAnalytics = obj
-
+ exports.qBeingUsed = false
+ exports.qTraversalComplete = undefined
Object.keys(obj).forEach((fn) => sandbox.spy(global.window.atmtdAnalytics, fn))
})
beforeEach(() => {
@@ -143,8 +145,12 @@ describe('Automatad Analytics Adapter', () => {
sandbox.restore();
});
after(() => {
+ const handlers = global.window.atmtdAnalytics
+ Object.keys(handlers).forEach((handler) => global.window.atmtdAnalytics[handler].reset())
global.window.atmtdAnalytics = undefined;
spec.disableAnalytics();
+ exports.qBeingUsed = false
+ exports.qTraversalComplete = undefined
})
it('Should call the auctionInitHandler when the auction init event is fired', () => {
@@ -298,6 +304,85 @@ describe('Automatad Analytics Adapter', () => {
});
});
+ describe('Behaviour of the adapter when the SDK has loaded midway', () => {
+ before(() => {
+ spec.enableAnalytics(CONFIG_WITH_DEBUG);
+ })
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+
+ global.window.atmtdAnalytics = undefined
+
+ exports.qBeingUsed = undefined
+ exports.qTraversalComplete = undefined
+ exports.queuePointer = 0
+ exports.retryCount = 0
+ exports.__atmtdAnalyticsQueue.length = 0
+
+ clock = sandbox.useFakeTimers();
+
+ sandbox.spy(exports.__atmtdAnalyticsQueue, 'push')
+ });
+ afterEach(() => {
+ sandbox.restore();
+ });
+ after(() => {
+ spec.disableAnalytics();
+ })
+
+ it('Should push to the que when the auctionInit event is fired and push to the que even after SDK has loaded after auctionInit event', () => {
+ events.emit(BID_RESPONSE, {type: BID_RESPONSE})
+ expect(exports.__atmtdAnalyticsQueue.push.called).to.equal(true)
+ expect(exports.__atmtdAnalyticsQueue).to.be.an('array').to.have.lengthOf(1)
+ expect(exports.__atmtdAnalyticsQueue[0]).to.have.lengthOf(2)
+ expect(exports.__atmtdAnalyticsQueue[0][0]).to.equal(BID_RESPONSE)
+ expect(exports.__atmtdAnalyticsQueue[0][1].type).to.equal(BID_RESPONSE)
+ expect(exports.qBeingUsed).to.equal(true)
+ expect(exports.qTraversalComplete).to.equal(undefined)
+ global.window.atmtdAnalytics = obj
+ events.emit(BID_RESPONSE, {type: BID_RESPONSE})
+ expect(exports.__atmtdAnalyticsQueue.push.calledTwice).to.equal(true)
+ expect(exports.__atmtdAnalyticsQueue).to.be.an('array').to.have.lengthOf(2)
+ expect(exports.__atmtdAnalyticsQueue[1]).to.have.lengthOf(2)
+ expect(exports.__atmtdAnalyticsQueue[1][0]).to.equal(BID_RESPONSE)
+ expect(exports.__atmtdAnalyticsQueue[1][1].type).to.equal(BID_RESPONSE)
+ expect(exports.qBeingUsed).to.equal(true)
+ expect(exports.qTraversalComplete).to.equal(undefined)
+ });
+
+ it('Should push to the que when the auctionInit event is fired and push to the analytics adapter handler after the que is processed', () => {
+ expect(exports.qBeingUsed).to.equal(undefined)
+ events.emit(AUCTION_INIT, {type: AUCTION_INIT})
+ global.window.atmtdAnalytics = {...obj}
+ const handlers = global.window.atmtdAnalytics
+ Object.keys(handlers).forEach((handler) => global.window.atmtdAnalytics[handler].reset())
+ expect(exports.__atmtdAnalyticsQueue.push.called).to.equal(true)
+ expect(exports.__atmtdAnalyticsQueue).to.be.an('array').to.have.lengthOf(1)
+ expect(exports.__atmtdAnalyticsQueue[0]).to.have.lengthOf(2)
+ expect(exports.__atmtdAnalyticsQueue[0][0]).to.equal(AUCTION_INIT)
+ expect(exports.__atmtdAnalyticsQueue[0][1].type).to.equal(AUCTION_INIT)
+ expect(exports.qBeingUsed).to.equal(true)
+ expect(exports.qTraversalComplete).to.equal(undefined)
+ expect(global.window.atmtdAnalytics.auctionInitHandler.callCount).to.equal(0)
+ clock.tick(2000)
+ expect(exports.qBeingUsed).to.equal(true)
+ expect(exports.qTraversalComplete).to.equal(undefined)
+ events.emit(NO_BID, {type: NO_BID})
+ expect(exports.__atmtdAnalyticsQueue).to.be.an('array').to.have.lengthOf(2)
+ expect(exports.__atmtdAnalyticsQueue.push.calledTwice).to.equal(true)
+ clock.tick(1500)
+ expect(exports.qBeingUsed).to.equal(false)
+ expect(exports.qTraversalComplete).to.equal(true)
+ events.emit(BID_RESPONSE, {type: BID_RESPONSE})
+ expect(exports.__atmtdAnalyticsQueue).to.be.an('array').to.have.lengthOf(2)
+ expect(exports.__atmtdAnalyticsQueue.push.calledTwice).to.equal(true)
+ expect(exports.__atmtdAnalyticsQueue.push.calledThrice).to.equal(false)
+ expect(global.window.atmtdAnalytics.auctionInitHandler.calledOnce).to.equal(true)
+ expect(global.window.atmtdAnalytics.noBidHandler.calledOnce).to.equal(true)
+ expect(global.window.atmtdAnalytics.bidResponseHandler.calledOnce).to.equal(true)
+ });
+ });
+
describe('Process Events from Que when SDK still has not loaded', () => {
before(() => {
spec.enableAnalytics({
@@ -312,6 +397,8 @@ describe('Automatad Analytics Adapter', () => {
sandbox.stub(exports.__atmtdAnalyticsQueue, 'push').callsFake((args) => {
Array.prototype.push.apply(exports.__atmtdAnalyticsQueue, [args]);
})
+ exports.queuePointer = 0;
+ exports.retryCount = 0;
})
beforeEach(() => {
sandbox = sinon.createSandbox();
@@ -326,7 +413,6 @@ describe('Automatad Analytics Adapter', () => {
sandbox.restore();
exports.queuePointer = 0;
exports.retryCount = 0;
- exports.__atmtdAnalyticsQueue = []
spec.disableAnalytics();
})
@@ -437,7 +523,6 @@ describe('Automatad Analytics Adapter', () => {
}
});
sandbox = sinon.createSandbox();
- sandbox.reset()
const obj = {
auctionInitHandler: (args) => {},
bidResponseHandler: (args) => {},
@@ -473,8 +558,10 @@ describe('Automatad Analytics Adapter', () => {
['impressionViewable', {type: 'impressionViewable'}]
]
});
- after(() => {
+ afterEach(() => {
sandbox.restore();
+ })
+ after(() => {
spec.disableAnalytics();
})
diff --git a/test/spec/modules/azerionedgeRtdProvider_spec.js b/test/spec/modules/azerionedgeRtdProvider_spec.js
new file mode 100644
index 00000000000..f08aaebdf55
--- /dev/null
+++ b/test/spec/modules/azerionedgeRtdProvider_spec.js
@@ -0,0 +1,183 @@
+import { config } from 'src/config.js';
+import * as azerionedgeRTD from 'modules/azerionedgeRtdProvider.js';
+import { loadExternalScript } from '../../../src/adloader.js';
+
+describe('Azerion Edge RTD submodule', function () {
+ const STORAGE_KEY = 'ht-pa-v1-a';
+ const USER_AUDIENCES = [
+ { id: '1', visits: 123 },
+ { id: '2', visits: 456 },
+ ];
+
+ const key = 'publisher123';
+ const bidders = ['appnexus', 'improvedigital'];
+ const process = { key: 'value' };
+ const dataProvider = { name: 'azerionedge', waitForIt: true };
+
+ let reqBidsConfigObj;
+ let storageStub;
+
+ beforeEach(function () {
+ config.resetConfig();
+ reqBidsConfigObj = { ortb2Fragments: { bidder: {} } };
+ window.azerionPublisherAudiences = sinon.spy();
+ storageStub = sinon.stub(azerionedgeRTD.storage, 'getDataFromLocalStorage');
+ });
+
+ afterEach(function () {
+ delete window.azerionPublisherAudiences;
+ storageStub.restore();
+ });
+
+ describe('initialisation', function () {
+ let returned;
+
+ beforeEach(function () {
+ returned = azerionedgeRTD.azerionedgeSubmodule.init(dataProvider);
+ });
+
+ it('should return true', function () {
+ expect(returned).to.equal(true);
+ });
+
+ it('should load external script', function () {
+ expect(loadExternalScript.called).to.be.true;
+ });
+
+ it('should load external script with default versioned url', function () {
+ const expected = 'https://edge.hyth.io/js/v1/azerion-edge.min.js';
+ expect(loadExternalScript.args[0][0]).to.deep.equal(expected);
+ });
+
+ it('should call azerionPublisherAudiencesStub with empty configuration', function () {
+ expect(window.azerionPublisherAudiences.args[0][0]).to.deep.equal({});
+ });
+
+ describe('with key', function () {
+ beforeEach(function () {
+ window.azerionPublisherAudiences.resetHistory();
+ loadExternalScript.resetHistory();
+ returned = azerionedgeRTD.azerionedgeSubmodule.init({
+ ...dataProvider,
+ params: { key },
+ });
+ });
+
+ it('should return true', function () {
+ expect(returned).to.equal(true);
+ });
+
+ it('should load external script with publisher id url', function () {
+ const expected = `https://edge.hyth.io/js/v1/${key}/azerion-edge.min.js`;
+ expect(loadExternalScript.args[0][0]).to.deep.equal(expected);
+ });
+ });
+
+ describe('with process configuration', function () {
+ beforeEach(function () {
+ window.azerionPublisherAudiences.resetHistory();
+ loadExternalScript.resetHistory();
+ returned = azerionedgeRTD.azerionedgeSubmodule.init({
+ ...dataProvider,
+ params: { process },
+ });
+ });
+
+ it('should return true', function () {
+ expect(returned).to.equal(true);
+ });
+
+ it('should call azerionPublisherAudiencesStub with process configuration', function () {
+ expect(window.azerionPublisherAudiences.args[0][0]).to.deep.equal(
+ process
+ );
+ });
+ });
+ });
+
+ describe('gets audiences', function () {
+ let callbackStub;
+
+ beforeEach(function () {
+ callbackStub = sinon.mock();
+ });
+
+ describe('with empty storage', function () {
+ beforeEach(function () {
+ azerionedgeRTD.azerionedgeSubmodule.getBidRequestData(
+ reqBidsConfigObj,
+ callbackStub,
+ dataProvider
+ );
+ });
+
+ it('does not run apply audiences to bidders', function () {
+ expect(reqBidsConfigObj.ortb2Fragments.bidder).to.deep.equal({});
+ });
+
+ it('calls callback anyway', function () {
+ expect(callbackStub.called).to.be.true;
+ });
+ });
+
+ describe('with populate storage', function () {
+ beforeEach(function () {
+ storageStub
+ .withArgs(STORAGE_KEY)
+ .returns(JSON.stringify(USER_AUDIENCES));
+ azerionedgeRTD.azerionedgeSubmodule.getBidRequestData(
+ reqBidsConfigObj,
+ callbackStub,
+ dataProvider
+ );
+ });
+
+ it('does apply audiences to bidder', function () {
+ const segments =
+ reqBidsConfigObj.ortb2Fragments.bidder['improvedigital'].user.data[0]
+ .segment;
+ expect(segments).to.deep.equal([{ id: '1' }, { id: '2' }]);
+ });
+
+ it('calls callback always', function () {
+ expect(callbackStub.called).to.be.true;
+ });
+ });
+ });
+
+ describe('sets audiences in bidder', function () {
+ const audiences = USER_AUDIENCES.map(({ id }) => id);
+ const expected = {
+ user: {
+ data: [
+ {
+ ext: { segtax: 4 },
+ name: 'azerionedge',
+ segment: [{ id: '1' }, { id: '2' }],
+ },
+ ],
+ },
+ };
+
+ it('for improvedigital by default', function () {
+ azerionedgeRTD.setAudiencesToBidders(
+ reqBidsConfigObj,
+ dataProvider,
+ audiences
+ );
+ expect(
+ reqBidsConfigObj.ortb2Fragments.bidder['improvedigital']
+ ).to.deep.equal(expected);
+ });
+
+ bidders.forEach((bidder) => {
+ it(`for ${bidder}`, function () {
+ const config = { ...dataProvider, params: { bidders } };
+ azerionedgeRTD.setAudiencesToBidders(reqBidsConfigObj, config, audiences);
+ expect(reqBidsConfigObj.ortb2Fragments.bidder[bidder]).to.deep.equal(
+ expected
+ );
+ });
+ });
+ });
+});
diff --git a/test/spec/modules/beopBidAdapter_spec.js b/test/spec/modules/beopBidAdapter_spec.js
index c77e304e539..663d622e505 100644
--- a/test/spec/modules/beopBidAdapter_spec.js
+++ b/test/spec/modules/beopBidAdapter_spec.js
@@ -312,4 +312,22 @@ describe('BeOp Bid Adapter tests', () => {
expect(payload.kwds).to.include('keywords');
})
})
+
+ describe('Ensure eids are get', function() {
+ let bidRequests = [];
+ afterEach(function () {
+ bidRequests = [];
+ });
+
+ it(`should get eids from bid`, function () {
+ let bid = Object.assign({}, validBid);
+ bid.userIdAsEids = [{source: 'provider.com', uids: [{id: 'someid', atype: 1, ext: {whatever: true}}]}];
+ bidRequests.push(bid);
+
+ const request = spec.buildRequests(bidRequests, {});
+ const payload = JSON.parse(request.data);
+ expect(payload.eids).to.exist;
+ expect(payload.eids[0].source).to.equal('provider.com');
+ });
+ })
});
diff --git a/test/spec/modules/bizzclickBidAdapter_spec.js b/test/spec/modules/bizzclickBidAdapter_spec.js
index f80051b0a50..f8e66caf657 100644
--- a/test/spec/modules/bizzclickBidAdapter_spec.js
+++ b/test/spec/modules/bizzclickBidAdapter_spec.js
@@ -1,6 +1,102 @@
import { expect } from 'chai';
-import { spec } from 'modules/bizzclickBidAdapter.js';
-import {config} from 'src/config.js';
+import { spec } from 'modules/bizzclickBidAdapter';
+import 'modules/priceFloors.js';
+import { newBidder } from 'src/adapters/bidderFactory';
+import { config } from '../../../src/config.js';
+import { syncAddFPDToBidderRequest } from '../../helpers/fpd.js';
+
+// load modules that register ORTB processors
+import 'src/prebid.js';
+import 'modules/currency.js';
+import 'modules/userId/index.js';
+import 'modules/multibid/index.js';
+import 'modules/priceFloors.js';
+import 'modules/consentManagement.js';
+import 'modules/consentManagementUsp.js';
+import 'modules/schain.js';
+
+const SIMPLE_BID_REQUEST = {
+ bidder: 'bizzclick',
+ params: {
+ accountId: 'testAccountId',
+ sourceId: 'testSourceId',
+ host: 'USE',
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [320, 250],
+ [300, 600],
+ ],
+ },
+ },
+ adUnitCode: 'div-gpt-ad-1499748733608-0',
+ transactionId: 'f183e871-fbed-45f0-a427-c8a63c4c01eb',
+ bidId: '33e9500b21129f',
+ bidderRequestId: '2772c1e566670b',
+ auctionId: '192721e36a0239',
+ sizes: [[300, 250], [160, 600]],
+ gdprConsent: {
+ apiVersion: 2,
+ consentString: 'CONSENT',
+ vendorData: { purpose: { consents: { 1: true } } },
+ gdprApplies: true,
+ addtlConsent: '1~1.35.41.101',
+ },
+}
+
+const BANNER_BID_REQUEST = {
+ bidder: 'bizzclick',
+ params: {
+ accountId: 'testAccountId',
+ sourceId: 'testSourceId',
+ host: 'USE',
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [300, 250],
+ [300, 600],
+ ],
+ },
+ },
+ adUnitCode: '/adunit-code/test-path',
+ bidId: 'test-bid-id-1',
+ bidderRequestId: 'test-bid-request-1',
+ auctionId: 'test-auction-1',
+ transactionId: 'test-transactionId-1',
+ code: 'banner_example',
+ timeout: 1000,
+}
+
+const VIDEO_BID_REQUEST = {
+ placementCode: '/DfpAccount1/slotVideo',
+ bidId: 'test-bid-id-2',
+ mediaTypes: {
+ video: {
+ playerSize: [400, 300],
+ w: 400,
+ h: 300,
+ minduration: 5,
+ maxduration: 10,
+ startdelay: 0,
+ skip: 1,
+ minbitrate: 200,
+ protocols: [1, 2, 4]
+ }
+ },
+ bidder: 'bizzclick',
+ params: {
+ accountId: '123',
+ sourceId: '123',
+ host: 'USE',
+ },
+ adUnitCode: '/adunit-code/test-path',
+ bidderRequestId: 'test-bid-request-1',
+ auctionId: 'test-auction-1',
+ transactionId: 'test-transactionId-1',
+ timeout: 1000,
+}
const NATIVE_BID_REQUEST = {
code: 'native_example',
@@ -34,386 +130,179 @@ const NATIVE_BID_REQUEST = {
},
bidder: 'bizzclick',
params: {
- placementId: 'hash',
- accountId: 'accountId'
- },
- timeout: 1000
-
-};
-
-const BANNER_BID_REQUEST = {
- code: 'banner_example',
- mediaTypes: {
- banner: {
- sizes: [[300, 250], [300, 600]]
- }
- },
- schain: {
- ver: '1.0',
- complete: 1,
- nodes: [
- {
- asi: 'example.com',
- sid: '164',
- hp: 1
- }
- ]
- },
- bidder: 'bizzclick',
- params: {
- placementId: 'hash',
- accountId: 'accountId'
+ accountId: 'testAccountId',
+ sourceId: 'testSourceId',
+ host: 'USE',
},
+ adUnitCode: '/adunit-code/test-path',
+ bidId: 'test-bid-id-1',
+ bidderRequestId: 'test-bid-request-1',
+ auctionId: 'test-auction-1',
+ transactionId: 'test-transactionId-1',
timeout: 1000,
- gdprConsent: {
- consentString: 'BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA',
- gdprApplies: 1,
- },
uspConsent: 'uspConsent'
-}
+};
-const bidRequest = {
+const bidderRequest = {
refererInfo: {
- referer: 'test.com'
- }
-}
-
-const VIDEO_BID_REQUEST = {
- code: 'video1',
- sizes: [640, 480],
- mediaTypes: { video: {
- minduration: 0,
- maxduration: 999,
- boxingallowed: 1,
- skip: 0,
- mimes: [
- 'application/javascript',
- 'video/mp4'
- ],
- w: 1920,
- h: 1080,
- protocols: [
- 2
- ],
- linearity: 1,
- api: [
- 1,
- 2
- ]
+ page: 'https://publisher.com/home',
+ ref: 'https://referrer'
}
- },
-
- bidder: 'bizzclick',
- params: {
- placementId: 'hash',
- accountId: 'accountId'
- },
- timeout: 1000
-
-}
-
-const BANNER_BID_RESPONSE = {
- id: 'request_id',
- bidid: 'request_imp_id',
- seatbid: [{
- bid: [{
- id: 'bid_id',
- impid: 'request_imp_id',
- price: 5,
- adomain: ['example.com'],
- adm: 'admcode',
- crid: 'crid',
- ext: {
- mediaType: 'banner'
- }
- }],
- }],
-};
-
-const VIDEO_BID_RESPONSE = {
- id: 'request_id',
- bidid: 'request_imp_id',
- seatbid: [{
- bid: [{
- id: 'bid_id',
- impid: 'request_imp_id',
- price: 5,
- adomain: ['example.com'],
- adm: 'admcode',
- crid: 'crid',
- ext: {
- mediaType: 'video',
- vastUrl: 'http://example.vast',
- }
- }],
- }],
};
-let imgData = {
- url: `https://example.com/image`,
- w: 1200,
- h: 627
-};
+const gdprConsent = {
+ apiVersion: 2,
+ consentString: 'CONSENT',
+ vendorData: { purpose: { consents: { 1: true } } },
+ gdprApplies: true,
+ addtlConsent: '1~1.35.41.101',
+}
-const NATIVE_BID_RESPONSE = {
- id: 'request_id',
- bidid: 'request_imp_id',
- seatbid: [{
- bid: [{
- id: 'bid_id',
- impid: 'request_imp_id',
- price: 5,
- adomain: ['example.com'],
- adm: { native:
- {
- assets: [
- {id: 0, title: 'dummyText'},
- {id: 3, image: imgData},
- {
- id: 5,
- data: {value: 'organization.name'}
- }
- ],
- link: {url: 'example.com'},
- imptrackers: ['tracker1.com', 'tracker2.com', 'tracker3.com'],
- jstracker: 'tracker1.com'
- }
- },
- crid: 'crid',
- ext: {
- mediaType: 'native'
- }
- }],
- }],
-};
+describe('bizzclickAdapter', function () {
+ const adapter = newBidder(spec);
+ describe('inherited functions', function () {
+ it('exists and is a function', function () {
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
+ });
+ });
-describe('BizzclickAdapter', function() {
- describe('with COPPA', function() {
- beforeEach(function() {
+ describe('with user privacy regulations', function () {
+ it('should send the Coppa "required" flag set to "1" in the request', function () {
sinon.stub(config, 'getConfig')
.withArgs('coppa')
.returns(true);
- });
- afterEach(function() {
+ const serverRequest = spec.buildRequests([SIMPLE_BID_REQUEST], syncAddFPDToBidderRequest(bidderRequest));
+ expect(serverRequest.data.regs.coppa).to.equal(1);
config.getConfig.restore();
});
- it('should send the Coppa "required" flag set to "1" in the request', function () {
- let serverRequest = spec.buildRequests([BANNER_BID_REQUEST]);
- expect(serverRequest.data[0].regs.coppa).to.equal(1);
+ it('should send the GDPR Consent data in the request', function () {
+ const serverRequest = spec.buildRequests([SIMPLE_BID_REQUEST], syncAddFPDToBidderRequest({ ...bidderRequest, gdprConsent }));
+ expect(serverRequest.data.regs.ext.gdpr).to.exist.and.to.equal(1);
+ expect(serverRequest.data.user.ext.consent).to.equal('CONSENT');
});
- });
- describe('isBidRequestValid', function() {
- it('should return true when required params found', function () {
- expect(spec.isBidRequestValid(NATIVE_BID_REQUEST)).to.equal(true);
- });
-
- it('should return false when required params are not passed', function () {
- let bid = Object.assign({}, NATIVE_BID_REQUEST);
- delete bid.params;
- bid.params = {
- 'IncorrectParam': 0
- };
- expect(spec.isBidRequestValid(bid)).to.equal(false);
+ it('should send the CCPA data in the request', function () {
+ const serverRequest = spec.buildRequests([SIMPLE_BID_REQUEST], syncAddFPDToBidderRequest({...bidderRequest, ...{ uspConsent: '1YYY' }}));
+ expect(serverRequest.data.regs.ext.us_privacy).to.equal('1YYY');
});
});
- describe('build Native Request', function () {
- const request = spec.buildRequests([NATIVE_BID_REQUEST], bidRequest);
-
- it('Creates a ServerRequest object with method, URL and data', function () {
- expect(request).to.exist;
- expect(request.method).to.exist;
- expect(request.url).to.exist;
- expect(request.data).to.exist;
- });
-
- it('sends bid request to our endpoint via POST', function () {
- expect(request.method).to.equal('POST');
- });
-
- it('Returns valid URL', function () {
- expect(request.url).to.equal('https://us-e-node1.bizzclick.com/bid?rtb_seat_id=prebidjs&secret_key=accountId');
+ describe('isBidRequestValid', function () {
+ it('should return true when required params found', function () {
+ expect(spec.isBidRequestValid(BANNER_BID_REQUEST)).to.equal(true);
});
- it('Returns empty data if no valid requests are passed', function () {
- let serverRequest = spec.buildRequests([]);
- expect(serverRequest).to.be.an('array').that.is.empty;
+ it('should return false when accountID/sourceId is missing', function () {
+ let localbid = Object.assign({}, BANNER_BID_REQUEST);
+ delete localbid.params.accountId;
+ delete localbid.params.sourceId;
+ expect(spec.isBidRequestValid(BANNER_BID_REQUEST)).to.equal(false);
});
});
- describe('build Banner Request', function () {
- const request = spec.buildRequests([BANNER_BID_REQUEST]);
-
- it('Creates a ServerRequest object with method, URL and data', function () {
- expect(request).to.exist;
- expect(request.method).to.exist;
- expect(request.url).to.exist;
- expect(request.data).to.exist;
+ describe('build request', function () {
+ it('should return an empty array when no bid requests', function () {
+ const bidRequest = spec.buildRequests([], syncAddFPDToBidderRequest(bidderRequest));
+ expect(bidRequest).to.be.an('array');
+ expect(bidRequest.length).to.equal(0);
});
- it('sends bid request to our endpoint via POST', function () {
+ it('should return a valid bid request object', function () {
+ const request = spec.buildRequests([SIMPLE_BID_REQUEST], syncAddFPDToBidderRequest(bidderRequest));
+ expect(request).to.not.equal('array');
+ expect(request.data).to.be.an('object');
expect(request.method).to.equal('POST');
+ expect(request.url).to.not.equal('');
+ expect(request.url).to.not.equal(undefined);
+ expect(request.url).to.not.equal(null);
+
+ expect(request.data.site).to.have.property('page');
+ expect(request.data.site).to.have.property('domain');
+ expect(request.data).to.have.property('id');
+ expect(request.data).to.have.property('imp');
+ expect(request.data).to.have.property('device');
});
- it('check consent and ccpa string is set properly', function() {
- expect(request.data[0].regs.ext.gdpr).to.equal(1);
- expect(request.data[0].user.ext.consent).to.equal(BANNER_BID_REQUEST.gdprConsent.consentString);
- expect(request.data[0].regs.ext.us_privacy).to.equal(BANNER_BID_REQUEST.uspConsent);
- })
-
- it('check schain is set properly', function() {
- expect(request.data[0].source.ext.schain.complete).to.equal(1);
- expect(request.data[0].source.ext.schain.ver).to.equal('1.0');
- })
-
- it('Returns valid URL', function () {
- expect(request.url).to.equal('https://us-e-node1.bizzclick.com/bid?rtb_seat_id=prebidjs&secret_key=accountId');
+ it('should return a valid bid BANNER request object', function () {
+ const request = spec.buildRequests([BANNER_BID_REQUEST], syncAddFPDToBidderRequest(bidderRequest));
+ expect(request.data.imp[0].banner).to.exist;
+ expect(request.data.imp[0].banner.format[0].w).to.be.an('number');
+ expect(request.data.imp[0].banner.format[0].h).to.be.an('number');
});
- });
- describe('build Video Request', function () {
- const request = spec.buildRequests([VIDEO_BID_REQUEST]);
-
- it('Creates a ServerRequest object with method, URL and data', function () {
- expect(request).to.exist;
- expect(request.method).to.exist;
- expect(request.url).to.exist;
- expect(request.data).to.exist;
- });
+ if (FEATURES.VIDEO) {
+ it('should return a valid bid VIDEO request object', function () {
+ const request = spec.buildRequests([VIDEO_BID_REQUEST], syncAddFPDToBidderRequest(bidderRequest));
+ expect(request.data.imp[0].video).to.exist;
+ expect(request.data.imp[0].video.w).to.be.an('number');
+ expect(request.data.imp[0].video.h).to.be.an('number');
+ });
+ }
- it('sends bid request to our endpoint via POST', function () {
- expect(request.method).to.equal('POST');
+ it('should return a valid bid NATIVE request object', function () {
+ const request = spec.buildRequests([NATIVE_BID_REQUEST], syncAddFPDToBidderRequest(bidderRequest));
+ expect(request.data.imp[0]).to.be.an('object');
});
+ })
- it('Returns valid URL', function () {
- expect(request.url).to.equal('https://us-e-node1.bizzclick.com/bid?rtb_seat_id=prebidjs&secret_key=accountId');
+ describe('interpretResponse', function () {
+ let bidRequests, bidderRequest;
+ beforeEach(function () {
+ bidRequests = [{
+ 'bidId': '28ffdk2B952532',
+ 'bidder': 'bizzclick',
+ 'userId': {
+ 'freepassId': {
+ 'userIp': '172.21.0.1',
+ 'userId': '123',
+ 'commonId': 'commonIdValue'
+ }
+ },
+ 'adUnitCode': 'adunit-code',
+ 'params': {
+ 'publisherId': 'publisherIdValue'
+ }
+ }];
+ bidderRequest = {};
});
- });
- describe('interpretResponse', function () {
- it('Empty response must return empty array', function() {
+ it('Empty response must return empty array', function () {
const emptyResponse = null;
- let response = spec.interpretResponse(emptyResponse);
+ let response = spec.interpretResponse(emptyResponse, BANNER_BID_REQUEST);
expect(response).to.be.an('array').that.is.empty;
})
it('Should interpret banner response', function () {
- const bannerResponse = {
- body: [BANNER_BID_RESPONSE]
- }
-
- const expectedBidResponse = {
- requestId: BANNER_BID_RESPONSE.id,
- cpm: BANNER_BID_RESPONSE.seatbid[0].bid[0].price,
- width: BANNER_BID_RESPONSE.seatbid[0].bid[0].w,
- height: BANNER_BID_RESPONSE.seatbid[0].bid[0].h,
- ttl: BANNER_BID_RESPONSE.ttl || 1200,
- currency: BANNER_BID_RESPONSE.cur || 'USD',
- netRevenue: true,
- creativeId: BANNER_BID_RESPONSE.seatbid[0].bid[0].crid,
- dealId: BANNER_BID_RESPONSE.seatbid[0].bid[0].dealid,
-
- meta: {advertiserDomains: BANNER_BID_RESPONSE.seatbid[0].bid[0].adomain},
- mediaType: 'banner',
- ad: BANNER_BID_RESPONSE.seatbid[0].bid[0].adm
- }
-
- let bannerResponses = spec.interpretResponse(bannerResponse);
-
- expect(bannerResponses).to.be.an('array').that.is.not.empty;
- let dataItem = bannerResponses[0];
- expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId',
- 'netRevenue', 'currency', 'dealId', 'meta', 'mediaType');
- expect(dataItem.requestId).to.equal(expectedBidResponse.requestId);
- expect(dataItem.cpm).to.equal(expectedBidResponse.cpm);
- expect(dataItem.ad).to.equal(expectedBidResponse.ad);
- expect(dataItem.ttl).to.equal(expectedBidResponse.ttl);
- expect(dataItem.meta.advertiserDomains).to.equal(expectedBidResponse.meta.advertiserDomains);
- expect(dataItem.creativeId).to.equal(expectedBidResponse.creativeId);
- expect(dataItem.netRevenue).to.be.true;
- expect(dataItem.currency).to.equal(expectedBidResponse.currency);
- expect(dataItem.width).to.equal(expectedBidResponse.width);
- expect(dataItem.height).to.equal(expectedBidResponse.height);
- });
-
- it('Should interpret video response', function () {
- const videoResponse = {
- body: [VIDEO_BID_RESPONSE]
- }
-
- const expectedBidResponse = {
- requestId: VIDEO_BID_RESPONSE.id,
- cpm: VIDEO_BID_RESPONSE.seatbid[0].bid[0].price,
- width: VIDEO_BID_RESPONSE.seatbid[0].bid[0].w,
- height: VIDEO_BID_RESPONSE.seatbid[0].bid[0].h,
- ttl: VIDEO_BID_RESPONSE.ttl || 1200,
- currency: VIDEO_BID_RESPONSE.cur || 'USD',
- netRevenue: true,
- creativeId: VIDEO_BID_RESPONSE.seatbid[0].bid[0].crid,
- dealId: VIDEO_BID_RESPONSE.seatbid[0].bid[0].dealid,
- mediaType: 'video',
- vastXml: VIDEO_BID_RESPONSE.seatbid[0].bid[0].adm,
- meta: {advertiserDomains: VIDEO_BID_RESPONSE.seatbid[0].bid[0].adomain},
- vastUrl: VIDEO_BID_RESPONSE.seatbid[0].bid[0].ext.vastUrl
- }
-
- let videoResponses = spec.interpretResponse(videoResponse);
-
- expect(videoResponses).to.be.an('array').that.is.not.empty;
- let dataItem = videoResponses[0];
- expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'vastXml', 'vastUrl', 'ttl', 'creativeId',
- 'netRevenue', 'currency', 'dealId', 'meta', 'mediaType');
- expect(dataItem.requestId).to.equal(expectedBidResponse.requestId);
- expect(dataItem.cpm).to.equal(expectedBidResponse.cpm);
- expect(dataItem.vastXml).to.equal(expectedBidResponse.vastXml)
- expect(dataItem.ttl).to.equal(expectedBidResponse.ttl);
- expect(dataItem.creativeId).to.equal(expectedBidResponse.creativeId);
- expect(dataItem.meta.advertiserDomains).to.equal(expectedBidResponse.meta.advertiserDomains);
- expect(dataItem.netRevenue).to.be.true;
- expect(dataItem.currency).to.equal(expectedBidResponse.currency);
- expect(dataItem.width).to.equal(expectedBidResponse.width);
- expect(dataItem.height).to.equal(expectedBidResponse.height);
- });
-
- it('Should interpret native response', function () {
- const nativeResponse = {
- body: [NATIVE_BID_RESPONSE]
- }
-
- const expectedBidResponse = {
- requestId: NATIVE_BID_RESPONSE.id,
- cpm: NATIVE_BID_RESPONSE.seatbid[0].bid[0].price,
- width: NATIVE_BID_RESPONSE.seatbid[0].bid[0].w,
- height: NATIVE_BID_RESPONSE.seatbid[0].bid[0].h,
- ttl: NATIVE_BID_RESPONSE.ttl || 1200,
- currency: NATIVE_BID_RESPONSE.cur || 'USD',
- netRevenue: true,
- creativeId: NATIVE_BID_RESPONSE.seatbid[0].bid[0].crid,
- dealId: NATIVE_BID_RESPONSE.seatbid[0].bid[0].dealid,
- mediaType: 'native',
- meta: {advertiserDomains: NATIVE_BID_RESPONSE.seatbid[0].bid[0].adomain},
- native: {clickUrl: NATIVE_BID_RESPONSE.seatbid[0].bid[0].adm.native.link.url}
- }
-
- let nativeResponses = spec.interpretResponse(nativeResponse);
-
- expect(nativeResponses).to.be.an('array').that.is.not.empty;
- let dataItem = nativeResponses[0];
- expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'native', 'ttl', 'creativeId',
- 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta');
- expect(dataItem.requestId).to.equal(expectedBidResponse.requestId);
- expect(dataItem.cpm).to.equal(expectedBidResponse.cpm);
- expect(dataItem.meta.advertiserDomains).to.equal(expectedBidResponse.meta.advertiserDomains);
- expect(dataItem.native.clickUrl).to.equal(expectedBidResponse.native.clickUrl)
- expect(dataItem.ttl).to.equal(expectedBidResponse.ttl);
- expect(dataItem.creativeId).to.equal(expectedBidResponse.creativeId);
- expect(dataItem.netRevenue).to.be.true;
- expect(dataItem.currency).to.equal(expectedBidResponse.currency);
- expect(dataItem.width).to.equal(expectedBidResponse.width);
- expect(dataItem.height).to.equal(expectedBidResponse.height);
- });
+ const serverResponse = {
+ body: {
+ 'cur': 'USD',
+ 'seatbid': [{
+ 'bid': [{
+ 'impid': '28ffdk2B952532',
+ 'price': 97,
+ 'adm': '
',
+ 'w': 300,
+ 'h': 250,
+ 'crid': 'creative0'
+ }]
+ }]
+ }
+ };
+ it('should interpret server response', function () {
+ const bidRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
+ const bids = spec.interpretResponse(serverResponse, bidRequest);
+ expect(bids).to.be.an('array');
+ const bid = bids[0];
+ expect(bid).to.be.an('object');
+ expect(bid.currency).to.equal('USD');
+ expect(bid.cpm).to.equal(97);
+ expect(bid.ad).to.equal(ad)
+ expect(bid.width).to.equal(300);
+ expect(bid.height).to.equal(250);
+ expect(bid.creativeId).to.equal('creative0');
+ });
+ })
});
-})
+});
diff --git a/test/spec/modules/bliinkBidAdapter_spec.js b/test/spec/modules/bliinkBidAdapter_spec.js
index d0320ab6ec1..3db97a17d88 100644
--- a/test/spec/modules/bliinkBidAdapter_spec.js
+++ b/test/spec/modules/bliinkBidAdapter_spec.js
@@ -7,6 +7,8 @@ import {
BLIINK_ENDPOINT_COOKIE_SYNC_IFRAME,
getEffectiveConnectionType,
getUserIds,
+ getDomLoadingDuration,
+ GVL_ID,
} from 'modules/bliinkBidAdapter.js';
import { config } from 'src/config.js';
@@ -31,6 +33,7 @@ import { config } from 'src/config.js';
*/
const connectionType = getEffectiveConnectionType();
+const domLoadingDuration = getDomLoadingDuration().toString();
const getConfigBid = (placement) => {
return {
adUnitCode: '/19968336/test',
@@ -57,6 +60,7 @@ const getConfigBid = (placement) => {
},
},
},
+ domLoadingDuration,
ect: connectionType,
params: {
placement: placement,
@@ -348,11 +352,31 @@ const GetUserIds = [
want: undefined,
},
{
- title: 'Should return userIds if exists',
+ title: 'Should return eids if exists',
args: {
- fn: getUserIds([{ userIds: { criteoId: 'testId' } }]),
+ fn: getUserIds([{ userIdAsEids: [
+ {
+ 'source': 'criteo.com',
+ 'uids': [
+ {
+ 'id': 'testId',
+ 'atype': 1
+ }
+ ]
+ }
+ ] }]),
},
- want: { criteoId: 'testId' },
+ want: [
+ {
+ 'source': 'criteo.com',
+ 'uids': [
+ {
+ 'id': 'testId',
+ 'atype': 1
+ }
+ ]
+ }
+ ],
},
];
@@ -655,12 +679,13 @@ const testsBuildRequests = [
method: 'POST',
url: BLIINK_ENDPOINT_ENGINE,
data: {
+ domLoadingDuration,
ect: connectionType,
keywords: '',
pageDescription: '',
pageTitle: '',
pageUrl:
- 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true',
+ 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html',
tags: [
{
transactionId: '2def0c5b2a7f6e',
@@ -697,6 +722,7 @@ const testsBuildRequests = [
method: 'POST',
url: BLIINK_ENDPOINT_ENGINE,
data: {
+ domLoadingDuration,
ect: connectionType,
gdpr: true,
gdprConsent: 'XXXX',
@@ -704,7 +730,7 @@ const testsBuildRequests = [
pageTitle: '',
keywords: '',
pageUrl:
- 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true',
+ 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html',
tags: [
{
transactionId: '2def0c5b2a7f6e',
@@ -742,6 +768,7 @@ const testsBuildRequests = [
method: 'POST',
url: BLIINK_ENDPOINT_ENGINE,
data: {
+ domLoadingDuration,
ect: connectionType,
gdpr: true,
uspConsent: 'uspConsent',
@@ -750,7 +777,7 @@ const testsBuildRequests = [
pageTitle: '',
keywords: '',
pageUrl:
- 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true',
+ 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html',
tags: [
{
transactionId: '2def0c5b2a7f6e',
@@ -801,6 +828,7 @@ const testsBuildRequests = [
method: 'POST',
url: BLIINK_ENDPOINT_ENGINE,
data: {
+ domLoadingDuration,
ect: connectionType,
gdpr: true,
gdprConsent: 'XXXX',
@@ -808,7 +836,7 @@ const testsBuildRequests = [
pageTitle: '',
keywords: '',
pageUrl:
- 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true',
+ 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html',
schain: {
ver: '1.0',
complete: 1,
@@ -840,16 +868,31 @@ const testsBuildRequests = [
},
},
{
- title: 'Should build request with userIds if exists',
+ title: 'Should build request with eids if exists',
args: {
fn: spec.buildRequests(
[
{
- userIds: {
- criteoId:
- 'vG4RRF93V05LRlJUTVVOQTJJJTJGbG1rZWxEeDVvc0NXWE42TzJqU2hG',
- netId: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg',
- },
+ userIdAsEids: [
+ {
+ 'source': 'criteo.com',
+ 'uids': [
+ {
+ 'id': 'vG4RRF93V05LRlJUTVVOQTJJJTJGbG1rZWxEeDVvc0NXWE42TzJqU2hG',
+ 'atype': 1
+ }
+ ]
+ },
+ {
+ 'source': 'netid.de',
+ 'uids': [
+ {
+ 'id': 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg',
+ 'atype': 1
+ }
+ ]
+ }
+ ],
},
],
Object.assign(getConfigBuildRequest('banner'), {
@@ -864,6 +907,7 @@ const testsBuildRequests = [
method: 'POST',
url: BLIINK_ENDPOINT_ENGINE,
data: {
+ domLoadingDuration,
ect: connectionType,
gdpr: true,
gdprConsent: 'XXXX',
@@ -871,11 +915,27 @@ const testsBuildRequests = [
pageTitle: '',
keywords: '',
pageUrl:
- 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true',
- userIds: {
- criteoId: 'vG4RRF93V05LRlJUTVVOQTJJJTJGbG1rZWxEeDVvc0NXWE42TzJqU2hG',
- netId: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg',
- },
+ 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html',
+ eids: [
+ {
+ 'source': 'criteo.com',
+ 'uids': [
+ {
+ 'id': 'vG4RRF93V05LRlJUTVVOQTJJJTJGbG1rZWxEeDVvc0NXWE42TzJqU2hG',
+ 'atype': 1
+ }
+ ]
+ },
+ {
+ 'source': 'netid.de',
+ 'uids': [
+ {
+ 'id': 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg',
+ 'atype': 1
+ }
+ ]
+ }
+ ],
tags: [
{
transactionId: '2def0c5b2a7f6e',
@@ -1053,6 +1113,7 @@ describe('BLIINK Adapter keywords & coppa true', function () {
method: 'POST',
url: BLIINK_ENDPOINT_ENGINE,
data: {
+ domLoadingDuration,
ect: connectionType,
gdpr: true,
coppa: 1,
@@ -1061,7 +1122,7 @@ describe('BLIINK Adapter keywords & coppa true', function () {
pageTitle: '',
keywords: 'Bliink,Saber,Prebid',
pageUrl:
- 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html?pbjs_debug=true',
+ 'http://localhost:9999/integrationExamples/gpt/bliink-adapter.html',
tags: [
{
transactionId: '2def0c5b2a7f6e',
@@ -1108,3 +1169,7 @@ describe('getEffectiveConnectionType', () => {
});
}
});
+
+it('should expose gvlid', function () {
+ expect(spec.gvlid).to.equal(GVL_ID);
+});
diff --git a/test/spec/modules/boldwinBidAdapter_spec.js b/test/spec/modules/boldwinBidAdapter_spec.js
index 52a6ec03757..9a7b16c0914 100644
--- a/test/spec/modules/boldwinBidAdapter_spec.js
+++ b/test/spec/modules/boldwinBidAdapter_spec.js
@@ -314,7 +314,7 @@ describe('BoldwinBidAdapter', function () {
expect(userSync[0].type).to.exist;
expect(userSync[0].url).to.exist;
expect(userSync[0].type).to.be.equal('image');
- expect(userSync[0].url).to.be.equal('https://cs.videowalldirect.com');
+ expect(userSync[0].url).to.be.equal('https://sync.videowalldirect.com');
});
});
});
diff --git a/test/spec/modules/browsiRtdProvider_spec.js b/test/spec/modules/browsiRtdProvider_spec.js
index 75120aa7505..5fcc78f4322 100644
--- a/test/spec/modules/browsiRtdProvider_spec.js
+++ b/test/spec/modules/browsiRtdProvider_spec.js
@@ -89,12 +89,6 @@ describe('browsi Real time data sub module', function () {
expect(browsiRTD.browsiSubmodule.getTargetingData([], null, null, auction)).to.eql({});
});
- it('should return NA if no prediction for ad unit', function () {
- makeSlot({code: 'adMock', divId: 'browsiAd_2'});
- browsiRTD.setData({});
- expect(browsiRTD.browsiSubmodule.getTargetingData(['adMock'], null, null, auction)).to.eql({adMock: {bv: 'NA'}});
- });
-
it('should return prediction from server', function () {
makeSlot({code: 'hasPrediction', divId: 'hasPrediction'});
const data = {
diff --git a/test/spec/modules/cointrafficBidAdapter_spec.js b/test/spec/modules/cointrafficBidAdapter_spec.js
index 79775f7b135..21f02b4f8ef 100644
--- a/test/spec/modules/cointrafficBidAdapter_spec.js
+++ b/test/spec/modules/cointrafficBidAdapter_spec.js
@@ -4,6 +4,11 @@ import { spec } from 'modules/cointrafficBidAdapter.js';
import { config } from 'src/config.js'
import * as utils from 'src/utils.js'
+/**
+ * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
+ * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
+ */
+
const ENDPOINT_URL = 'https://apps-pbd.ctraffic.io/pb/tmp';
describe('cointrafficBidAdapter', function () {
diff --git a/test/spec/modules/colossussspBidAdapter_spec.js b/test/spec/modules/colossussspBidAdapter_spec.js
index b8c872d879d..ebe1e9be4d4 100644
--- a/test/spec/modules/colossussspBidAdapter_spec.js
+++ b/test/spec/modules/colossussspBidAdapter_spec.js
@@ -255,13 +255,46 @@ describe('ColossussspAdapter', function () {
});
describe('buildRequests with user ids', function () {
- bid.userId = {}
- bid.userId.britepoolid = 'britepoolid123';
- bid.userId.idl_env = 'idl_env123';
- bid.userId.tdid = 'tdid123';
- bid.userId.id5id = { uid: 'id5id123' };
- bid.userId.uid2 = { id: 'uid2id123' };
- let serverRequest = spec.buildRequests([bid], bidderRequest);
+ var clonedBid = JSON.parse(JSON.stringify(bid));
+ clonedBid.userId = {}
+ clonedBid.userId.britepoolid = 'britepoolid123';
+ clonedBid.userId.idl_env = 'idl_env123';
+ clonedBid.userId.tdid = 'tdid123';
+ clonedBid.userId.id5id = { uid: 'id5id123' };
+ clonedBid.userId.uid2 = { id: 'uid2id123' };
+ clonedBid.userIdAsEids = [
+ {
+ 'source': 'pubcid.org',
+ 'uids': [
+ {
+ 'id': '4679e98e-1d83-4718-8aba-aa88hhhaaa',
+ 'atype': 1
+ }
+ ]
+ },
+ {
+ 'source': 'adserver.org',
+ 'uids': [
+ {
+ 'id': 'e804908e-57b4-4f46-a097-08be44321e79',
+ 'atype': 1,
+ 'ext': {
+ 'rtiPartner': 'TDID'
+ }
+ }
+ ]
+ },
+ {
+ 'source': 'neustar.biz',
+ 'uids': [
+ {
+ 'id': 'E1:Bvss1x8hXM2zHeqiqj2umJUziavSvLT6E_ORri5fDCsZb-5sfD18oNWycTmdx6QBNdbURBVv466hLJiKSwHCaTxvROo8smjqj6GfvlKfzQI',
+ 'atype': 1
+ }
+ ]
+ }
+ ];
+ let serverRequest = spec.buildRequests([clonedBid], bidderRequest);
it('Returns valid data if array of bids is valid', function () {
let data = serverRequest.data;
let placements = data['placements'];
@@ -270,11 +303,11 @@ describe('ColossussspAdapter', function () {
let placement = placements[i];
expect(placement).to.have.property('eids')
expect(placement.eids).to.be.an('array')
- expect(placement.eids.length).to.be.equal(5)
+ expect(placement.eids.length).to.be.equal(8)
for (let index in placement.eids) {
let v = placement.eids[index];
expect(v).to.have.all.keys('source', 'uids')
- expect(v.source).to.be.oneOf(['britepool.com', 'identityLink', 'adserver.org', 'id5-sync.com', 'uidapi.com'])
+ expect(v.source).to.be.oneOf(['pubcid.org', 'adserver.org', 'neustar.biz', 'britepool.com', 'identityLink', 'id5-sync.com', 'adserver.org', 'uidapi.com'])
expect(v.uids).to.be.an('array');
expect(v.uids.length).to.be.equal(1)
expect(v.uids[0]).to.have.property('id')
diff --git a/test/spec/modules/concertBidAdapter_spec.js b/test/spec/modules/concertBidAdapter_spec.js
index 40294deb26d..0a76ed3e62d 100644
--- a/test/spec/modules/concertBidAdapter_spec.js
+++ b/test/spec/modules/concertBidAdapter_spec.js
@@ -94,7 +94,7 @@ describe('ConcertAdapter', function () {
});
describe('spec.isBidRequestValid', function() {
- it('should return when it recieved all the required params', function() {
+ it('should return when it received all the required params', function() {
const bid = bidRequests[0];
expect(spec.isBidRequestValid(bid)).to.equal(true);
});
diff --git a/test/spec/modules/connatixBidAdapter_spec.js b/test/spec/modules/connatixBidAdapter_spec.js
index 16ead9f9458..4d816c4e816 100644
--- a/test/spec/modules/connatixBidAdapter_spec.js
+++ b/test/spec/modules/connatixBidAdapter_spec.js
@@ -90,6 +90,10 @@ describe('connatixBidAdapter', function () {
gdprApplies: true
},
uspConsent: '1YYY',
+ gppConsent: {
+ gppString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==',
+ applicableSections: [7]
+ },
ortb2: {
site: {
data: {
@@ -128,6 +132,7 @@ describe('connatixBidAdapter', function () {
expect(serverRequest.data.refererInfo).to.equal(bidderRequest.refererInfo);
expect(serverRequest.data.gdprConsent).to.equal(bidderRequest.gdprConsent);
expect(serverRequest.data.uspConsent).to.equal(bidderRequest.uspConsent);
+ expect(serverRequest.data.gppConsent).to.equal(bidderRequest.gppConsent);
expect(serverRequest.data.ortb2).to.equal(bidderRequest.ortb2);
});
});
@@ -135,14 +140,12 @@ describe('connatixBidAdapter', function () {
describe('interpretResponse', function () {
const CustomerId = '99f20d18-c4b4-4a28-3d8e-d43e2c8cb4ac';
const PlayerId = 'e4984e88-9ff4-45a3-8b9d-33aabcad634f';
- const Bid = {Cpm: 0.1, LineItems: [], RequestId: '2f897340c4eaa3', Ttl: 86400};
+ const Bid = {Cpm: 0.1, RequestId: '2f897340c4eaa3', Ttl: 86400, CustomerId, PlayerId};
let serverResponse;
this.beforeEach(function () {
serverResponse = {
body: {
- CustomerId,
- PlayerId,
Bids: [ Bid ]
},
headers: function() { }
@@ -162,18 +165,6 @@ describe('connatixBidAdapter', function () {
expect(response).to.be.an('array').that.is.empty;
});
- it('Should return an empty array if CustomerId is null', function () {
- serverResponse.body.CustomerId = null;
- const response = spec.interpretResponse(serverResponse);
- expect(response).to.be.an('array').that.is.empty;
- });
-
- it('Should return an empty array if PlayerId is null', function () {
- serverResponse.body.PlayerId = null;
- const response = spec.interpretResponse(serverResponse);
- expect(response).to.be.an('array').that.is.empty;
- });
-
it('Should return one bid response for one bid', function() {
const bidResponses = spec.interpretResponse(serverResponse);
expect(bidResponses.length).to.equal(1);
@@ -212,12 +203,10 @@ describe('connatixBidAdapter', function () {
const CustomerId = '99f20d18-c4b4-4a28-3d8e-d43e2c8cb4ac';
const PlayerId = 'e4984e88-9ff4-45a3-8b9d-33aabcad634f';
const UserSyncEndpoint = 'https://connatix.com/sync'
- const Bid = {Cpm: 0.1, LineItems: [], RequestId: '2f897340c4eaa3', Ttl: 86400};
+ const Bid = {Cpm: 0.1, RequestId: '2f897340c4eaa3', Ttl: 86400, CustomerId, PlayerId};
const serverResponse = {
body: {
- CustomerId,
- PlayerId,
UserSyncEndpoint,
Bids: [ Bid ]
},
diff --git a/test/spec/modules/connectIdSystem_spec.js b/test/spec/modules/connectIdSystem_spec.js
index 5376ba60886..686c3d63a63 100644
--- a/test/spec/modules/connectIdSystem_spec.js
+++ b/test/spec/modules/connectIdSystem_spec.js
@@ -3,6 +3,7 @@ import {connectIdSubmodule, storage} from 'modules/connectIdSystem.js';
import {server} from '../../mocks/xhr';
import {parseQS, parseUrl} from 'src/utils.js';
import {uspDataHandler, gppDataHandler} from 'src/adapterManager.js';
+import * as refererDetection from '../../../src/refererDetection';
const TEST_SERVER_URL = 'http://localhost:9876/';
@@ -288,6 +289,79 @@ describe('Yahoo ConnectID Submodule', () => {
expect(setCookieStub.firstCall.args[2]).to.equal(expiryDelta.toUTCString());
});
+ it('returns an object with the stored ID from cookies and syncs because of expired TTL', () => {
+ const last2Days = Date.now() - (60 * 60 * 24 * 1000 * 2);
+ const last21Days = Date.now() - (60 * 60 * 24 * 1000 * 21);
+ const ttl = 10000;
+ const cookieData = {connectId: 'foo', he: 'email', lastSynced: last2Days, puid: '9', lastUsed: last21Days, ttl};
+ getCookieStub.withArgs(STORAGE_KEY).returns(JSON.stringify(cookieData));
+
+ let result = invokeGetIdAPI({
+ he: HASHED_EMAIL,
+ pixelId: PIXEL_ID
+ }, consentData);
+
+ expect(result).to.be.an('object').that.has.all.keys('id', 'callback');
+ expect(result.id).to.deep.equal(cookieData);
+ expect(typeof result.callback).to.equal('function');
+ });
+
+ it('returns an object with the stored ID from cookies and not syncs because of valid TTL', () => {
+ const last2Days = Date.now() - (60 * 60 * 24 * 1000 * 2);
+ const last21Days = Date.now() - (60 * 60 * 24 * 1000 * 21);
+ const ttl = 60 * 60 * 24 * 1000 * 3;
+ const cookieData = {connectId: 'foo', he: HASHED_EMAIL, lastSynced: last2Days, puid: '9', lastUsed: last21Days, ttl};
+ getCookieStub.withArgs(STORAGE_KEY).returns(JSON.stringify(cookieData));
+
+ let result = invokeGetIdAPI({
+ he: HASHED_EMAIL,
+ pixelId: PIXEL_ID
+ }, consentData);
+
+ expect(result).to.be.an('object').that.has.all.keys('id');
+ cookieData.lastUsed = result.id.lastUsed;
+ expect(result.id).to.deep.equal(cookieData);
+ });
+
+ it('returns an object with the stored ID from cookies and not syncs because of valid TTL with provided puid', () => {
+ const last2Days = Date.now() - (60 * 60 * 24 * 1000 * 2);
+ const last21Days = Date.now() - (60 * 60 * 24 * 1000 * 21);
+ const ttl = 60 * 60 * 24 * 1000 * 3;
+ const cookieData = {connectId: 'foo', he: HASHED_EMAIL, lastSynced: last2Days, puid: '9', lastUsed: last21Days, ttl};
+ getCookieStub.withArgs(STORAGE_KEY).returns(JSON.stringify(cookieData));
+
+ let result = invokeGetIdAPI({
+ he: HASHED_EMAIL,
+ pixelId: PIXEL_ID,
+ puid: '9'
+ }, consentData);
+
+ expect(result).to.be.an('object').that.has.all.keys('id');
+ cookieData.lastUsed = result.id.lastUsed;
+ expect(result.id).to.deep.equal(cookieData);
+ });
+
+ it('returns an object with the stored ID from cookies and syncs because is O&O traffic', () => {
+ const last2Days = Date.now() - (60 * 60 * 24 * 1000 * 2);
+ const last21Days = Date.now() - (60 * 60 * 24 * 1000 * 21);
+ const ttl = 60 * 60 * 24 * 1000 * 3;
+ const cookieData = {connectId: 'foo', he: HASHED_EMAIL, lastSynced: last2Days, puid: '9', lastUsed: last21Days, ttl};
+ getCookieStub.withArgs(STORAGE_KEY).returns(JSON.stringify(cookieData));
+ const getRefererInfoStub = sinon.stub(refererDetection, 'getRefererInfo');
+ getRefererInfoStub.returns({
+ ref: 'https://dev.fc.yahoo.com?test'
+ });
+ let result = invokeGetIdAPI({
+ he: HASHED_EMAIL,
+ pixelId: PIXEL_ID
+ }, consentData);
+ getRefererInfoStub.restore();
+
+ expect(result).to.be.an('object').that.has.all.keys('id', 'callback');
+ expect(result.id).to.deep.equal(cookieData);
+ expect(typeof result.callback).to.equal('function');
+ });
+
it('Makes an ajax GET request to the production API endpoint with stored puid when id is stale', () => {
const last15Days = Date.now() - (60 * 60 * 24 * 1000 * 15);
const last29Days = Date.now() - (60 * 60 * 24 * 1000 * 29);
diff --git a/test/spec/modules/consentManagementGpp_spec.js b/test/spec/modules/consentManagementGpp_spec.js
index 99d4f94f502..93a876d0233 100644
--- a/test/spec/modules/consentManagementGpp_spec.js
+++ b/test/spec/modules/consentManagementGpp_spec.js
@@ -290,7 +290,7 @@ describe('consentManagementGpp', function () {
});
it('should not re-use errors', (done) => {
- cmpResult = Promise.reject(new Error());
+ cmpResult = GreedyPromise.reject(new Error());
GPPClient.init(makeCmp).catch(() => {
cmpResult = {signalStatus: 'ready'};
return GPPClient.init(makeCmp).then(([client]) => {
diff --git a/test/spec/modules/consentManagementUsp_spec.js b/test/spec/modules/consentManagementUsp_spec.js
index e98486754ab..c372c66f7f0 100644
--- a/test/spec/modules/consentManagementUsp_spec.js
+++ b/test/spec/modules/consentManagementUsp_spec.js
@@ -522,6 +522,19 @@ describe('consentManagement', function () {
setConsentConfig(goodConfig);
expect(uspDataHandler.getConsentData()).to.eql('string');
});
+
+ it('does not invoke registerDeletion if the CMP calls back with an error', () => {
+ sandbox.stub(window, '__uspapi').callsFake((cmd, _, cb) => {
+ if (cmd === 'registerDeletion') {
+ cb(null, false);
+ } else {
+ // eslint-disable-next-line standard/no-callback-literal
+ cb({uspString: 'string'}, true);
+ }
+ });
+ setConsentConfig(goodConfig);
+ sinon.assert.notCalled(adapterManager.callDataDeletionRequest);
+ })
});
});
});
diff --git a/test/spec/modules/consumableBidAdapter_spec.js b/test/spec/modules/consumableBidAdapter_spec.js
index deeb8f7100d..d8e75454245 100644
--- a/test/spec/modules/consumableBidAdapter_spec.js
+++ b/test/spec/modules/consumableBidAdapter_spec.js
@@ -651,21 +651,30 @@ describe('Consumable BidAdapter', function () {
expect(opts[0].url).to.equal('https://sync.serverbid.com/ss/730181.html?gdpr=0&gdpr_consent=GDPR_CONSENT_STRING');
})
- it('should return a sync url if iframe syncs are enabled and GPP applies', function () {
+ it('should return a sync url if iframe syncs are enabled and has GPP consent with applicable sections', function () {
let gppConsent = {
applicableSections: [1, 2],
gppString: 'GPP_CONSENT_STRING'
}
- let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE], {}, {}, gppConsent);
+ let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE], {}, '', gppConsent);
expect(opts.length).to.equal(1);
- expect(opts[0].url).to.equal('https://sync.serverbid.com/ss/730181.html?gpp=GPP_CONSENT_STRING&gpp_sid=1,2');
+ expect(opts[0].url).to.equal('https://sync.serverbid.com/ss/730181.html?gpp=GPP_CONSENT_STRING&gpp_sid=1%2C2');
})
- it('should return a sync url if iframe syncs are enabled and USP applies', function () {
- let uspConsent = {
- consentString: 'USP_CONSENT_STRING',
+ it('should return a sync url if iframe syncs are enabled and has GPP consent without applicable sections', function () {
+ let gppConsent = {
+ applicableSections: [],
+ gppString: 'GPP_CONSENT_STRING'
}
+ let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE], {}, '', gppConsent);
+
+ expect(opts.length).to.equal(1);
+ expect(opts[0].url).to.equal('https://sync.serverbid.com/ss/730181.html?gpp=GPP_CONSENT_STRING');
+ })
+
+ it('should return a sync url if iframe syncs are enabled and USP applies', function () {
+ let uspConsent = 'USP_CONSENT_STRING';
let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE], {}, uspConsent);
expect(opts.length).to.equal(1);
@@ -677,9 +686,7 @@ describe('Consumable BidAdapter', function () {
consentString: 'GDPR_CONSENT_STRING',
gdprApplies: true,
}
- let uspConsent = {
- consentString: 'USP_CONSENT_STRING',
- }
+ let uspConsent = 'USP_CONSENT_STRING';
let opts = spec.getUserSyncs(syncOptions, [AD_SERVER_RESPONSE], gdprConsent, uspConsent);
expect(opts.length).to.equal(1);
@@ -704,50 +711,22 @@ describe('Consumable BidAdapter', function () {
sandbox.restore();
});
- it('Request should have unifiedId config params', function() {
+ it('Request should have EIDs', function() {
bidderRequest.bidRequest[0].userId = {};
bidderRequest.bidRequest[0].userId.tdid = 'TTD_ID';
- bidderRequest.bidRequest[0].userIdAsEids = createEidsArray(bidderRequest.bidRequest[0].userId);
- let request = spec.buildRequests(bidderRequest.bidRequest, BIDDER_REQUEST_1);
- let data = JSON.parse(request.data);
- expect(data.user.eids).to.deep.equal([{
+ bidderRequest.bidRequest[0].userIdAsEids = [{
'source': 'adserver.org',
'uids': [{
- 'id': 'TTD_ID',
+ 'id': 'TTD_ID_FROM_USER_ID_MODULE',
'atype': 1,
'ext': {
'rtiPartner': 'TDID'
}
}]
- }]);
- });
-
- it('Request should have adsrvrOrgId from UserId Module if config and userId module both have TTD ID', function() {
- sandbox.stub(config, 'getConfig').callsFake((key) => {
- var config = {
- adsrvrOrgId: {
- 'TDID': 'TTD_ID_FROM_CONFIG',
- 'TDID_LOOKUP': 'TRUE',
- 'TDID_CREATED_AT': '2022-06-21T09:47:00'
- }
- };
- return config[key];
- });
- bidderRequest.bidRequest[0].userId = {};
- bidderRequest.bidRequest[0].userId.tdid = 'TTD_ID';
- bidderRequest.bidRequest[0].userIdAsEids = createEidsArray(bidderRequest.bidRequest[0].userId);
+ }];
let request = spec.buildRequests(bidderRequest.bidRequest, BIDDER_REQUEST_1);
let data = JSON.parse(request.data);
- expect(data.user.eids).to.deep.equal([{
- 'source': 'adserver.org',
- 'uids': [{
- 'id': 'TTD_ID',
- 'atype': 1,
- 'ext': {
- 'rtiPartner': 'TDID'
- }
- }]
- }]);
+ expect(data.user.eids).to.deep.equal(bidderRequest.bidRequest[0].userIdAsEids);
});
it('Request should NOT have adsrvrOrgId params if userId is NOT object', function() {
diff --git a/test/spec/modules/contxtfulRtdProvider_spec.js b/test/spec/modules/contxtfulRtdProvider_spec.js
new file mode 100644
index 00000000000..541c0e6e6dd
--- /dev/null
+++ b/test/spec/modules/contxtfulRtdProvider_spec.js
@@ -0,0 +1,200 @@
+import { contxtfulSubmodule } from '../../../modules/contxtfulRtdProvider.js';
+import { expect } from 'chai';
+import { loadExternalScriptStub } from 'test/mocks/adloaderStub.js';
+
+import * as events from '../../../src/events';
+
+const _ = null;
+const VERSION = 'v1';
+const CUSTOMER = 'CUSTOMER';
+const CONTXTFUL_CONNECTOR_ENDPOINT = `https://api.receptivity.io/${VERSION}/prebid/${CUSTOMER}/connector/p.js`;
+const INITIAL_RECEPTIVITY = { ReceptivityState: 'INITIAL_RECEPTIVITY' };
+const INITIAL_RECEPTIVITY_EVENT = new CustomEvent('initialReceptivity', { detail: INITIAL_RECEPTIVITY });
+
+const CONTXTFUL_API = { GetReceptivity: sinon.stub() }
+const RX_ENGINE_IS_READY_EVENT = new CustomEvent('rxEngineIsReady', {detail: CONTXTFUL_API});
+
+function buildInitConfig(version, customer) {
+ return {
+ name: 'contxtful',
+ params: {
+ version,
+ customer,
+ },
+ };
+}
+
+describe('contxtfulRtdProvider', function () {
+ let sandbox = sinon.sandbox.create();
+ let loadExternalScriptTag;
+ let eventsEmitSpy;
+
+ beforeEach(() => {
+ loadExternalScriptTag = document.createElement('script');
+ loadExternalScriptStub.callsFake((_url, _moduleName) => loadExternalScriptTag);
+
+ CONTXTFUL_API.GetReceptivity.reset();
+
+ eventsEmitSpy = sandbox.spy(events, ['emit']);
+ });
+
+ afterEach(function () {
+ delete window.Contxtful;
+ sandbox.restore();
+ });
+
+ describe('extractParameters with invalid configuration', () => {
+ const {
+ params: { customer, version },
+ } = buildInitConfig(VERSION, CUSTOMER);
+ const theories = [
+ [
+ null,
+ 'params.version should be a non-empty string',
+ 'null object for config',
+ ],
+ [
+ {},
+ 'params.version should be a non-empty string',
+ 'empty object for config',
+ ],
+ [
+ { customer },
+ 'params.version should be a non-empty string',
+ 'customer only in config',
+ ],
+ [
+ { version },
+ 'params.customer should be a non-empty string',
+ 'version only in config',
+ ],
+ [
+ { customer, version: '' },
+ 'params.version should be a non-empty string',
+ 'empty string for version',
+ ],
+ [
+ { customer: '', version },
+ 'params.customer should be a non-empty string',
+ 'empty string for customer',
+ ],
+ [
+ { customer: '', version: '' },
+ 'params.version should be a non-empty string',
+ 'empty string for version & customer',
+ ],
+ ];
+
+ theories.forEach(([params, expectedErrorMessage, _description]) => {
+ const config = { name: 'contxtful', params };
+ it('throws the expected error', () => {
+ expect(() => contxtfulSubmodule.extractParameters(config)).to.throw(
+ expectedErrorMessage
+ );
+ });
+ });
+ });
+
+ describe('initialization with invalid config', function () {
+ it('returns false', () => {
+ expect(contxtfulSubmodule.init({})).to.be.false;
+ });
+ });
+
+ describe('initialization with valid config', function () {
+ it('returns true when initializing', () => {
+ const config = buildInitConfig(VERSION, CUSTOMER);
+ expect(contxtfulSubmodule.init(config)).to.be.true;
+ });
+
+ it('loads contxtful module script asynchronously', (done) => {
+ contxtfulSubmodule.init(buildInitConfig(VERSION, CUSTOMER));
+
+ setTimeout(() => {
+ expect(loadExternalScriptStub.calledOnce).to.be.true;
+ expect(loadExternalScriptStub.args[0][0]).to.equal(
+ CONTXTFUL_CONNECTOR_ENDPOINT
+ );
+ done();
+ }, 10);
+ });
+ });
+
+ describe('load external script return falsy', function () {
+ it('returns true when initializing', () => {
+ loadExternalScriptStub.callsFake(() => {});
+ const config = buildInitConfig(VERSION, CUSTOMER);
+ expect(contxtfulSubmodule.init(config)).to.be.true;
+ });
+ });
+
+ describe('rxEngine from external script', function () {
+ it('use rxEngine api to get receptivity', () => {
+ contxtfulSubmodule.init(buildInitConfig(VERSION, CUSTOMER));
+ loadExternalScriptTag.dispatchEvent(RX_ENGINE_IS_READY_EVENT);
+
+ contxtfulSubmodule.getTargetingData(['ad-slot']);
+
+ expect(CONTXTFUL_API.GetReceptivity.calledOnce).to.be.true;
+ });
+ });
+
+ describe('initial receptivity is not dispatched', function () {
+ it('does not initialize receptivity value', () => {
+ contxtfulSubmodule.init(buildInitConfig(VERSION, CUSTOMER));
+
+ let targetingData = contxtfulSubmodule.getTargetingData(['ad-slot']);
+ expect(targetingData).to.deep.equal({});
+ });
+ });
+
+ describe('initial receptivity is invalid', function () {
+ const theories = [
+ [new Event('initialReceptivity'), 'event without details'],
+ [new CustomEvent('initialReceptivity', { }), 'custom event without details'],
+ [new CustomEvent('initialReceptivity', { detail: {} }), 'custom event with invalid details'],
+ [new CustomEvent('initialReceptivity', { detail: { ReceptivityState: '' } }), 'custom event with details without ReceptivityState'],
+ ];
+
+ theories.forEach(([initialReceptivityEvent, _description]) => {
+ it('does not initialize receptivity value', () => {
+ contxtfulSubmodule.init(buildInitConfig(VERSION, CUSTOMER));
+ loadExternalScriptTag.dispatchEvent(initialReceptivityEvent);
+
+ let targetingData = contxtfulSubmodule.getTargetingData(['ad-slot']);
+ expect(targetingData).to.deep.equal({});
+ });
+ })
+ });
+
+ describe('getTargetingData', function () {
+ const theories = [
+ [undefined, {}, 'undefined ad-slots'],
+ [[], {}, 'empty ad-slots'],
+ [
+ ['ad-slot'],
+ { 'ad-slot': { ReceptivityState: 'INITIAL_RECEPTIVITY' } },
+ 'single ad-slot',
+ ],
+ [
+ ['ad-slot-1', 'ad-slot-2'],
+ {
+ 'ad-slot-1': { ReceptivityState: 'INITIAL_RECEPTIVITY' },
+ 'ad-slot-2': { ReceptivityState: 'INITIAL_RECEPTIVITY' },
+ },
+ 'many ad-slots',
+ ],
+ ];
+
+ theories.forEach(([adUnits, expected, _description]) => {
+ it('adds "ReceptivityState" to the adUnits', function () {
+ contxtfulSubmodule.init(buildInitConfig(VERSION, CUSTOMER));
+ loadExternalScriptTag.dispatchEvent(INITIAL_RECEPTIVITY_EVENT);
+
+ expect(contxtfulSubmodule.getTargetingData(adUnits)).to.deep.equal(
+ expected
+ );
+ });
+ });
+ });
+});
diff --git a/test/spec/modules/conversantBidAdapter_spec.js b/test/spec/modules/conversantBidAdapter_spec.js
index 59ebefa2d60..9503a050092 100644
--- a/test/spec/modules/conversantBidAdapter_spec.js
+++ b/test/spec/modules/conversantBidAdapter_spec.js
@@ -2,13 +2,20 @@ import {expect} from 'chai';
import {spec, storage} from 'modules/conversantBidAdapter.js';
import * as utils from 'src/utils.js';
import {createEidsArray} from 'modules/userId/eids.js';
-import { config } from '../../../src/config.js';
import {deepAccess} from 'src/utils';
+// load modules that register ORTB processors
+import 'src/prebid.js'
+import 'modules/currency.js';
+import 'modules/userId/index.js'; // handles eids
+import 'modules/priceFloors.js';
+import 'modules/consentManagement.js';
+import 'modules/consentManagementUsp.js';
+import 'modules/schain.js'; // handles schain
+import {hook} from '../../../src/hook.js'
describe('Conversant adapter tests', function() {
const siteId = '108060';
const versionPattern = /^\d+\.\d+\.\d+(.)*$/;
-
const bidRequests = [
// banner with single size
{
@@ -19,13 +26,18 @@ describe('Conversant adapter tests', function() {
tag_id: 'tagid-1',
bidfloor: 0.5
},
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250]],
+ }
+ },
placementCode: 'pcode000',
transactionId: 'tx000',
- sizes: [[300, 250]],
bidId: 'bid000',
bidderRequestId: '117d765b87bed38',
auctionId: 'req000'
},
+
// banner with sizes in mediaTypes.banner.sizes
{
bidder: 'conversant',
@@ -51,9 +63,13 @@ describe('Conversant adapter tests', function() {
position: 2,
tag_id: ''
},
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 600], [160, 600]],
+ }
+ },
placementCode: 'pcode002',
transactionId: 'tx002',
- sizes: [[300, 600], [160, 600]],
bidId: 'bid002',
bidderRequestId: '117d765b87bed38',
auctionId: 'req000'
@@ -77,7 +93,6 @@ describe('Conversant adapter tests', function() {
},
placementCode: 'pcode003',
transactionId: 'tx003',
- sizes: [640, 480],
bidId: 'bid003',
bidderRequestId: '117d765b87bed38',
auctionId: 'req000'
@@ -125,16 +140,15 @@ describe('Conversant adapter tests', function() {
bidderRequestId: '117d765b87bed38',
auctionId: 'req000'
},
- // video with first party data
+ // banner with first party data
{
bidder: 'conversant',
params: {
site_id: siteId
},
mediaTypes: {
- video: {
- context: 'instream',
- mimes: ['video/mp4', 'video/x-flv']
+ banner: {
+ sizes: [[300, 600], [160, 600]],
}
},
ortb2Imp: {
@@ -150,23 +164,6 @@ describe('Conversant adapter tests', function() {
bidId: 'bid006',
bidderRequestId: '117d765b87bed38',
auctionId: 'req000'
- },
- {
- bidder: 'conversant',
- params: {
- site_id: siteId
- },
- mediaTypes: {
- banner: {
- sizes: [[728, 90], [468, 60]],
- pos: 5
- }
- },
- placementCode: 'pcode001',
- transactionId: 'tx001',
- bidId: 'bid007',
- bidderRequestId: '117d765b87bed38',
- auctionId: 'req000'
}
];
@@ -217,7 +214,14 @@ describe('Conversant adapter tests', function() {
}]
}]
},
- headers: {}};
+ headers: {}
+ };
+
+ before(() => {
+ // ortbConverter depends on other modules to be setup to work as expected so run hook.ready to register some
+ // submodules so functions like setOrtbSourceExtSchain and setOrtbUserExtEids are available
+ hook.ready();
+ });
it('Verify basic properties', function() {
expect(spec.code).to.equal('conversant');
@@ -232,12 +236,9 @@ describe('Conversant adapter tests', function() {
expect(spec.isBidRequestValid({})).to.be.false;
expect(spec.isBidRequestValid({params: {}})).to.be.false;
expect(spec.isBidRequestValid({params: {site_id: '123'}})).to.be.true;
- expect(spec.isBidRequestValid(bidRequests[0])).to.be.true;
- expect(spec.isBidRequestValid(bidRequests[1])).to.be.true;
- expect(spec.isBidRequestValid(bidRequests[2])).to.be.true;
- expect(spec.isBidRequestValid(bidRequests[3])).to.be.true;
- expect(spec.isBidRequestValid(bidRequests[4])).to.be.true;
- expect(spec.isBidRequestValid(bidRequests[5])).to.be.true;
+ bidRequests.forEach((bid) => {
+ expect(spec.isBidRequestValid(bid)).to.be.true;
+ });
const simpleVideo = JSON.parse(JSON.stringify(bidRequests[3]));
simpleVideo.params.site_id = 123;
@@ -251,152 +252,171 @@ describe('Conversant adapter tests', function() {
expect(spec.isBidRequestValid(simpleVideo)).to.be.true;
});
- it('Verify buildRequest', function() {
- const page = 'http://test.com?a=b&c=123';
- const bidderRequest = {
- refererInfo: {
- page: page
- },
- ortb2: {
- source: {
- tid: 'tid000'
+ describe('Verify buildRequest', function() {
+ let page, bidderRequest, request, payload;
+ before(() => {
+ page = 'http://test.com?a=b&c=123';
+ // ortbConverter uses the site/device information from the ortb2 object passed in the bidderRequest object
+ bidderRequest = {
+ refererInfo: {
+ page: page
+ },
+ ortb2: {
+ source: {
+ tid: 'tid000'
+ },
+ site: {
+ mobile: 0,
+ page: page,
+ },
+ device: {
+ w: screen.width,
+ h: screen.height,
+ dnt: 0,
+ ua: navigator.userAgent
+ }
}
- }
- };
- const request = spec.buildRequests(bidRequests, bidderRequest);
- expect(request.method).to.equal('POST');
- expect(request.url).to.equal('https://web.hb.ad.cpe.dotomi.com/cvx/client/hb/ortb/25');
- const payload = request.data;
+ };
+ request = spec.buildRequests(bidRequests, bidderRequest);
+ payload = request.data;
+ });
+
+ it('Verify common elements', function() {
+ expect(request.method).to.equal('POST');
+ expect(request.url).to.equal('https://web.hb.ad.cpe.dotomi.com/cvx/client/hb/ortb/25');
+
+ expect(payload).to.have.property('id');
+ expect(payload.source).to.have.property('tid', 'tid000');
+ expect(payload).to.have.property('at', 1);
+ expect(payload).to.have.property('imp');
+ expect(payload.imp).to.be.an('array').with.lengthOf(bidRequests.length);
+
+ expect(payload).to.have.property('site');
+ expect(payload.site).to.have.property('id', siteId);
+ expect(payload.site).to.have.property('mobile').that.is.oneOf([0, 1]);
+
+ expect(payload.site).to.have.property('page', page);
+
+ expect(payload).to.have.property('device');
+ expect(payload.device).to.have.property('w', screen.width);
+ expect(payload.device).to.have.property('h', screen.height);
+ expect(payload.device).to.have.property('dnt').that.is.oneOf([0, 1]);
+ expect(payload.device).to.have.property('ua', navigator.userAgent);
+
+ expect(payload).to.not.have.property('user'); // there should be no user by default
+ expect(payload).to.not.have.property('tmax'); // there should be no user by default
+ });
- expect(payload).to.have.property('id');
- expect(payload.source).to.have.property('tid', 'tid000');
- expect(payload).to.have.property('at', 1);
- expect(payload).to.have.property('imp');
- expect(payload.imp).to.be.an('array').with.lengthOf(8);
-
- expect(payload.imp[0]).to.have.property('id', 'bid000');
- expect(payload.imp[0]).to.have.property('secure', 1);
- expect(payload.imp[0]).to.have.property('bidfloor', 0.5);
- expect(payload.imp[0]).to.have.property('displaymanager', 'Prebid.js');
- expect(payload.imp[0]).to.have.property('displaymanagerver').that.matches(versionPattern);
- expect(payload.imp[0]).to.have.property('tagid', 'tagid-1');
- expect(payload.imp[0]).to.have.property('banner');
- expect(payload.imp[0].banner).to.have.property('pos', 1);
- expect(payload.imp[0].banner).to.have.property('format');
- expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}]);
- expect(payload.imp[0]).to.not.have.property('video');
-
- expect(payload.imp[1]).to.have.property('id', 'bid001');
- expect(payload.imp[1]).to.have.property('secure', 1);
- expect(payload.imp[1]).to.have.property('bidfloor', 0);
- expect(payload.imp[1]).to.have.property('displaymanager', 'Prebid.js');
- expect(payload.imp[1]).to.have.property('displaymanagerver').that.matches(versionPattern);
- expect(payload.imp[1]).to.not.have.property('tagid');
- expect(payload.imp[1]).to.have.property('banner');
- expect(payload.imp[1].banner).to.not.have.property('pos');
- expect(payload.imp[1].banner).to.have.property('format');
- expect(payload.imp[1].banner.format).to.deep.equal([{w: 728, h: 90}, {w: 468, h: 60}]);
-
- expect(payload.imp[2]).to.have.property('id', 'bid002');
- expect(payload.imp[2]).to.have.property('secure', 1);
- expect(payload.imp[2]).to.have.property('bidfloor', 0);
- expect(payload.imp[2]).to.have.property('displaymanager', 'Prebid.js');
- expect(payload.imp[2]).to.have.property('displaymanagerver').that.matches(versionPattern);
- expect(payload.imp[2]).to.have.property('banner');
- expect(payload.imp[2].banner).to.have.property('pos', 2);
- expect(payload.imp[2].banner).to.have.property('format');
- expect(payload.imp[2].banner.format).to.deep.equal([{w: 300, h: 600}, {w: 160, h: 600}]);
-
- expect(payload.imp[3]).to.have.property('id', 'bid003');
- expect(payload.imp[3]).to.have.property('secure', 1);
- expect(payload.imp[3]).to.have.property('bidfloor', 0);
- expect(payload.imp[3]).to.have.property('displaymanager', 'Prebid.js');
- expect(payload.imp[3]).to.have.property('displaymanagerver').that.matches(versionPattern);
- expect(payload.imp[3]).to.not.have.property('tagid');
- expect(payload.imp[3]).to.have.property('video');
- expect(payload.imp[3].video).to.have.property('pos', 3);
- expect(payload.imp[3].video).to.have.property('w', 632);
- expect(payload.imp[3].video).to.have.property('h', 499);
- expect(payload.imp[3].video).to.have.property('mimes');
- expect(payload.imp[3].video.mimes).to.deep.equal(['video/mp4', 'video/x-flv']);
- expect(payload.imp[3].video).to.have.property('protocols');
- expect(payload.imp[3].video.protocols).to.deep.equal([1, 2]);
- expect(payload.imp[3].video).to.have.property('api');
- expect(payload.imp[3].video.api).to.deep.equal([2]);
- expect(payload.imp[3].video).to.have.property('maxduration', 30);
- expect(payload.imp[3]).to.not.have.property('banner');
-
- expect(payload.imp[4]).to.have.property('id', 'bid004');
- expect(payload.imp[4]).to.have.property('secure', 1);
- expect(payload.imp[4]).to.have.property('bidfloor', 0);
- expect(payload.imp[4]).to.have.property('displaymanager', 'Prebid.js');
- expect(payload.imp[4]).to.have.property('displaymanagerver').that.matches(versionPattern);
- expect(payload.imp[4]).to.not.have.property('tagid');
- expect(payload.imp[4]).to.have.property('video');
- expect(payload.imp[4].video).to.not.have.property('pos');
- expect(payload.imp[4].video).to.have.property('w', 1024);
- expect(payload.imp[4].video).to.have.property('h', 768);
- expect(payload.imp[4].video).to.have.property('mimes');
- expect(payload.imp[4].video.mimes).to.deep.equal(['video/mp4', 'video/x-flv']);
- expect(payload.imp[4].video).to.have.property('protocols');
- expect(payload.imp[4].video.protocols).to.deep.equal([1, 2, 3]);
- expect(payload.imp[4].video).to.have.property('api');
- expect(payload.imp[4].video.api).to.deep.equal([2, 3]);
- expect(payload.imp[4].video).to.have.property('maxduration', 30);
- expect(payload.imp[4]).to.not.have.property('banner');
-
- expect(payload.imp[5]).to.have.property('id', 'bid005');
- expect(payload.imp[5]).to.have.property('secure', 1);
- expect(payload.imp[5]).to.have.property('bidfloor', 0);
- expect(payload.imp[5]).to.have.property('displaymanager', 'Prebid.js');
- expect(payload.imp[5]).to.have.property('displaymanagerver').that.matches(versionPattern);
- expect(payload.imp[5]).to.not.have.property('tagid');
- expect(payload.imp[5]).to.have.property('video');
- expect(payload.imp[5].video).to.have.property('pos', 2);
- expect(payload.imp[5].video).to.not.have.property('w');
- expect(payload.imp[5].video).to.not.have.property('h');
- expect(payload.imp[5].video).to.have.property('mimes');
- expect(payload.imp[5].video.mimes).to.deep.equal(['video/mp4', 'video/x-flv']);
- expect(payload.imp[5].video).to.not.have.property('protocols');
- expect(payload.imp[5].video).to.not.have.property('api');
- expect(payload.imp[5].video).to.not.have.property('maxduration');
- expect(payload.imp[5]).to.not.have.property('banner');
-
- expect(payload.imp[6]).to.have.property('id', 'bid006');
- expect(payload.imp[6]).to.have.property('video');
- expect(payload.imp[6].video).to.have.property('mimes');
- expect(payload.imp[6].video.mimes).to.deep.equal(['video/mp4', 'video/x-flv']);
- expect(payload.imp[6]).to.not.have.property('banner');
- expect(payload.imp[6]).to.have.property('instl');
- expect(payload.imp[6]).to.have.property('ext');
- expect(payload.imp[6].ext).to.have.property('data');
- expect(payload.imp[6].ext.data).to.have.property('pbadslot');
-
- expect(payload.imp[7]).to.have.property('id', 'bid007');
- expect(payload.imp[7]).to.have.property('secure', 1);
- expect(payload.imp[7]).to.have.property('bidfloor', 0);
- expect(payload.imp[7]).to.have.property('displaymanager', 'Prebid.js');
- expect(payload.imp[7]).to.have.property('displaymanagerver').that.matches(versionPattern);
- expect(payload.imp[7]).to.not.have.property('tagid');
- expect(payload.imp[7]).to.have.property('banner');
- expect(payload.imp[7].banner).to.have.property('pos', 5);
- expect(payload.imp[7].banner).to.have.property('format');
- expect(payload.imp[7].banner.format).to.deep.equal([{w: 728, h: 90}, {w: 468, h: 60}]);
-
- expect(payload).to.have.property('site');
- expect(payload.site).to.have.property('id', siteId);
- expect(payload.site).to.have.property('mobile').that.is.oneOf([0, 1]);
-
- expect(payload.site).to.have.property('page', page);
-
- expect(payload).to.have.property('device');
- expect(payload.device).to.have.property('w', screen.width);
- expect(payload.device).to.have.property('h', screen.height);
- expect(payload.device).to.have.property('dnt').that.is.oneOf([0, 1]);
- expect(payload.device).to.have.property('ua', navigator.userAgent);
-
- expect(payload).to.not.have.property('user'); // there should be no user by default
- expect(payload).to.not.have.property('tmax'); // there should be no user by default
+ it('Simple banner', () => {
+ expect(payload.imp[0]).to.have.property('id', 'bid000');
+ expect(payload.imp[0]).to.have.property('secure', 1);
+ expect(payload.imp[0]).to.have.property('bidfloor', 0.5);
+ expect(payload.imp[0]).to.have.property('displaymanager', 'Prebid.js');
+ expect(payload.imp[0]).to.have.property('displaymanagerver').that.matches(versionPattern);
+ expect(payload.imp[0]).to.have.property('tagid', 'tagid-1');
+ expect(payload.imp[0]).to.have.property('banner');
+ expect(payload.imp[0].banner).to.have.property('pos', 1);
+ expect(payload.imp[0].banner).to.have.property('format');
+ expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}]);
+ expect(payload.imp[0]).to.not.have.property('video');
+ });
+
+ it('Banner multiple sizes', () => {
+ expect(payload.imp[1]).to.have.property('id', 'bid001');
+ expect(payload.imp[1]).to.have.property('secure', 1);
+ expect(payload.imp[1]).to.have.property('bidfloor', 0);
+ expect(payload.imp[1]).to.have.property('displaymanager', 'Prebid.js');
+ expect(payload.imp[1]).to.have.property('displaymanagerver').that.matches(versionPattern);
+ expect(payload.imp[1]).to.not.have.property('tagid');
+ expect(payload.imp[1]).to.have.property('banner');
+ expect(payload.imp[1].banner).to.not.have.property('pos');
+ expect(payload.imp[1].banner).to.have.property('format');
+ expect(payload.imp[1].banner.format).to.deep.equal([{w: 728, h: 90}, {w: 468, h: 60}]);
+ });
+
+ it('Banner with tagid and position', () => {
+ expect(payload.imp[2]).to.have.property('id', 'bid002');
+ expect(payload.imp[2]).to.have.property('secure', 1);
+ expect(payload.imp[2]).to.have.property('bidfloor', 0);
+ expect(payload.imp[2]).to.have.property('displaymanager', 'Prebid.js');
+ expect(payload.imp[2]).to.have.property('displaymanagerver').that.matches(versionPattern);
+ expect(payload.imp[2]).to.have.property('banner');
+ expect(payload.imp[2].banner).to.have.property('pos', 2);
+ expect(payload.imp[2].banner).to.have.property('format');
+ expect(payload.imp[2].banner.format).to.deep.equal([{w: 300, h: 600}, {w: 160, h: 600}]);
+ });
+
+ if (FEATURES.VIDEO) {
+ it('Simple video', () => {
+ expect(payload.imp[3]).to.have.property('id', 'bid003');
+ expect(payload.imp[3]).to.have.property('secure', 1);
+ expect(payload.imp[3]).to.have.property('bidfloor', 0);
+ expect(payload.imp[3]).to.have.property('displaymanager', 'Prebid.js');
+ expect(payload.imp[3]).to.have.property('displaymanagerver').that.matches(versionPattern);
+ expect(payload.imp[3]).to.not.have.property('tagid');
+ expect(payload.imp[3]).to.have.property('video');
+ expect(payload.imp[3].video).to.have.property('pos', 3);
+ expect(payload.imp[3].video).to.have.property('w', 632);
+ expect(payload.imp[3].video).to.have.property('h', 499);
+ expect(payload.imp[3].video).to.have.property('mimes');
+ expect(payload.imp[3].video.mimes).to.deep.equal(['video/mp4', 'video/x-flv']);
+ expect(payload.imp[3].video).to.have.property('protocols');
+ expect(payload.imp[3].video.protocols).to.deep.equal([1, 2]);
+ expect(payload.imp[3].video).to.have.property('api');
+ expect(payload.imp[3].video.api).to.deep.equal([2]);
+ expect(payload.imp[3].video).to.have.property('maxduration', 30);
+ expect(payload.imp[3]).to.not.have.property('banner');
+ });
+
+ it('Video with playerSize', () => {
+ expect(payload.imp[4]).to.have.property('id', 'bid004');
+ expect(payload.imp[4]).to.have.property('secure', 1);
+ expect(payload.imp[4]).to.have.property('bidfloor', 0);
+ expect(payload.imp[4]).to.have.property('displaymanager', 'Prebid.js');
+ expect(payload.imp[4]).to.have.property('displaymanagerver').that.matches(versionPattern);
+ expect(payload.imp[4]).to.not.have.property('tagid');
+ expect(payload.imp[4]).to.have.property('video');
+ expect(payload.imp[4].video).to.not.have.property('pos');
+ expect(payload.imp[4].video).to.have.property('w', 1024);
+ expect(payload.imp[4].video).to.have.property('h', 768);
+ expect(payload.imp[4].video).to.have.property('mimes');
+ expect(payload.imp[4].video.mimes).to.deep.equal(['video/mp4', 'video/x-flv']);
+ expect(payload.imp[4].video).to.have.property('protocols');
+ expect(payload.imp[4].video.protocols).to.deep.equal([1, 2, 3]);
+ expect(payload.imp[4].video).to.have.property('api');
+ expect(payload.imp[4].video.api).to.deep.equal([1, 2, 3]);
+ expect(payload.imp[4].video).to.have.property('maxduration', 30);
+ });
+
+ it('Video without sizes', () => {
+ expect(payload.imp[5]).to.have.property('id', 'bid005');
+ expect(payload.imp[5]).to.have.property('secure', 1);
+ expect(payload.imp[5]).to.have.property('bidfloor', 0);
+ expect(payload.imp[5]).to.have.property('displaymanager', 'Prebid.js');
+ expect(payload.imp[5]).to.have.property('displaymanagerver').that.matches(versionPattern);
+ expect(payload.imp[5]).to.not.have.property('tagid');
+ expect(payload.imp[5]).to.have.property('video');
+ expect(payload.imp[5].video).to.have.property('pos', 2);
+ expect(payload.imp[5].video).to.not.have.property('w');
+ expect(payload.imp[5].video).to.not.have.property('h');
+ expect(payload.imp[5].video).to.have.property('mimes');
+ expect(payload.imp[5].video.mimes).to.deep.equal(['video/mp4', 'video/x-flv']);
+ expect(payload.imp[5].video).to.not.have.property('protocols');
+ expect(payload.imp[5].video).to.not.have.property('api');
+ expect(payload.imp[5].video).to.not.have.property('maxduration');
+ expect(payload.imp[5]).to.not.have.property('banner');
+ });
+ }
+
+ it('With FPD', () => {
+ expect(payload.imp[6]).to.have.property('id', 'bid006');
+ expect(payload.imp[6]).to.have.property('banner');
+ expect(payload.imp[6]).to.not.have.property('video');
+ expect(payload.imp[6]).to.have.property('instl');
+ expect(payload.imp[6]).to.have.property('ext');
+ expect(payload.imp[6].ext).to.have.property('data');
+ expect(payload.imp[6].ext.data).to.have.property('pbadslot');
+ });
});
it('Verify timeout', () => {
@@ -440,59 +460,62 @@ describe('Conversant adapter tests', function() {
expect(request.url).to.equal(testUrl);
});
- it('Verify interpretResponse', function() {
- const request = spec.buildRequests(bidRequests, {});
- const response = spec.interpretResponse(bidResponses, request);
- expect(response).to.be.an('array').with.lengthOf(4);
-
- let bid = response[0];
- expect(bid).to.have.property('requestId', 'bid000');
- expect(bid).to.have.property('currency', 'USD');
- expect(bid).to.have.property('cpm', 0.99);
- expect(bid).to.have.property('creativeId', '1000');
- expect(bid).to.have.property('width', 300);
- expect(bid).to.have.property('height', 250);
- expect(bid.meta.advertiserDomains).to.deep.equal(['https://example.com']);
- expect(bid).to.have.property('ad', 'markup000
');
- expect(bid).to.have.property('ttl', 300);
- expect(bid).to.have.property('netRevenue', true);
+ describe('Verify interpretResponse', function() {
+ let bid, request, response;
+
+ before(() => {
+ request = spec.buildRequests(bidRequests, {});
+ response = spec.interpretResponse(bidResponses, request);
+ });
+
+ it('Banner', function() {
+ expect(response).to.be.an('array').with.lengthOf(4);
+ bid = response[0];
+ expect(bid).to.have.property('requestId', 'bid000');
+ expect(bid).to.have.property('cpm', 0.99);
+ expect(bid).to.have.property('creativeId', '1000');
+ expect(bid).to.have.property('width', 300);
+ expect(bid).to.have.property('height', 250);
+ expect(bid.meta.advertiserDomains).to.deep.equal(['https://example.com']);
+ expect(bid).to.have.property('ad', 'markup000
');
+ expect(bid).to.have.property('ttl', 300);
+ expect(bid).to.have.property('netRevenue', true);
+ });
// There is no bid001 because cpm is $0
- bid = response[1];
- expect(bid).to.have.property('requestId', 'bid002');
- expect(bid).to.have.property('currency', 'USD');
- expect(bid).to.have.property('cpm', 2.99);
- expect(bid).to.have.property('creativeId', '1002');
- expect(bid).to.have.property('width', 300);
- expect(bid).to.have.property('height', 600);
- expect(bid).to.have.property('ad', 'markup002
');
- expect(bid).to.have.property('ttl', 300);
- expect(bid).to.have.property('netRevenue', true);
-
- bid = response[2];
- expect(bid).to.have.property('requestId', 'bid003');
- expect(bid).to.have.property('currency', 'USD');
- expect(bid).to.have.property('cpm', 3.99);
- expect(bid).to.have.property('creativeId', '1003');
- expect(bid).to.have.property('width', 632);
- expect(bid).to.have.property('height', 499);
- expect(bid).to.have.property('vastUrl', 'markup003');
- expect(bid).to.have.property('mediaType', 'video');
- expect(bid).to.have.property('ttl', 300);
- expect(bid).to.have.property('netRevenue', true);
-
- bid = response[3];
- expect(bid).to.have.property('vastXml', '
');
- });
+ it('Banner multiple sizes', function() {
+ bid = response[1];
+ expect(bid).to.have.property('requestId', 'bid002');
+ expect(bid).to.have.property('cpm', 2.99);
+ expect(bid).to.have.property('creativeId', '1002');
+ expect(bid).to.have.property('width', 300);
+ expect(bid).to.have.property('height', 600);
+ expect(bid).to.have.property('ad', 'markup002
');
+ expect(bid).to.have.property('ttl', 300);
+ expect(bid).to.have.property('netRevenue', true);
+ });
+
+ if (FEATURES.VIDEO) {
+ it('Video', function () {
+ bid = response[2];
+ expect(bid).to.have.property('requestId', 'bid003');
+ expect(bid).to.have.property('cpm', 3.99);
+ expect(bid).to.have.property('creativeId', '1003');
+ expect(bid).to.have.property('playerWidth', 632);
+ expect(bid).to.have.property('playerHeight', 499);
+ expect(bid).to.have.property('vastUrl', 'notify003');
+ expect(bid).to.have.property('vastXml', 'markup003');
+ expect(bid).to.have.property('mediaType', 'video');
+ expect(bid).to.have.property('ttl', 300);
+ expect(bid).to.have.property('netRevenue', true);
+ });
- it('Verify handling of bad responses', function() {
- let response = spec.interpretResponse({}, {});
- expect(response).to.be.an('array').with.lengthOf(0);
- response = spec.interpretResponse({id: '123'}, {});
- expect(response).to.be.an('array').with.lengthOf(0);
- response = spec.interpretResponse({id: '123', seatbid: []}, {});
- expect(response).to.be.an('array').with.lengthOf(0);
+ it('Empty Video', function() {
+ bid = response[3];
+ expect(bid).to.have.property('vastXml', '
');
+ });
+ }
});
it('Verify publisher commond id support', function() {
@@ -524,79 +547,23 @@ describe('Conversant adapter tests', function() {
expect(payload).to.not.have.nested.property('user.ext.eids');
});
- it('Verify GDPR bid request', function() {
- // add gdpr info
- const bidderRequest = {
- gdprConsent: {
- consentString: 'BOJObISOJObISAABAAENAA4AAAAAoAAA',
- gdprApplies: true
- }
- };
-
- const payload = spec.buildRequests(bidRequests, bidderRequest).data;
- expect(payload).to.have.deep.nested.property('user.ext.consent', 'BOJObISOJObISAABAAENAA4AAAAAoAAA');
- expect(payload).to.have.deep.nested.property('regs.ext.gdpr', 1);
- });
-
- it('Verify GDPR bid request without gdprApplies', function() {
- // add gdpr info
- const bidderRequest = {
- gdprConsent: {
- consentString: ''
- }
- };
-
- const payload = spec.buildRequests(bidRequests, bidderRequest).data;
- expect(payload).to.have.deep.nested.property('user.ext.consent', '');
- expect(payload).to.not.have.deep.nested.property('regs.ext.gdpr');
- });
-
- describe('CCPA', function() {
- it('should have us_privacy', function() {
- const bidderRequest = {
- uspConsent: '1NYN'
- };
-
- const payload = spec.buildRequests(bidRequests, bidderRequest).data;
- expect(payload).to.have.deep.nested.property('regs.ext.us_privacy', '1NYN');
- expect(payload).to.not.have.deep.nested.property('regs.ext.gdpr');
- });
-
- it('should have no us_privacy', function() {
- const payload = spec.buildRequests(bidRequests, {}).data;
- expect(payload).to.not.have.deep.nested.property('regs.ext.us_privacy');
- });
-
- it('should have both gdpr and us_privacy', function() {
- const bidderRequest = {
- gdprConsent: {
- consentString: 'BOJObISOJObISAABAAENAA4AAAAAoAAA',
- gdprApplies: true
- },
- uspConsent: '1NYN'
- };
-
- const payload = spec.buildRequests(bidRequests, bidderRequest).data;
- expect(payload).to.have.deep.nested.property('user.ext.consent', 'BOJObISOJObISAABAAENAA4AAAAAoAAA');
- expect(payload).to.have.deep.nested.property('regs.ext.gdpr', 1);
- expect(payload).to.have.deep.nested.property('regs.ext.us_privacy', '1NYN');
- });
- });
-
describe('Extended ID', function() {
it('Verify unifiedid and liveramp', function() {
// clone bidRequests
let requests = utils.deepClone(bidRequests);
+ const uid = {pubcid: '112233', idl_env: '334455'};
+ const eidArray = [{'source': 'pubcid.org', 'uids': [{'id': '112233', 'atype': 1}]}, {'source': 'liveramp.com', 'uids': [{'id': '334455', 'atype': 3}]}];
+
// add pubcid to every entry
requests.forEach((unit) => {
- Object.assign(unit, {userId: {pubcid: '112233', tdid: '223344', idl_env: '334455'}});
- Object.assign(unit, {userIdAsEids: createEidsArray(unit.userId)});
+ Object.assign(unit, {userId: uid});
+ Object.assign(unit, {userIdAsEids: eidArray});
});
// construct http post payload
const payload = spec.buildRequests(requests, {}).data;
expect(payload).to.have.deep.nested.property('user.ext.eids', [
- {source: 'adserver.org', uids: [{id: '223344', atype: 1, ext: {rtiPartner: 'TDID'}}]},
+ {source: 'pubcid.org', uids: [{id: '112233', atype: 1}]},
{source: 'liveramp.com', uids: [{id: '334455', atype: 3}]}
]);
});
diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js
index 7cba0e2fbdf..2cdb09f2098 100755
--- a/test/spec/modules/criteoBidAdapter_spec.js
+++ b/test/spec/modules/criteoBidAdapter_spec.js
@@ -364,93 +364,6 @@ describe('The Criteo bidding adapter', function () {
});
it('should return false when given an invalid video bid request', function () {
- expect(spec.isBidRequestValid({
- bidder: 'criteo',
- mediaTypes: {
- video: {
- mimes: ['video/mpeg'],
- playerSize: [640, 480],
- protocols: [5, 6],
- maxduration: 30,
- api: [1, 2]
- }
- },
- params: {
- networkId: 456,
- video: {
- skip: 1,
- placement: 1,
- playbackmethod: 1
- }
- },
- })).to.equal(false);
-
- expect(spec.isBidRequestValid({
- bidder: 'criteo',
- mediaTypes: {
- video: {
- context: 'instream',
- mimes: ['video/mpeg'],
- playerSize: [640, 480],
- protocols: [5, 6],
- maxduration: 30,
- api: [1, 2]
- }
- },
- params: {
- networkId: 456,
- video: {
- skip: 1,
- placement: 2,
- playbackmethod: 1
- }
- },
- })).to.equal(false);
-
- expect(spec.isBidRequestValid({
- bidder: 'criteo',
- mediaTypes: {
- video: {
- context: 'outstream',
- mimes: ['video/mpeg'],
- playerSize: [640, 480],
- protocols: [5, 6],
- maxduration: 30,
- api: [1, 2]
- }
- },
- params: {
- networkId: 456,
- video: {
- skip: 1,
- placement: 1,
- playbackmethod: 1
- }
- },
- })).to.equal(false);
-
- expect(spec.isBidRequestValid({
- bidder: 'criteo',
- mediaTypes: {
- video: {
- context: 'adpod',
- mimes: ['video/mpeg'],
- playerSize: [640, 480],
- protocols: [5, 6],
- maxduration: 30,
- api: [1, 2]
- }
- },
- params: {
- networkId: 456,
- video: {
- skip: 1,
- placement: 1,
- playbackmethod: 1
- }
- },
- })).to.equal(false);
-
expect(spec.isBidRequestValid({
bidder: 'criteo',
mediaTypes: {
@@ -1122,6 +1035,30 @@ describe('The Criteo bidding adapter', function () {
expect(request.data.user.uspIab).to.equal('1YNY');
});
+ it('should properly build a request with site and app ortb fields', function () {
+ const bidRequests = [];
+ let app = {
+ publisher: {
+ id: 'appPublisherId'
+ }
+ };
+ let site = {
+ publisher: {
+ id: 'sitePublisherId'
+ }
+ };
+ const bidderRequest = {
+ ortb2: {
+ app: app,
+ site: site
+ }
+ };
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+
+ expect(request.data.app).to.equal(app);
+ expect(request.data.site).to.equal(site);
+ });
+
it('should properly build a request with device sua field', function () {
const sua = {}
const bidRequests = [
@@ -1173,7 +1110,7 @@ describe('The Criteo bidding adapter', function () {
const ortb2 = {
regs: {
gpp: 'gpp_consent_string',
- gpp_sid: [0, 1, 2]
+ gpp_sid: [0, 1, 2],
}
};
@@ -1183,6 +1120,48 @@ describe('The Criteo bidding adapter', function () {
expect(request.data.regs.gpp_sid).to.deep.equal([0, 1, 2]);
});
+ it('should properly build a request with dsa object', function () {
+ const bidRequests = [
+ {
+ bidder: 'criteo',
+ adUnitCode: 'bid-123',
+ transactionId: 'transaction-123',
+ mediaTypes: {
+ banner: {
+ sizes: [[728, 90]]
+ }
+ },
+ params: {
+ zoneId: 123,
+ },
+ },
+ ];
+ let dsa = {
+ required: 3,
+ pubrender: 0,
+ datatopub: 2,
+ transparency: [{
+ domain: 'platform1domain.com',
+ params: [1]
+ }, {
+ domain: 'SSP2domain.com',
+ params: [1, 2]
+ }]
+ };
+ const ortb2 = {
+ regs: {
+ ext: {
+ dsa: dsa
+ }
+ }
+ };
+
+ const request = spec.buildRequests(bidRequests, { ...bidderRequest, ortb2 });
+ expect(request.data.regs).to.not.be.null;
+ expect(request.data.regs.ext).to.not.be.null;
+ expect(request.data.regs.ext.dsa).to.deep.equal(dsa);
+ });
+
it('should properly build a request with schain object', function () {
const expectedSchain = {
someProperty: 'someValue'
@@ -1326,12 +1305,25 @@ describe('The Criteo bidding adapter', function () {
sizes: [[640, 480]],
mediaTypes: {
video: {
+ context: 'instream',
playerSize: [640, 480],
mimes: ['video/mp4', 'video/x-flv'],
maxduration: 30,
api: [1, 2],
protocols: [2, 3],
- plcmt: 3
+ plcmt: 3,
+ w: 640,
+ h: 480,
+ linearity: 1,
+ skipmin: 30,
+ skipafter: 30,
+ minbitrate: 10000,
+ maxbitrate: 48000,
+ delivery: [1, 2, 3],
+ pos: 1,
+ playbackend: 1,
+ adPodDurationSec: 30,
+ durationRangeSec: [1, 30],
}
},
params: {
@@ -1350,6 +1342,7 @@ describe('The Criteo bidding adapter', function () {
expect(request.url).to.match(/^https:\/\/bidder\.criteo\.com\/cdb\?profileId=207&av=\d+&wv=[^&]+&cb=\d/);
expect(request.method).to.equal('POST');
const ortbRequest = request.data;
+ expect(ortbRequest.slots[0].video.context).to.equal('instream');
expect(ortbRequest.slots[0].video.mimes).to.deep.equal(['video/mp4', 'video/x-flv']);
expect(ortbRequest.slots[0].sizes).to.deep.equal([]);
expect(ortbRequest.slots[0].video.playersizes).to.deep.equal(['640x480']);
@@ -1362,6 +1355,18 @@ describe('The Criteo bidding adapter', function () {
expect(ortbRequest.slots[0].video.playbackmethod).to.deep.equal([1, 3]);
expect(ortbRequest.slots[0].video.placement).to.equal(2);
expect(ortbRequest.slots[0].video.plcmt).to.equal(3);
+ expect(ortbRequest.slots[0].video.w).to.equal(640);
+ expect(ortbRequest.slots[0].video.h).to.equal(480);
+ expect(ortbRequest.slots[0].video.linearity).to.equal(1);
+ expect(ortbRequest.slots[0].video.skipmin).to.equal(30);
+ expect(ortbRequest.slots[0].video.skipafter).to.equal(30);
+ expect(ortbRequest.slots[0].video.minbitrate).to.equal(10000);
+ expect(ortbRequest.slots[0].video.maxbitrate).to.equal(48000);
+ expect(ortbRequest.slots[0].video.delivery).to.deep.equal([1, 2, 3]);
+ expect(ortbRequest.slots[0].video.pos).to.equal(1);
+ expect(ortbRequest.slots[0].video.playbackend).to.equal(1);
+ expect(ortbRequest.slots[0].video.adPodDurationSec).to.equal(30);
+ expect(ortbRequest.slots[0].video.durationRangeSec).to.deep.equal([1, 30]);
});
it('should properly build a video request with more than one player size', function () {
@@ -1879,6 +1884,86 @@ describe('The Criteo bidding adapter', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request.data.slots[0].rwdd).to.be.undefined;
});
+
+ it('should properly build a request when FLEDGE is enabled', function () {
+ const bidderRequest = {
+ fledgeEnabled: true,
+ };
+ const bidRequests = [
+ {
+ bidder: 'criteo',
+ adUnitCode: 'bid-123',
+ transactionId: 'transaction-123',
+ mediaTypes: {
+ banner: {
+ sizes: [[728, 90]]
+ }
+ },
+ params: {
+ zoneId: 123,
+ ext: {
+ bidfloor: 0.75
+ }
+ },
+ ortb2Imp: {
+ ext: {
+ ae: 1
+ }
+ }
+ },
+ ];
+
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.slots[0].ext.ae).to.equal(1);
+ });
+
+ it('should properly build a request when FLEDGE is disabled', function () {
+ const bidderRequest = {
+ fledgeEnabled: false,
+ };
+ const bidRequests = [
+ {
+ bidder: 'criteo',
+ adUnitCode: 'bid-123',
+ transactionId: 'transaction-123',
+ mediaTypes: {
+ banner: {
+ sizes: [[728, 90]]
+ }
+ },
+ params: {
+ zoneId: 123,
+ ext: {
+ bidfloor: 0.75
+ }
+ },
+ ortb2Imp: {
+ ext: {
+ ae: 1
+ }
+ }
+ },
+ ];
+
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.slots[0].ext).to.not.have.property('ae');
+ });
+
+ it('should properly transmit device.ext.cdep if available', function () {
+ const bidderRequest = {
+ ortb2: {
+ device: {
+ ext: {
+ cdep: 'cookieDeprecationLabel'
+ }
+ }
+ }
+ };
+ const bidRequests = [];
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ const ortbRequest = request.data;
+ expect(ortbRequest.device.ext.cdep).to.equal('cookieDeprecationLabel');
+ });
});
describe('interpretResponse', function () {
@@ -1936,6 +2021,48 @@ describe('The Criteo bidding adapter', function () {
expect(bids[0].meta.networkName).to.equal('Criteo');
});
+ it('should properly parse a bid response with dsa', function () {
+ const response = {
+ body: {
+ slots: [{
+ impid: 'test-requestId',
+ cpm: 1.23,
+ creative: 'test-ad',
+ creativecode: 'test-crId',
+ width: 728,
+ height: 90,
+ deal: 'myDealCode',
+ adomain: ['criteo.com'],
+ ext: {
+ dsa: {
+ adrender: 1
+ },
+ meta: {
+ networkName: 'Criteo'
+ }
+ }
+ }],
+ },
+ };
+ const request = {
+ bidRequests: [{
+ adUnitCode: 'test-requestId',
+ bidId: 'test-bidId',
+ mediaTypes: {
+ banner: {
+ sizes: [[728, 90]]
+ }
+ },
+ params: {
+ networkId: 456,
+ }
+ }]
+ };
+ const bids = spec.interpretResponse(response, request);
+ expect(bids).to.have.lengthOf(1);
+ expect(bids[0].meta.dsa.adrender).to.equal(1);
+ });
+
it('should properly parse a bid response with a networkId with twin ad unit banner win', function () {
const response = {
body: {
@@ -2410,6 +2537,163 @@ describe('The Criteo bidding adapter', function () {
expect(bids[0].height).to.equal(90);
});
+ it('should properly parse a bid response with FLEDGE auction configs', function () {
+ let auctionConfig1 = {
+ auctionSignals: {},
+ decisionLogicUrl: 'https://grid-mercury.criteo.com/fledge/decision',
+ interestGroupBuyers: ['https://first-buyer-domain.com', 'https://second-buyer-domain.com'],
+ perBuyerSignals: {
+ 'https://first-buyer-domain.com': {
+ foo: 'bar',
+ },
+ 'https://second-buyer-domain.com': {
+ foo: 'baz'
+ },
+ },
+ perBuyerTimeout: {
+ '*': 500,
+ 'buyer1': 100,
+ 'buyer2': 200
+ },
+ perBuyerGroupLimits: {
+ '*': 60,
+ 'buyer1': 300,
+ 'buyer2': 400
+ },
+ seller: 'https://seller-domain.com',
+ sellerTimeout: 500,
+ sellerSignals: {
+ foo: 'bar',
+ foo2: 'bar2',
+ floor: 1,
+ currency: 'USD',
+ perBuyerTimeout: {
+ 'buyer1': 100,
+ 'buyer2': 200
+ },
+ perBuyerGroupLimits: {
+ 'buyer1': 300,
+ 'buyer2': 400
+ },
+ },
+ sellerCurrency: 'USD',
+ };
+ let auctionConfig2 = {
+ auctionSignals: {},
+ decisionLogicUrl: 'https://grid-mercury.criteo.com/fledge/decision',
+ interestGroupBuyers: ['https://first-buyer-domain.com', 'https://second-buyer-domain.com'],
+ perBuyerSignals: {
+ 'https://first-buyer-domain.com': {
+ foo: 'bar',
+ },
+ 'https://second-buyer-domain.com': {
+ foo: 'baz'
+ },
+ },
+ perBuyerTimeout: {
+ '*': 500,
+ 'buyer1': 100,
+ 'buyer2': 200
+ },
+ perBuyerGroupLimits: {
+ '*': 60,
+ 'buyer1': 300,
+ 'buyer2': 400
+ },
+ seller: 'https://seller-domain.com',
+ sellerTimeout: 500,
+ sellerSignals: {
+ foo: 'bar',
+ floor: 1,
+ perBuyerTimeout: {
+ 'buyer1': 100,
+ 'buyer2': 200
+ },
+ perBuyerGroupLimits: {
+ 'buyer1': 300,
+ 'buyer2': 400
+ },
+ },
+ sellerCurrency: '???'
+ };
+ const response = {
+ body: {
+ ext: {
+ igi: [{
+ impid: 'test-bidId',
+ igs: [{
+ impid: 'test-bidId',
+ bidId: 'test-bidId',
+ config: auctionConfig1
+ }]
+ }, {
+ impid: 'test-bidId-2',
+ igs: [{
+ impid: 'test-bidId-2',
+ bidId: 'test-bidId-2',
+ config: auctionConfig2
+ }]
+ }]
+ },
+ },
+ };
+ const bidderRequest = {
+ ortb2: {
+ source: {
+ tid: 'abc'
+ }
+ }
+ };
+ const bidRequests = [
+ {
+ bidId: 'test-bidId',
+ bidder: 'criteo',
+ adUnitCode: 'bid-123',
+ transactionId: 'transaction-123',
+ mediaTypes: {
+ banner: {
+ sizes: [[728, 90]]
+ }
+ },
+ params: {
+ bidFloor: 1,
+ bidFloorCur: 'EUR'
+ }
+ },
+ {
+ bidId: 'test-bidId-2',
+ bidder: 'criteo',
+ adUnitCode: 'bid-123',
+ transactionId: 'transaction-123',
+ mediaTypes: {
+ banner: {
+ sizes: [[728, 90]]
+ }
+ },
+ params: {
+ bidFloor: 1,
+ bidFloorCur: 'EUR'
+ }
+ },
+ ];
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ const interpretedResponse = spec.interpretResponse(response, request);
+ expect(interpretedResponse).to.have.property('bids');
+ expect(interpretedResponse).to.have.property('fledgeAuctionConfigs');
+ expect(interpretedResponse.bids).to.have.lengthOf(0);
+ expect(interpretedResponse.fledgeAuctionConfigs).to.have.lengthOf(2);
+ expect(interpretedResponse.fledgeAuctionConfigs[0]).to.deep.equal({
+ bidId: 'test-bidId',
+ impid: 'test-bidId',
+ config: auctionConfig1,
+ });
+ expect(interpretedResponse.fledgeAuctionConfigs[1]).to.deep.equal({
+ bidId: 'test-bidId-2',
+ impid: 'test-bidId-2',
+ config: auctionConfig2,
+ });
+ });
+
[{
hasBidResponseLevelPafData: true,
hasBidResponseBidLevelPafData: true,
diff --git a/test/spec/modules/criteoIdSystem_spec.js b/test/spec/modules/criteoIdSystem_spec.js
index aaf63873d93..975271738e5 100644
--- a/test/spec/modules/criteoIdSystem_spec.js
+++ b/test/spec/modules/criteoIdSystem_spec.js
@@ -52,17 +52,21 @@ describe('CriteoId module', function () {
});
const storageTestCases = [
- { cookie: 'bidId', localStorage: 'bidId2', expected: 'bidId' },
- { cookie: 'bidId', localStorage: undefined, expected: 'bidId' },
- { cookie: undefined, localStorage: 'bidId', expected: 'bidId' },
- { cookie: undefined, localStorage: undefined, expected: undefined },
+ { submoduleConfig: undefined, cookie: 'bidId', localStorage: 'bidId2', expected: 'bidId' },
+ { submoduleConfig: undefined, cookie: 'bidId', localStorage: undefined, expected: 'bidId' },
+ { submoduleConfig: undefined, cookie: undefined, localStorage: 'bidId', expected: 'bidId' },
+ { submoduleConfig: undefined, cookie: undefined, localStorage: undefined, expected: undefined },
+ { submoduleConfig: { storage: { type: 'cookie' } }, cookie: 'bidId', localStorage: 'bidId2', expected: 'bidId' },
+ { submoduleConfig: { storage: { type: 'cookie' } }, cookie: undefined, localStorage: 'bidId2', expected: undefined },
+ { submoduleConfig: { storage: { type: 'html5' } }, cookie: 'bidId', localStorage: 'bidId2', expected: 'bidId2' },
+ { submoduleConfig: { storage: { type: 'html5' } }, cookie: 'bidId', localStorage: undefined, expected: undefined },
]
- storageTestCases.forEach(testCase => it('getId() should return the bidId when it exists in local storages', function () {
+ storageTestCases.forEach(testCase => it('getId() should return the user id depending on the storage type enabled and the data available', function () {
getCookieStub.withArgs('cto_bidid').returns(testCase.cookie);
getLocalStorageStub.withArgs('cto_bidid').returns(testCase.localStorage);
- const result = criteoIdSubmodule.getId();
+ const result = criteoIdSubmodule.getId(testCase.submoduleConfig);
expect(result.id).to.be.deep.equal(testCase.expected ? { criteoId: testCase.expected } : undefined);
expect(result.callback).to.be.a('function');
}))
@@ -95,22 +99,24 @@ describe('CriteoId module', function () {
});
const responses = [
- { bundle: 'bundle', bidId: 'bidId', acwsUrl: 'acwsUrl' },
- { bundle: 'bundle', bidId: undefined, acwsUrl: 'acwsUrl' },
- { bundle: 'bundle', bidId: 'bidId', acwsUrl: undefined },
- { bundle: undefined, bidId: 'bidId', acwsUrl: 'acwsUrl' },
- { bundle: 'bundle', bidId: undefined, acwsUrl: undefined },
- { bundle: undefined, bidId: 'bidId', acwsUrl: undefined },
- { bundle: undefined, bidId: undefined, acwsUrl: 'acwsUrl' },
- { bundle: undefined, bidId: undefined, acwsUrl: ['acwsUrl', 'acwsUrl2'] },
- { bundle: undefined, bidId: undefined, acwsUrl: undefined },
+ { submoduleConfig: undefined, shouldWriteCookie: true, shouldWriteLocalStorage: true, bundle: 'bundle', bidId: 'bidId', acwsUrl: 'acwsUrl' },
+ { submoduleConfig: undefined, shouldWriteCookie: true, shouldWriteLocalStorage: true, bundle: 'bundle', bidId: undefined, acwsUrl: 'acwsUrl' },
+ { submoduleConfig: undefined, shouldWriteCookie: true, shouldWriteLocalStorage: true, bundle: 'bundle', bidId: 'bidId', acwsUrl: undefined },
+ { submoduleConfig: undefined, shouldWriteCookie: true, shouldWriteLocalStorage: true, bundle: undefined, bidId: 'bidId', acwsUrl: 'acwsUrl' },
+ { submoduleConfig: undefined, shouldWriteCookie: true, shouldWriteLocalStorage: true, bundle: 'bundle', bidId: undefined, acwsUrl: undefined },
+ { submoduleConfig: undefined, shouldWriteCookie: true, shouldWriteLocalStorage: true, bundle: undefined, bidId: 'bidId', acwsUrl: undefined },
+ { submoduleConfig: undefined, shouldWriteCookie: true, shouldWriteLocalStorage: true, bundle: undefined, bidId: undefined, acwsUrl: 'acwsUrl' },
+ { submoduleConfig: undefined, shouldWriteCookie: true, shouldWriteLocalStorage: true, bundle: undefined, bidId: undefined, acwsUrl: ['acwsUrl', 'acwsUrl2'] },
+ { submoduleConfig: undefined, shouldWriteCookie: true, shouldWriteLocalStorage: true, bundle: undefined, bidId: undefined, acwsUrl: undefined },
+ { submoduleConfig: { storage: { type: 'cookie' } }, shouldWriteCookie: true, shouldWriteLocalStorage: false, bundle: 'bundle', bidId: 'bidId', acwsUrl: undefined },
+ { submoduleConfig: { storage: { type: 'html5' } }, shouldWriteCookie: false, shouldWriteLocalStorage: true, bundle: 'bundle', bidId: 'bidId', acwsUrl: undefined },
]
responses.forEach(response => describe('test user sync response behavior', function () {
const expirationTs = new Date(nowTimestamp + cookiesMaxAge).toString();
it('should save bidId if it exists', function () {
- const result = criteoIdSubmodule.getId();
+ const result = criteoIdSubmodule.getId(response.submoduleConfig);
result.callback((id) => {
expect(id).to.be.deep.equal(response.bidId ? { criteoId: response.bidId } : undefined);
});
@@ -127,16 +133,35 @@ describe('CriteoId module', function () {
expect(setCookieStub.calledWith('cto_bundle')).to.be.false;
expect(setLocalStorageStub.calledWith('cto_bundle')).to.be.false;
} else if (response.bundle) {
- expect(setCookieStub.calledWith('cto_bundle', response.bundle, expirationTs, null, '.com')).to.be.true;
- expect(setCookieStub.calledWith('cto_bundle', response.bundle, expirationTs, null, '.testdev.com')).to.be.true;
- expect(setLocalStorageStub.calledWith('cto_bundle', response.bundle)).to.be.true;
+ if (response.shouldWriteCookie) {
+ expect(setCookieStub.calledWith('cto_bundle', response.bundle, expirationTs, null, '.com')).to.be.true;
+ expect(setCookieStub.calledWith('cto_bundle', response.bundle, expirationTs, null, '.testdev.com')).to.be.true;
+ } else {
+ expect(setCookieStub.calledWith('cto_bundle', response.bundle, expirationTs, null, '.com')).to.be.false;
+ expect(setCookieStub.calledWith('cto_bundle', response.bundle, expirationTs, null, '.testdev.com')).to.be.false;
+ }
+
+ if (response.shouldWriteLocalStorage) {
+ expect(setLocalStorageStub.calledWith('cto_bundle', response.bundle)).to.be.true;
+ } else {
+ expect(setLocalStorageStub.calledWith('cto_bundle', response.bundle)).to.be.false;
+ }
expect(triggerPixelStub.called).to.be.false;
}
if (response.bidId) {
- expect(setCookieStub.calledWith('cto_bidid', response.bidId, expirationTs, null, '.com')).to.be.true;
- expect(setCookieStub.calledWith('cto_bidid', response.bidId, expirationTs, null, '.testdev.com')).to.be.true;
- expect(setLocalStorageStub.calledWith('cto_bidid', response.bidId)).to.be.true;
+ if (response.shouldWriteCookie) {
+ expect(setCookieStub.calledWith('cto_bidid', response.bidId, expirationTs, null, '.com')).to.be.true;
+ expect(setCookieStub.calledWith('cto_bidid', response.bidId, expirationTs, null, '.testdev.com')).to.be.true;
+ } else {
+ expect(setCookieStub.calledWith('cto_bidid', response.bidId, expirationTs, null, '.com')).to.be.false;
+ expect(setCookieStub.calledWith('cto_bidid', response.bidId, expirationTs, null, '.testdev.com')).to.be.false;
+ }
+ if (response.shouldWriteLocalStorage) {
+ expect(setLocalStorageStub.calledWith('cto_bidid', response.bidId)).to.be.true;
+ } else {
+ expect(setLocalStorageStub.calledWith('cto_bidid', response.bidId)).to.be.false;
+ }
} else {
expect(setCookieStub.calledWith('cto_bidid', '', pastDateString, null, '.com')).to.be.true;
expect(setCookieStub.calledWith('cto_bidid', '', pastDateString, null, '.testdev.com')).to.be.true;
diff --git a/test/spec/modules/currency_spec.js b/test/spec/modules/currency_spec.js
index f7c2580f3f3..fa44b7daa7a 100644
--- a/test/spec/modules/currency_spec.js
+++ b/test/spec/modules/currency_spec.js
@@ -10,11 +10,12 @@ import {
addBidResponseHook,
currencySupportEnabled,
currencyRates,
- ready
+ responseReady
} from 'modules/currency.js';
import {createBid} from '../../../src/bidfactory.js';
import CONSTANTS from '../../../src/constants.json';
import {server} from '../../mocks/xhr.js';
+import * as events from 'src/events.js';
var assert = require('chai').assert;
var expect = require('chai').expect;
@@ -32,7 +33,6 @@ describe('currency', function () {
beforeEach(function () {
fakeCurrencyFileServer = server;
- ready.reset();
});
afterEach(function () {
@@ -259,6 +259,19 @@ describe('currency', function () {
expect(innerBid.getCpmInNewCurrency('JPY')).to.equal('100.000');
});
+ it('does not block auctions if rates do not need to be fetched', () => {
+ sandbox.stub(responseReady, 'resolve');
+ setConfig({
+ adServerCurrency: 'USD',
+ rates: {
+ USD: {
+ JPY: 100
+ }
+ }
+ });
+ sinon.assert.called(responseReady.resolve);
+ })
+
it('uses rates specified in json when provided and consider boosted bid', function () {
setConfig({
adServerCurrency: 'USD',
@@ -287,32 +300,56 @@ describe('currency', function () {
expect(innerBid.getCpmInNewCurrency('JPY')).to.equal('1000.000');
});
- it('uses default rates when currency file fails to load', function () {
- setConfig({});
-
- setConfig({
- adServerCurrency: 'USD',
- defaultRates: {
- USD: {
- JPY: 100
+ describe('when rates fail to load', () => {
+ let bid, addBidResponse, reject;
+ beforeEach(() => {
+ bid = makeBid({cpm: 100, currency: 'JPY', bidder: 'rubicoin'});
+ addBidResponse = sinon.spy();
+ reject = sinon.spy();
+ })
+ it('uses default rates if specified', function () {
+ setConfig({
+ adServerCurrency: 'USD',
+ defaultRates: {
+ USD: {
+ JPY: 100
+ }
}
- }
- });
-
- // default response is 404
- fakeCurrencyFileServer.respond();
+ });
- var bid = { cpm: 100, currency: 'JPY', bidder: 'rubicon' };
- var innerBid;
+ // default response is 404
+ addBidResponseHook(addBidResponse, 'au', bid);
+ fakeCurrencyFileServer.respond();
+ sinon.assert.calledWith(addBidResponse, 'au', sinon.match(innerBid => {
+ expect(innerBid.cpm).to.equal('1.0000');
+ expect(typeof innerBid.getCpmInNewCurrency).to.equal('function');
+ expect(innerBid.getCpmInNewCurrency('JPY')).to.equal('100.000');
+ return true;
+ }));
+ });
- addBidResponseHook(function(adCodeId, bid) {
- innerBid = bid;
- }, 'elementId', bid);
+ it('rejects bids if no default rates are specified', () => {
+ setConfig({
+ adServerCurrency: 'USD',
+ });
+ addBidResponseHook(addBidResponse, 'au', bid, reject);
+ fakeCurrencyFileServer.respond();
+ sinon.assert.notCalled(addBidResponse);
+ sinon.assert.calledWith(reject, CONSTANTS.REJECTION_REASON.CANNOT_CONVERT_CURRENCY);
+ });
- expect(innerBid.cpm).to.equal('1.0000');
- expect(typeof innerBid.getCpmInNewCurrency).to.equal('function');
- expect(innerBid.getCpmInNewCurrency('JPY')).to.equal('100.000');
- });
+ it('attempts to load rates again on the next auction', () => {
+ setConfig({
+ adServerCurrency: 'USD',
+ });
+ fakeCurrencyFileServer.respond();
+ fakeCurrencyFileServer.respondWith(JSON.stringify(getCurrencyRates()));
+ events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {});
+ addBidResponseHook(addBidResponse, 'au', bid, reject);
+ fakeCurrencyFileServer.respond();
+ sinon.assert.calledWith(addBidResponse, 'au', bid, reject);
+ })
+ })
});
describe('currency.addBidResponseDecorator bidResponseQueue', function () {
@@ -321,29 +358,26 @@ describe('currency', function () {
fakeCurrencyFileServer.respondWith(JSON.stringify(getCurrencyRates()));
- var bid = { 'cpm': 1, 'currency': 'USD' };
+ const bid = { 'cpm': 1, 'currency': 'USD' };
setConfig({ 'adServerCurrency': 'JPY' });
- var marker = false;
- let promiseResolved = false;
+ let responseAdded = false;
+ let isReady = false;
+ responseReady.promise.then(() => { isReady = true });
+
addBidResponseHook(Object.assign(function() {
- marker = true;
- }, {
- bail: function (promise) {
- promise.then(() => promiseResolved = true);
- }
+ responseAdded = true;
}), 'elementId', bid);
- expect(marker).to.equal(false);
-
setTimeout(() => {
- expect(promiseResolved).to.be.false;
+ expect(responseAdded).to.equal(false);
+ expect(isReady).to.equal(false);
fakeCurrencyFileServer.respond();
setTimeout(() => {
- expect(marker).to.equal(true);
- expect(promiseResolved).to.be.true;
+ expect(responseAdded).to.equal(true);
+ expect(isReady).to.equal(true);
done();
});
});
@@ -419,6 +453,23 @@ describe('currency', function () {
expect(reject.calledOnce).to.be.true;
});
+ it('should reject bid when rates have not loaded when the auction times out', () => {
+ fakeCurrencyFileServer.respondWith(JSON.stringify(getCurrencyRates()));
+ setConfig({'adServerCurrency': 'JPY'});
+ const bid = makeBid({cpm: 1, currency: 'USD', auctionId: 'aid'});
+ const noConversionBid = makeBid({cpm: 1, currency: 'JPY', auctionId: 'aid'});
+ const reject = sinon.spy();
+ const addBidResponse = sinon.spy();
+ addBidResponseHook(addBidResponse, 'au', bid, reject);
+ addBidResponseHook(addBidResponse, 'au', noConversionBid, reject);
+ events.emit(CONSTANTS.EVENTS.AUCTION_TIMEOUT, {auctionId: 'aid'});
+ fakeCurrencyFileServer.respond();
+ sinon.assert.calledOnce(addBidResponse);
+ sinon.assert.calledWith(addBidResponse, 'au', noConversionBid, reject);
+ sinon.assert.calledOnce(reject);
+ sinon.assert.calledWith(reject, CONSTANTS.REJECTION_REASON.CANNOT_CONVERT_CURRENCY);
+ })
+
it('should return 1 when currency support is enabled and same currency code is requested as is set to adServerCurrency', function () {
fakeCurrencyFileServer.respondWith(JSON.stringify(getCurrencyRates()));
setConfig({ 'adServerCurrency': 'JPY' });
diff --git a/test/spec/modules/debugging_mod_spec.js b/test/spec/modules/debugging_mod_spec.js
index 8c7f0e84bce..ab99ba2aa0c 100644
--- a/test/spec/modules/debugging_mod_spec.js
+++ b/test/spec/modules/debugging_mod_spec.js
@@ -103,8 +103,8 @@ describe('bid interceptor', () => {
});
describe('rule', () => {
- function matchingRule({replace, options}) {
- setRules({when: {}, then: replace, options: options});
+ function matchingRule({replace, options, paapi}) {
+ setRules({when: {}, then: replace, options: options, paapi});
return interceptor.match({});
}
@@ -164,6 +164,24 @@ describe('bid interceptor', () => {
});
});
+ describe('paapi', () => {
+ it('should accept literals', () => {
+ const mockConfig = [
+ {paapi: 1},
+ {paapi: 2}
+ ]
+ const paapi = matchingRule({paapi: mockConfig}).paapi({});
+ expect(paapi).to.eql(mockConfig);
+ });
+
+ it('should accept a function and pass extra args to it', () => {
+ const paapiDef = sinon.stub();
+ const args = [{}, {}, {}];
+ matchingRule({paapi: paapiDef}).paapi(...args);
+ expect(paapiDef.calledOnceWith(...args.map(sinon.match.same))).to.be.true;
+ })
+ })
+
describe('.options', () => {
it('should include default rule options', () => {
const optDef = {someOption: 'value'};
@@ -181,16 +199,17 @@ describe('bid interceptor', () => {
});
describe('intercept()', () => {
- let done, addBid;
+ let done, addBid, addPaapiConfig;
function intercept(args = {}) {
const bidRequest = {bids: args.bids || []};
- return interceptor.intercept(Object.assign({bidRequest, done, addBid}, args));
+ return interceptor.intercept(Object.assign({bidRequest, done, addBid, addPaapiConfig}, args));
}
beforeEach(() => {
done = sinon.spy();
addBid = sinon.spy();
+ addPaapiConfig = sinon.spy();
});
describe('on no match', () => {
@@ -253,6 +272,29 @@ describe('bid interceptor', () => {
});
});
+ it('should call addPaapiConfigs when provided', () => {
+ const mockPaapiConfigs = [
+ {paapi: 1},
+ {paapi: 2}
+ ]
+ setRules({
+ when: {id: 2},
+ paapi: mockPaapiConfigs,
+ });
+ intercept({bidRequest: REQUEST});
+ expect(addPaapiConfig.callCount).to.eql(2);
+ mockPaapiConfigs.forEach(cfg => sinon.assert.calledWith(addPaapiConfig, cfg))
+ })
+
+ it('should not call onBid when then is null', () => {
+ setRules({
+ when: {id: 2},
+ then: null
+ });
+ intercept({bidRequest: REQUEST});
+ sinon.assert.notCalled(addBid);
+ })
+
it('should call done()', () => {
intercept({bidRequest: REQUEST});
expect(done.calledOnce).to.be.true;
diff --git a/test/spec/modules/deepintentBidAdapter_spec.js b/test/spec/modules/deepintentBidAdapter_spec.js
index d2a351b4089..644e9255789 100644
--- a/test/spec/modules/deepintentBidAdapter_spec.js
+++ b/test/spec/modules/deepintentBidAdapter_spec.js
@@ -357,5 +357,34 @@ describe('Deepintent adapter', function () {
let response = spec.interpretResponse(invalidResponse, bRequest);
expect(response[0].mediaType).to.equal(undefined);
});
- })
+ });
+ describe('GPP and coppa', function() {
+ it('Request params check with GPP Consent', function () {
+ let bidderReq = {gppConsent: {gppString: 'gpp-string-test', applicableSections: [5]}};
+ let bRequest = spec.buildRequests(request, bidderReq);
+ let data = JSON.parse(bRequest.data);
+ expect(data.regs.gpp).to.equal('gpp-string-test');
+ expect(data.regs.gpp_sid[0]).to.equal(5);
+ });
+ it('Request params check with GPP Consent read from ortb2', function () {
+ let bidderReq = {
+ ortb2: {
+ regs: {
+ gpp: 'gpp-test-string',
+ gpp_sid: [5]
+ }
+ }
+ };
+ let bRequest = spec.buildRequests(request, bidderReq);
+ let data = JSON.parse(bRequest.data);
+ expect(data.regs.gpp).to.equal('gpp-test-string');
+ expect(data.regs.gpp_sid[0]).to.equal(5);
+ });
+ it('should include coppa flag in bid request if coppa is set to true', () => {
+ let bidderReq = {ortb2: {regs: {coppa: 1}}};
+ let bRequest = spec.buildRequests(request, bidderReq);
+ let data = JSON.parse(bRequest.data);
+ expect(data.regs.coppa).to.equal(1);
+ });
+ });
});
diff --git a/test/spec/modules/dfpAdServerVideo_spec.js b/test/spec/modules/dfpAdServerVideo_spec.js
index 89485adf28b..39713c2b51a 100644
--- a/test/spec/modules/dfpAdServerVideo_spec.js
+++ b/test/spec/modules/dfpAdServerVideo_spec.js
@@ -1,43 +1,61 @@
-import { expect } from 'chai';
+import {expect} from 'chai';
import parse from 'url-parse';
-import {buildDfpVideoUrl, buildAdpodVideoUrl, dep} from 'modules/dfpAdServerVideo.js';
-import adUnit from 'test/fixtures/video/adUnit.json';
+import {buildAdpodVideoUrl, buildDfpVideoUrl, dep} from 'modules/dfpAdServerVideo.js';
+import AD_UNIT from 'test/fixtures/video/adUnit.json';
import * as utils from 'src/utils.js';
-import { config } from 'src/config.js';
-import { targeting } from 'src/targeting.js';
-import { auctionManager } from 'src/auctionManager.js';
-import { gdprDataHandler, uspDataHandler } from 'src/adapterManager.js';
+import {deepClone} from 'src/utils.js';
+import {config} from 'src/config.js';
+import {targeting} from 'src/targeting.js';
+import {auctionManager} from 'src/auctionManager.js';
+import {gdprDataHandler, uspDataHandler} from 'src/adapterManager.js';
import * as adpod from 'modules/adpod.js';
-import { server } from 'test/mocks/xhr.js';
+import {server} from 'test/mocks/xhr.js';
import * as adServer from 'src/adserver.js';
-import {deepClone} from 'src/utils.js';
import {hook} from '../../../src/hook.js';
-import {getRefererInfo} from '../../../src/refererDetection.js';
-
-const bid = {
- videoCacheKey: 'abc',
- adserverTargeting: {
- hb_uuid: 'abc',
- hb_cache_id: 'abc',
- },
-};
+import {stubAuctionIndex} from '../../helpers/indexStub.js';
+import {AuctionIndex} from '../../../src/auctionIndex.js';
describe('The DFP video support module', function () {
before(() => {
hook.ready();
});
- let sandbox;
+ let sandbox, bid, adUnit;
beforeEach(() => {
sandbox = sinon.sandbox.create();
+ bid = {
+ videoCacheKey: 'abc',
+ adserverTargeting: {
+ hb_uuid: 'abc',
+ hb_cache_id: 'abc',
+ },
+ };
+ adUnit = deepClone(AD_UNIT);
});
afterEach(() => {
sandbox.restore();
});
+ function getURL(options) {
+ return parse(buildDfpVideoUrl(Object.assign({
+ adUnit: adUnit,
+ bid: bid,
+ params: {
+ 'iu': 'my/adUnit'
+ }
+ }, options)))
+ }
+ function getQueryParams(options) {
+ return utils.parseQS(getURL(options).query);
+ }
+
+ function getCustomParams(options) {
+ return utils.parseQS('?' + decodeURIComponent(getQueryParams(options).cust_params));
+ }
+
Object.entries({
params: {
params: {
@@ -51,27 +69,25 @@ describe('The DFP video support module', function () {
describe(`when using ${t}`, () => {
it('should use page location as default for description_url', () => {
sandbox.stub(dep, 'ri').callsFake(() => ({page: 'example.com'}));
-
- const url = parse(buildDfpVideoUrl(Object.assign({
- adUnit: adUnit,
- bid: bid,
- }, options)));
- const prm = utils.parseQS(url.query);
+ const prm = getQueryParams(options);
expect(prm.description_url).to.eql('example.com');
- })
- })
+ });
+
+ it('should use a URI encoded page location as default for description_url', () => {
+ sandbox.stub(dep, 'ri').callsFake(() => ({page: 'https://example.com?iu=/99999999/news&cust_params=current_hour%3D12%26newscat%3Dtravel&pbjs_debug=true'}));
+ const prm = getQueryParams(options);
+ expect(prm.description_url).to.eql('https%3A%2F%2Fexample.com%3Fiu%3D%2F99999999%2Fnews%26cust_params%3Dcurrent_hour%253D12%2526newscat%253Dtravel%26pbjs_debug%3Dtrue');
+ });
+ });
})
it('should make a legal request URL when given the required params', function () {
- const url = parse(buildDfpVideoUrl({
- adUnit: adUnit,
- bid: bid,
+ const url = getURL({
params: {
'iu': 'my/adUnit',
'description_url': 'someUrl.com',
}
- }));
-
+ })
expect(url.protocol).to.equal('https:');
expect(url.host).to.equal('securepubads.g.doubleclick.net');
@@ -88,15 +104,10 @@ describe('The DFP video support module', function () {
});
it('can take an adserver url as a parameter', function () {
- const bidCopy = utils.deepClone(bid);
- bidCopy.vastUrl = 'vastUrl.example';
-
- const url = parse(buildDfpVideoUrl({
- adUnit: adUnit,
- bid: bidCopy,
+ bid.vastUrl = 'vastUrl.example';
+ const url = getURL({
url: 'https://video.adserver.example/',
- }));
-
+ })
expect(url.host).to.equal('video.adserver.example');
});
@@ -110,161 +121,64 @@ describe('The DFP video support module', function () {
});
it('overwrites url params when both url and params object are given', function () {
- const url = parse(buildDfpVideoUrl({
- adUnit: adUnit,
- bid: bid,
+ const params = getQueryParams({
url: 'https://video.adserver.example/ads?sz=640x480&iu=/123/aduniturl&impl=s',
params: { iu: 'my/adUnit' }
- }));
+ });
- const queryObject = utils.parseQS(url.query);
- expect(queryObject.iu).to.equal('my/adUnit');
+ expect(params.iu).to.equal('my/adUnit');
});
it('should override param defaults with user-provided ones', function () {
- const url = parse(buildDfpVideoUrl({
- adUnit: adUnit,
- bid: bid,
+ const params = getQueryParams({
params: {
- 'iu': 'my/adUnit',
'output': 'vast',
}
- }));
-
- expect(utils.parseQS(url.query)).to.have.property('output', 'vast');
+ });
+ expect(params.output).to.equal('vast');
});
it('should include the cache key and adserver targeting in cust_params', function () {
- const bidCopy = utils.deepClone(bid);
- bidCopy.adserverTargeting = Object.assign(bidCopy.adserverTargeting, {
+ bid.adserverTargeting = Object.assign(bid.adserverTargeting, {
hb_adid: 'ad_id',
});
- const url = parse(buildDfpVideoUrl({
- adUnit: adUnit,
- bid: bidCopy,
- params: {
- 'iu': 'my/adUnit'
- }
- }));
- const queryObject = utils.parseQS(url.query);
- const customParams = utils.parseQS('?' + decodeURIComponent(queryObject.cust_params));
+ const customParams = getCustomParams()
expect(customParams).to.have.property('hb_adid', 'ad_id');
expect(customParams).to.have.property('hb_uuid', bid.videoCacheKey);
expect(customParams).to.have.property('hb_cache_id', bid.videoCacheKey);
});
- it('should include the us_privacy key when USP Consent is available', function () {
- let uspDataHandlerStub = sinon.stub(uspDataHandler, 'getConsentData');
- uspDataHandlerStub.returns('1YYY');
-
- const bidCopy = utils.deepClone(bid);
- bidCopy.adserverTargeting = Object.assign(bidCopy.adserverTargeting, {
- hb_adid: 'ad_id',
- });
-
- const url = parse(buildDfpVideoUrl({
- adUnit: adUnit,
- bid: bidCopy,
- params: {
- 'iu': 'my/adUnit'
- }
- }));
- const queryObject = utils.parseQS(url.query);
- expect(queryObject.us_privacy).to.equal('1YYY');
- uspDataHandlerStub.restore();
- });
-
- it('should not include the us_privacy key when USP Consent is not available', function () {
- const bidCopy = utils.deepClone(bid);
- bidCopy.adserverTargeting = Object.assign(bidCopy.adserverTargeting, {
- hb_adid: 'ad_id',
- });
-
- const url = parse(buildDfpVideoUrl({
- adUnit: adUnit,
- bid: bidCopy,
- params: {
- 'iu': 'my/adUnit'
- }
- }));
- const queryObject = utils.parseQS(url.query);
- expect(queryObject.us_privacy).to.equal(undefined);
- });
-
it('should include the GDPR keys when GDPR Consent is available', function () {
- let gdprDataHandlerStub = sinon.stub(gdprDataHandler, 'getConsentData');
- gdprDataHandlerStub.returns({
+ sandbox.stub(gdprDataHandler, 'getConsentData').returns({
gdprApplies: true,
consentString: 'consent',
addtlConsent: 'moreConsent'
});
-
- const bidCopy = utils.deepClone(bid);
- bidCopy.adserverTargeting = Object.assign(bidCopy.adserverTargeting, {
- hb_adid: 'ad_id',
- });
-
- const url = parse(buildDfpVideoUrl({
- adUnit: adUnit,
- bid: bidCopy,
- params: {
- 'iu': 'my/adUnit'
- }
- }));
- const queryObject = utils.parseQS(url.query);
+ const queryObject = getQueryParams();
expect(queryObject.gdpr).to.equal('1');
expect(queryObject.gdpr_consent).to.equal('consent');
expect(queryObject.addtl_consent).to.equal('moreConsent');
- gdprDataHandlerStub.restore();
});
it('should not include the GDPR keys when GDPR Consent is not available', function () {
- const bidCopy = utils.deepClone(bid);
- bidCopy.adserverTargeting = Object.assign(bidCopy.adserverTargeting, {
- hb_adid: 'ad_id',
- });
-
- const url = parse(buildDfpVideoUrl({
- adUnit: adUnit,
- bid: bidCopy,
- params: {
- 'iu': 'my/adUnit'
- }
- }));
- const queryObject = utils.parseQS(url.query);
+ const queryObject = getQueryParams()
expect(queryObject.gdpr).to.equal(undefined);
expect(queryObject.gdpr_consent).to.equal(undefined);
expect(queryObject.addtl_consent).to.equal(undefined);
});
it('should only include the GDPR keys for GDPR Consent fields with values', function () {
- let gdprDataHandlerStub = sinon.stub(gdprDataHandler, 'getConsentData');
- gdprDataHandlerStub.returns({
+ sandbox.stub(gdprDataHandler, 'getConsentData').returns({
gdprApplies: true,
consentString: 'consent',
});
-
- const bidCopy = utils.deepClone(bid);
- bidCopy.adserverTargeting = Object.assign(bidCopy.adserverTargeting, {
- hb_adid: 'ad_id',
- });
-
- const url = parse(buildDfpVideoUrl({
- adUnit: adUnit,
- bid: bidCopy,
- params: {
- 'iu': 'my/adUnit'
- }
- }));
- const queryObject = utils.parseQS(url.query);
+ const queryObject = getQueryParams()
expect(queryObject.gdpr).to.equal('1');
expect(queryObject.gdpr_consent).to.equal('consent');
expect(queryObject.addtl_consent).to.equal(undefined);
- gdprDataHandlerStub.restore();
});
-
describe('GAM PPID', () => {
let ppid;
let getPPIDStub;
@@ -280,29 +194,283 @@ describe('The DFP video support module', function () {
'url': {url: 'https://video.adserver.mock/', params: {'iu': 'mock/unit'}}
}).forEach(([t, opts]) => {
describe(`when using ${t}`, () => {
- function buildUrlAndGetParams() {
- const url = parse(buildDfpVideoUrl(Object.assign({
- adUnit: adUnit,
- bid: deepClone(bid),
- }, opts)));
- return utils.parseQS(url.query);
- }
-
it('should be included if available', () => {
ppid = 'mockPPID';
- const q = buildUrlAndGetParams();
+ const q = getQueryParams(opts);
expect(q.ppid).to.equal('mockPPID');
});
it('should not be included if not available', () => {
ppid = undefined;
- const q = buildUrlAndGetParams();
+ const q = getQueryParams(opts);
expect(q.hasOwnProperty('ppid')).to.be.false;
})
})
})
})
+ describe('ORTB video parameters', () => {
+ Object.entries({
+ plcmt: [
+ {
+ video: {
+ plcmt: 1
+ },
+ expected: '1'
+ }
+ ],
+ min_ad_duration: [
+ {
+ video: {
+ minduration: 123
+ },
+ expected: '123000'
+ }
+ ],
+ max_ad_duration: [
+ {
+ video: {
+ maxduration: 321
+ },
+ expected: '321000'
+ }
+ ],
+ vpos: [
+ {
+ video: {
+ startdelay: 0
+ },
+ expected: 'preroll'
+ },
+ {
+ video: {
+ startdelay: -1
+ },
+ expected: 'midroll'
+ },
+ {
+ video: {
+ startdelay: -2
+ },
+ expected: 'postroll'
+ },
+ {
+ video: {
+ startdelay: 10
+ },
+ expected: 'midroll'
+ }
+ ],
+ vconp: [
+ {
+ video: {
+ playbackmethod: [7]
+ },
+ expected: '2'
+ },
+ {
+ video: {
+ playbackmethod: [7, 1]
+ },
+ expected: undefined
+ }
+ ],
+ vpa: [
+ {
+ video: {
+ playbackmethod: [1, 2, 4, 5, 6, 7]
+ },
+ expected: 'auto'
+ },
+ {
+ video: {
+ playbackmethod: [3, 7],
+ },
+ expected: 'click'
+ },
+ {
+ video: {
+ playbackmethod: [1, 3],
+ },
+ expected: undefined
+ }
+ ],
+ vpmute: [
+ {
+ video: {
+ playbackmethod: [1, 3, 4, 5, 7]
+ },
+ expected: '0'
+ },
+ {
+ video: {
+ playbackmethod: [2, 6, 7],
+ },
+ expected: '1'
+ },
+ {
+ video: {
+ playbackmethod: [1, 2]
+ },
+ expected: undefined
+ }
+ ]
+ }).forEach(([param, cases]) => {
+ describe(param, () => {
+ cases.forEach(({video, expected}) => {
+ describe(`when mediaTypes.video has ${JSON.stringify(video)}`, () => {
+ it(`fills in ${param} = ${expected}`, () => {
+ Object.assign(adUnit.mediaTypes.video, video);
+ expect(getQueryParams()[param]).to.eql(expected);
+ });
+ it(`does not override pub-provided params.${param}`, () => {
+ Object.assign(adUnit.mediaTypes.video, video);
+ expect(getQueryParams({
+ params: {
+ [param]: 'OG'
+ }
+ })[param]).to.eql('OG');
+ });
+ it('does not fill if param has no value', () => {
+ expect(getQueryParams().hasOwnProperty(param)).to.be.false;
+ })
+ })
+ })
+ })
+ })
+ });
+
+ describe('ppsj', () => {
+ let ortb2;
+ beforeEach(() => {
+ ortb2 = null;
+ })
+
+ function getSignals() {
+ const ppsj = JSON.parse(atob(getQueryParams().ppsj));
+ return Object.fromEntries(ppsj.PublisherProvidedTaxonomySignals.map(sig => [sig.taxonomy, sig.values]));
+ }
+
+ Object.entries({
+ 'FPD from bid request'() {
+ bid.requestId = 'req-id';
+ sandbox.stub(auctionManager, 'index').get(() => stubAuctionIndex({
+ bidRequests: [
+ {
+ bidId: 'req-id',
+ ortb2
+ }
+ ]
+ }));
+ },
+ 'global FPD from auction'() {
+ bid.auctionId = 'auid';
+ sandbox.stub(auctionManager, 'index').get(() => new AuctionIndex(() => [{
+ getAuctionId: () => 'auid',
+ getFPD: () => ({
+ global: ortb2
+ })
+ }]));
+ }
+ }).forEach(([t, setup]) => {
+ describe(`using ${t}`, () => {
+ beforeEach(setup);
+ it('does not fill if there\'s no segments in segtax 4 or 6', () => {
+ ortb2 = {
+ site: {
+ content: {
+ data: [
+ {
+ segment: [
+ {id: '1'},
+ {id: '2'}
+ ]
+ },
+ ]
+ }
+ },
+ user: {
+ data: [
+ {
+ ext: {
+ segtax: 1,
+ },
+ segment: [
+ {id: '3'}
+ ]
+ }
+ ]
+ }
+ }
+ expect(getQueryParams().ppsj).to.not.exist;
+ });
+
+ const SEGMENTS = [
+ {
+ ext: {
+ segtax: 4,
+ },
+ segment: [
+ {id: '4-1'},
+ {id: '4-2'}
+ ]
+ },
+ {
+ ext: {
+ segtax: 4,
+ },
+ segment: [
+ {id: '4-2'},
+ {id: '4-3'}
+ ]
+ },
+ {
+ ext: {
+ segtax: 6,
+ },
+ segment: [
+ {id: '6-1'},
+ {id: '6-2'}
+ ]
+ },
+ {
+ ext: {
+ segtax: 6,
+ },
+ segment: [
+ {id: '6-2'},
+ {id: '6-3'}
+ ]
+ },
+ ]
+
+ it('collects user.data segments with segtax = 4 into IAB_AUDIENCE_1_1', () => {
+ ortb2 = {
+ user: {
+ data: SEGMENTS
+ }
+ }
+ expect(getSignals()).to.eql({
+ IAB_AUDIENCE_1_1: ['4-1', '4-2', '4-3']
+ })
+ })
+
+ it('collects site.content.data segments with segtax = 6 into IAB_CONTENT_2_2', () => {
+ ortb2 = {
+ site: {
+ content: {
+ data: SEGMENTS
+ }
+ }
+ }
+ expect(getSignals()).to.eql({
+ IAB_CONTENT_2_2: ['6-1', '6-2', '6-3']
+ })
+ })
+ })
+ })
+ })
+
describe('special targeting unit test', function () {
const allTargetingData = {
'hb_format': 'video',
@@ -629,7 +797,6 @@ describe('The DFP video support module', function () {
expect(queryParams).to.have.property('unviewed_position_start', '1');
expect(queryParams).to.have.property('url');
expect(queryParams).to.have.property('cust_params');
- expect(queryParams).to.have.property('us_privacy', '1YYY');
expect(queryParams).to.have.property('gdpr', '1');
expect(queryParams).to.have.property('gdpr_consent', 'consent');
expect(queryParams).to.have.property('addtl_consent', 'moreConsent');
diff --git a/test/spec/modules/dgkeywordRtdProvider_spec.js b/test/spec/modules/dgkeywordRtdProvider_spec.js
index 754740b7a64..ff88ea0512f 100644
--- a/test/spec/modules/dgkeywordRtdProvider_spec.js
+++ b/test/spec/modules/dgkeywordRtdProvider_spec.js
@@ -91,6 +91,22 @@ describe('Digital Garage Keyword Module', function () {
expect(dgRtd.getTargetBidderOfDgKeywords(adUnits_no_target)).an('array')
.that.is.empty;
});
+ it('convertKeywordsToString method unit test', function () {
+ const keywordsTest = [
+ { keywords: { param1: 'keywords1' }, result: 'param1=keywords1' },
+ { keywords: { param1: 'keywords1', param2: 'keywords2' }, result: 'param1=keywords1,param2=keywords2' },
+ { keywords: { p1: 'k1', p2: 'k2', p: 'k' }, result: 'p1=k1,p2=k2,p=k' },
+ { keywords: { p1: 'k1', p2: 'k2', p: ['k'] }, result: 'p1=k1,p2=k2,p=k' },
+ { keywords: { p1: 'k1', p2: ['k21', 'k22'], p: ['k'] }, result: 'p1=k1,p2=k21,p2=k22,p=k' },
+ { keywords: { p1: ['k11', 'k12', 'k13'], p2: ['k21', 'k22'], p: ['k'] }, result: 'p1=k11,p1=k12,p1=k13,p2=k21,p2=k22,p=k' },
+ { keywords: { p1: [], p2: ['', ''], p: [''] }, result: 'p1,p2,p' },
+ { keywords: { p1: 1, p2: [1, 'k2'], p: '' }, result: 'p1,p2=k2,p' },
+ { keywords: { p1: ['k1', 2, 'k3'], p2: [1, 2], p: 3 }, result: 'p1=k1,p1=k3,p2,p' },
+ ];
+ for (const test of keywordsTest) {
+ expect(dgRtd.convertKeywordsToString(test.keywords)).equal(test.result);
+ }
+ })
it('should have targets', function () {
const adUnits_targets = [
{
@@ -242,16 +258,16 @@ describe('Digital Garage Keyword Module', function () {
expect(targets[1].bidder).to.be.equal('dg2');
expect(targets[1].params.placementId).to.be.equal(99999998);
expect(targets[1].params.dgkeyword).to.be.an('undefined');
- expect(targets[1].params.keywords).to.be.an('undefined');
+ expect(targets[1].params.ortb2Imp).to.be.an('undefined');
targets = pbjs.adUnits[1].bids;
expect(targets[0].bidder).to.be.equal('dg');
expect(targets[0].params.placementId).to.be.equal(99999996);
expect(targets[0].params.dgkeyword).to.be.an('undefined');
- expect(targets[0].params.keywords).to.be.an('undefined');
+ expect(targets[0].params.ortb2Imp).to.be.an('undefined');
expect(targets[2].bidder).to.be.equal('dg3');
expect(targets[2].params.placementId).to.be.equal(99999994);
expect(targets[2].params.dgkeyword).to.be.an('undefined');
- expect(targets[2].params.keywords).to.be.an('undefined');
+ expect(targets[2].params.ortb2Imp).to.be.an('undefined');
expect(pbjs.getBidderConfig()).to.be.deep.equal({});
@@ -275,16 +291,16 @@ describe('Digital Garage Keyword Module', function () {
expect(targets[1].bidder).to.be.equal('dg2');
expect(targets[1].params.placementId).to.be.equal(99999998);
expect(targets[1].params.dgkeyword).to.be.an('undefined');
- expect(targets[1].params.keywords).to.be.an('undefined');
+ expect(targets[1].params.ortb2Imp).to.be.an('undefined');
targets = pbjs.adUnits[1].bids;
expect(targets[0].bidder).to.be.equal('dg');
expect(targets[0].params.placementId).to.be.equal(99999996);
expect(targets[0].params.dgkeyword).to.be.an('undefined');
- expect(targets[0].params.keywords).to.be.an('undefined');
+ expect(targets[0].params.ortb2Imp).to.be.an('undefined');
expect(targets[2].bidder).to.be.equal('dg3');
expect(targets[2].params.placementId).to.be.equal(99999994);
expect(targets[2].params.dgkeyword).to.be.an('undefined');
- expect(targets[2].params.keywords).to.be.an('undefined');
+ expect(targets[2].params.ortb2Imp).to.be.an('undefined');
expect(pbjs.getBidderConfig()).to.be.deep.equal({});
@@ -318,16 +334,16 @@ describe('Digital Garage Keyword Module', function () {
expect(targets[1].bidder).to.be.equal('dg2');
expect(targets[1].params.placementId).to.be.equal(99999998);
expect(targets[1].params.dgkeyword).to.be.an('undefined');
- expect(targets[1].params.keywords).to.be.deep.equal(SUCCESS_RESULT);
+ expect(targets[1].ortb2Imp.ext.data.keywords).to.be.deep.equal(dgRtd.convertKeywordsToString(SUCCESS_RESULT));
targets = pbjs.adUnits[1].bids;
expect(targets[0].bidder).to.be.equal('dg');
expect(targets[0].params.placementId).to.be.equal(99999996);
expect(targets[0].params.dgkeyword).to.be.an('undefined');
- expect(targets[0].params.keywords).to.be.deep.equal(SUCCESS_RESULT);
+ expect(targets[0].ortb2Imp.ext.data.keywords).to.be.deep.equal(dgRtd.convertKeywordsToString(SUCCESS_RESULT));
expect(targets[2].bidder).to.be.equal('dg3');
expect(targets[2].params.placementId).to.be.equal(99999994);
expect(targets[2].params.dgkeyword).to.be.an('undefined');
- expect(targets[2].params.keywords).to.be.an('undefined');
+ expect(targets[2].ortb2Imp).to.be.an('undefined');
if (!IGNORE_SET_ORTB2) {
expect(pbjs.getBidderConfig()).to.be.deep.equal({
diff --git a/test/spec/modules/discoveryBidAdapter_spec.js b/test/spec/modules/discoveryBidAdapter_spec.js
index 078add73046..f1475ec3739 100644
--- a/test/spec/modules/discoveryBidAdapter_spec.js
+++ b/test/spec/modules/discoveryBidAdapter_spec.js
@@ -1,5 +1,17 @@
import { expect } from 'chai';
-import { spec } from 'modules/discoveryBidAdapter.js';
+import {
+ spec,
+ getPmgUID,
+ storage,
+ getPageTitle,
+ getPageDescription,
+ getPageKeywords,
+ getConnectionDownLink,
+ THIRD_PARTY_COOKIE_ORIGIN,
+ COOKIE_KEY_MGUID,
+ getCurrentTimeToUTCString
+} from 'modules/discoveryBidAdapter.js';
+import * as utils from 'src/utils.js';
describe('discovery:BidAdapterTests', function () {
let bidRequestData = {
@@ -11,12 +23,59 @@ describe('discovery:BidAdapterTests', function () {
bidder: 'discovery',
params: {
token: 'd0f4902b616cc5c38cbe0a08676d0ed9',
+ siteId: 'siteId_01',
+ zoneId: 'zoneId_01',
+ publisher: '52',
+ position: 'left',
+ referrer: 'https://discovery.popin.cc',
+ },
+ refererInfo: {
+ page: 'https://discovery.popin.cc',
+ stack: [
+ 'a.com',
+ 'b.com'
+ ]
},
mediaTypes: {
banner: {
sizes: [[300, 250]],
+ pos: 'left',
+ },
+ },
+ ortb2: {
+ user: {
+ ext: {
+ data: {
+ CxSegments: []
+ }
+ }
+ },
+ site: {
+ domain: 'discovery.popin.cc',
+ publisher: {
+ domain: 'discovery.popin.cc'
+ },
+ page: 'https://discovery.popin.cc',
+ cat: ['IAB-19', 'IAB-20'],
},
},
+ ortb2Imp: {
+ ext: {
+ gpid: 'adslot_gpid',
+ tid: 'tid_01',
+ data: {
+ browsi: {
+ browsiViewability: 'NA',
+ },
+ adserver: {
+ name: 'adserver_name',
+ adslot: 'adslot_name',
+ },
+ keywords: ['travel', 'sport'],
+ pbadslot: '202309999'
+ }
+ }
+ },
adUnitCode: 'regular_iframe',
transactionId: 'd163f9e2-7ecd-4c2c-a3bd-28ceb52a60ee',
sizes: [[300, 250]],
@@ -29,9 +88,96 @@ describe('discovery:BidAdapterTests', function () {
bidderWinsCount: 0,
},
],
+ ortb2: {
+ user: {
+ data: {
+ segment: [
+ {
+ id: '412'
+ }
+ ],
+ name: 'test.popin.cc',
+ ext: {
+ segclass: '1',
+ segtax: 503
+ }
+ }
+ }
+ }
};
let request = [];
+ let bidRequestDataNoParams = {
+ bidderCode: 'discovery',
+ auctionId: 'ff66e39e-4075-4d18-9854-56fde9b879ac',
+ bidderRequestId: '4fec04e87ad785',
+ bids: [
+ {
+ bidder: 'discovery',
+ params: {
+ referrer: 'https://discovery.popin.cc',
+ },
+ refererInfo: {
+ page: 'https://discovery.popin.cc',
+ stack: [
+ 'a.com',
+ 'b.com'
+ ]
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250]],
+ pos: 'left',
+ },
+ },
+ ortb2: {
+ user: {
+ ext: {
+ data: {
+ CxSegments: []
+ }
+ }
+ },
+ site: {
+ domain: 'discovery.popin.cc',
+ publisher: {
+ domain: 'discovery.popin.cc'
+ },
+ page: 'https://discovery.popin.cc',
+ cat: ['IAB-19', 'IAB-20'],
+ },
+ },
+ ortb2Imp: {
+ ext: {
+ gpid: 'adslot_gpid',
+ tid: 'tid_01',
+ data: {
+ browsi: {
+ browsiViewability: 'NA',
+ },
+ adserver: {
+ name: 'adserver_name',
+ adslot: 'adslot_name',
+ },
+ keywords: ['travel', 'sport'],
+ pbadslot: '202309999'
+ }
+ }
+ },
+ adUnitCode: 'regular_iframe',
+ transactionId: 'd163f9e2-7ecd-4c2c-a3bd-28ceb52a60ee',
+ sizes: [[300, 250]],
+ bidId: '276092a19e05eb',
+ bidderRequestId: '1fadae168708b',
+ auctionId: 'ff66e39e-4075-4d18-9854-56fde9b879ac',
+ src: 'client',
+ bidRequestsCount: 1,
+ bidderRequestsCount: 1,
+ bidderWinsCount: 0,
+ },
+ ],
+ };
+
it('discovery:validate_pub_params', function () {
expect(
spec.isBidRequestValid({
@@ -45,11 +191,68 @@ describe('discovery:BidAdapterTests', function () {
).to.equal(true);
});
+ it('isBidRequestValid:no_params', function () {
+ expect(
+ spec.isBidRequestValid({
+ bidder: 'discovery',
+ params: {},
+ })
+ ).to.equal(true);
+ });
+
it('discovery:validate_generated_params', function () {
request = spec.buildRequests(bidRequestData.bids, bidRequestData);
let req_data = JSON.parse(request.data);
expect(req_data.imp).to.have.lengthOf(1);
});
+ describe('first party data', function () {
+ it('should pass additional parameter in request for topics', function () {
+ const request = spec.buildRequests(bidRequestData.bids, bidRequestData);
+ let res = JSON.parse(request.data);
+ expect(res.ext.tpData).to.deep.equal(bidRequestData.ortb2.user.data);
+ });
+ });
+
+ describe('discovery: buildRequests', function() {
+ describe('getPmgUID function', function() {
+ let sandbox;
+
+ beforeEach(() => {
+ sandbox = sinon.sandbox.create();
+ sandbox.stub(storage, 'getCookie');
+ sandbox.stub(storage, 'setCookie');
+ sandbox.stub(utils, 'generateUUID').returns('new-uuid');
+ sandbox.stub(storage, 'cookiesAreEnabled');
+ })
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should generate new UUID and set cookie if not exists', () => {
+ storage.cookiesAreEnabled.callsFake(() => true);
+ storage.getCookie.callsFake(() => null);
+ const uid = getPmgUID();
+ expect(uid).to.equal('new-uuid');
+ expect(storage.setCookie.calledOnce).to.be.true;
+ });
+
+ it('should return existing UUID from cookie', () => {
+ storage.cookiesAreEnabled.callsFake(() => true);
+ storage.getCookie.callsFake(() => 'existing-uuid');
+ const uid = getPmgUID();
+ expect(uid).to.equal('existing-uuid');
+ expect(storage.setCookie.called).to.be.true;
+ });
+
+ it('should not set new UUID when cookies are not enabled', () => {
+ storage.cookiesAreEnabled.callsFake(() => false);
+ storage.getCookie.callsFake(() => null);
+ getPmgUID();
+ expect(storage.setCookie.calledOnce).to.be.false;
+ });
+ })
+ });
it('discovery:validate_response_params', function () {
let tempAdm = '
'
@@ -90,4 +293,324 @@ describe('discovery:BidAdapterTests', function () {
expect(bid.height).to.equal(250);
expect(bid.currency).to.equal('USD');
});
+
+ describe('discovery: getUserSyncs', function() {
+ const COOKY_SYNC_IFRAME_URL = 'https://asset.popin.cc/js/cookieSync.html';
+ const IFRAME_ENABLED = {
+ iframeEnabled: true,
+ pixelEnabled: false,
+ };
+ const IFRAME_DISABLED = {
+ iframeEnabled: false,
+ pixelEnabled: false,
+ };
+ const GDPR_CONSENT = {
+ consentString: 'gdprConsentString',
+ gdprApplies: true
+ };
+ const USP_CONSENT = {
+ consentString: 'uspConsentString'
+ }
+
+ let syncParamUrl = `dm=${encodeURIComponent(location.origin || `https://${location.host}`)}`;
+ syncParamUrl += '&gdpr=1&gdpr_consent=gdprConsentString&ccpa_consent=uspConsentString';
+ const expectedIframeSyncs = [
+ {
+ type: 'iframe',
+ url: `${COOKY_SYNC_IFRAME_URL}?${syncParamUrl}`
+ }
+ ];
+
+ it('should return nothing if iframe is disabled', () => {
+ const userSyncs = spec.getUserSyncs(IFRAME_DISABLED, undefined, GDPR_CONSENT, USP_CONSENT, undefined);
+ expect(userSyncs).to.be.undefined;
+ });
+
+ it('should do userSyncs if iframe is enabled', () => {
+ const userSyncs = spec.getUserSyncs(IFRAME_ENABLED, undefined, GDPR_CONSENT, USP_CONSENT, undefined);
+ expect(userSyncs).to.deep.equal(expectedIframeSyncs);
+ });
+ });
+});
+
+describe('discovery Bid Adapter Tests', function () {
+ describe('buildRequests', () => {
+ describe('getPageTitle function', function() {
+ let sandbox;
+
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should return the top document title if available', function() {
+ const fakeTopDocument = {
+ title: 'Top Document Title',
+ querySelector: () => ({ content: 'Top Document Title test' })
+ };
+ const fakeTopWindow = {
+ document: fakeTopDocument
+ };
+ const result = getPageTitle({ top: fakeTopWindow });
+ expect(result).to.equal('Top Document Title');
+ });
+
+ it('should return the content of top og:title meta tag if title is empty', function() {
+ const ogTitleContent = 'Top OG Title Content';
+ const fakeTopWindow = {
+ document: {
+ title: '',
+ querySelector: sandbox.stub().withArgs('meta[property="og:title"]').returns({ content: ogTitleContent })
+ }
+ };
+
+ const result = getPageTitle({ top: fakeTopWindow });
+ expect(result).to.equal(ogTitleContent);
+ });
+
+ it('should return the document title if no og:title meta tag is present', function() {
+ document.title = 'Test Page Title';
+ sandbox.stub(document, 'querySelector').withArgs('meta[property="og:title"]').returns(null);
+
+ const result = getPageTitle({ top: undefined });
+ expect(result).to.equal('Test Page Title');
+ });
+
+ it('should return the content of og:title meta tag if present', function() {
+ document.title = '';
+ const ogTitleContent = 'Top OG Title Content';
+ sandbox.stub(document, 'querySelector').withArgs('meta[property="og:title"]').returns({ content: ogTitleContent });
+ const result = getPageTitle({ top: undefined });
+ expect(result).to.equal(ogTitleContent);
+ });
+
+ it('should return an empty string if no title or og:title meta tag is found', function() {
+ document.title = '';
+ sandbox.stub(document, 'querySelector').withArgs('meta[property="og:title"]').returns(null);
+ const result = getPageTitle({ top: undefined });
+ expect(result).to.equal('');
+ });
+
+ it('should handle exceptions when accessing top.document and fallback to current document', function() {
+ const fakeWindow = {
+ get top() {
+ throw new Error('Access denied');
+ }
+ };
+ const ogTitleContent = 'Current OG Title Content';
+ document.title = 'Current Document Title';
+ sandbox.stub(document, 'querySelector').withArgs('meta[property="og:title"]').returns({ content: ogTitleContent });
+ const result = getPageTitle(fakeWindow);
+ expect(result).to.equal('Current Document Title');
+ });
+ });
+
+ describe('getPageDescription function', function() {
+ let sandbox;
+
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should return the top document description if available', function() {
+ const descriptionContent = 'Top Document Description';
+ const fakeTopDocument = {
+ querySelector: sandbox.stub().withArgs('meta[name="description"]').returns({ content: descriptionContent })
+ };
+ const fakeTopWindow = { document: fakeTopDocument };
+ const result = getPageDescription({ top: fakeTopWindow });
+ expect(result).to.equal(descriptionContent);
+ });
+
+ it('should return the top document og:description if description is not present', function() {
+ const ogDescriptionContent = 'Top OG Description';
+ const fakeTopDocument = {
+ querySelector: sandbox.stub().withArgs('meta[property="og:description"]').returns({ content: ogDescriptionContent })
+ };
+ const fakeTopWindow = { document: fakeTopDocument };
+ const result = getPageDescription({ top: fakeTopWindow });
+ expect(result).to.equal(ogDescriptionContent);
+ });
+
+ it('should return the current document description if top document is not accessible', function() {
+ const descriptionContent = 'Current Document Description';
+ sandbox.stub(document, 'querySelector')
+ .withArgs('meta[name="description"]').returns({ content: descriptionContent })
+ const fakeWindow = {
+ get top() {
+ throw new Error('Access denied');
+ }
+ };
+ const result = getPageDescription(fakeWindow);
+ expect(result).to.equal(descriptionContent);
+ });
+
+ it('should return the current document og:description if description is not present and top document is not accessible', function() {
+ const ogDescriptionContent = 'Current OG Description';
+ sandbox.stub(document, 'querySelector')
+ .withArgs('meta[property="og:description"]').returns({ content: ogDescriptionContent });
+
+ const fakeWindow = {
+ get top() {
+ throw new Error('Access denied');
+ }
+ };
+ const result = getPageDescription(fakeWindow);
+ expect(result).to.equal(ogDescriptionContent);
+ });
+ });
+
+ describe('getPageKeywords function', function() {
+ let sandbox;
+
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should return the top document keywords if available', function() {
+ const keywordsContent = 'keyword1, keyword2, keyword3';
+ const fakeTopDocument = {
+ querySelector: sandbox.stub()
+ .withArgs('meta[name="keywords"]').returns({ content: keywordsContent })
+ };
+ const fakeTopWindow = { document: fakeTopDocument };
+
+ const result = getPageKeywords({ top: fakeTopWindow });
+ expect(result).to.equal(keywordsContent);
+ });
+
+ it('should return the current document keywords if top document is not accessible', function() {
+ const keywordsContent = 'keyword1, keyword2, keyword3';
+ sandbox.stub(document, 'querySelector')
+ .withArgs('meta[name="keywords"]').returns({ content: keywordsContent });
+
+ // æ¨ĄæéĄļåąįĒåŖčŽŋéŽåŧ常
+ const fakeWindow = {
+ get top() {
+ throw new Error('Access denied');
+ }
+ };
+
+ const result = getPageKeywords(fakeWindow);
+ expect(result).to.equal(keywordsContent);
+ });
+
+ it('should return an empty string if no keywords meta tag is found', function() {
+ sandbox.stub(document, 'querySelector').withArgs('meta[name="keywords"]').returns(null);
+
+ const result = getPageKeywords();
+ expect(result).to.equal('');
+ });
+ });
+ describe('getConnectionDownLink function', function() {
+ let sandbox;
+
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should return the downlink value as a string if available', function() {
+ const downlinkValue = 2.5;
+ const fakeNavigator = {
+ connection: {
+ downlink: downlinkValue
+ }
+ };
+
+ const result = getConnectionDownLink({ navigator: fakeNavigator });
+ expect(result).to.equal(downlinkValue.toString());
+ });
+
+ it('should return undefined if downlink is not available', function() {
+ const fakeNavigator = {
+ connection: {}
+ };
+
+ const result = getConnectionDownLink({ navigator: fakeNavigator });
+ expect(result).to.be.undefined;
+ });
+
+ it('should return undefined if connection is not available', function() {
+ const fakeNavigator = {};
+
+ const result = getConnectionDownLink({ navigator: fakeNavigator });
+ expect(result).to.be.undefined;
+ });
+
+ it('should handle cases where navigator is not defined', function() {
+ const result = getConnectionDownLink({});
+ expect(result).to.be.undefined;
+ });
+ });
+
+ describe('getUserSyncs with message event listener', function() {
+ function messageHandler(event) {
+ if (!event.data || event.origin !== THIRD_PARTY_COOKIE_ORIGIN) {
+ return;
+ }
+
+ window.removeEventListener('message', messageHandler, true);
+ event.stopImmediatePropagation();
+
+ const response = event.data;
+ if (!response.optout && response.mguid) {
+ storage.setCookie(COOKIE_KEY_MGUID, response.mguid, getCurrentTimeToUTCString());
+ }
+ }
+
+ let sandbox;
+
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+ sandbox.stub(storage, 'setCookie');
+ sandbox.stub(window, 'removeEventListener');
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should set a cookie when a valid message is received', () => {
+ const fakeEvent = {
+ data: { optout: '', mguid: '12345' },
+ origin: THIRD_PARTY_COOKIE_ORIGIN,
+ stopImmediatePropagation: sinon.spy()
+ };
+
+ messageHandler(fakeEvent);
+
+ expect(fakeEvent.stopImmediatePropagation.calledOnce).to.be.true;
+ expect(window.removeEventListener.calledWith('message', messageHandler, true)).to.be.true;
+ expect(storage.setCookie.calledWith(COOKIE_KEY_MGUID, '12345', sinon.match.string)).to.be.true;
+ });
+ it('should not do anything when an invalid message is received', () => {
+ const fakeEvent = {
+ data: null,
+ origin: 'http://invalid-origin.com',
+ stopImmediatePropagation: sinon.spy()
+ };
+
+ messageHandler(fakeEvent);
+
+ expect(fakeEvent.stopImmediatePropagation.notCalled).to.be.true;
+ expect(window.removeEventListener.notCalled).to.be.true;
+ expect(storage.setCookie.notCalled).to.be.true;
+ });
+ });
+ });
});
diff --git a/test/spec/modules/docereeAdManagerBidAdapter_spec.js b/test/spec/modules/docereeAdManagerBidAdapter_spec.js
new file mode 100644
index 00000000000..26b054f4e29
--- /dev/null
+++ b/test/spec/modules/docereeAdManagerBidAdapter_spec.js
@@ -0,0 +1,125 @@
+import { expect } from 'chai';
+import { spec } from '../../../modules/docereeAdManagerBidAdapter.js';
+import { config } from '../../../src/config.js';
+
+describe('docereeadmanager', function () {
+ config.setConfig({
+ docereeadmanager: {
+ user: {
+ data: {
+ email: '',
+ firstname: '',
+ lastname: '',
+ mobile: '',
+ specialization: '',
+ organization: '',
+ hcpid: '',
+ dob: '',
+ gender: '',
+ city: '',
+ state: '',
+ country: '',
+ hashedhcpid: '',
+ hashedemail: '',
+ hashedmobile: '',
+ userid: '',
+ zipcode: '',
+ userconsent: '',
+ },
+ },
+ },
+ });
+ let bid = {
+ bidId: 'testing',
+ bidder: 'docereeadmanager',
+ params: {
+ placementId: 'DOC-19-1',
+ gdpr: '1',
+ gdprconsent:
+ 'CPQfU1jPQfU1jG0AAAENAwCAAAAAAAAAAAAAAAAAAAAA.IGLtV_T9fb2vj-_Z99_tkeYwf95y3p-wzhheMs-8NyZeH_B4Wv2MyvBX4JiQKGRgksjLBAQdtHGlcTQgBwIlViTLMYk2MjzNKJrJEilsbO2dYGD9Pn8HT3ZCY70-vv__7v3ff_3g',
+ },
+ };
+
+ describe('isBidRequestValid', function () {
+ it('Should return true if placementId is present', function () {
+ expect(spec.isBidRequestValid(bid)).to.be.true;
+ });
+ it('Should return false if placementId is not present', function () {
+ delete bid.params.placementId;
+ expect(spec.isBidRequestValid(bid)).to.be.false;
+ });
+ });
+
+ describe('isGdprConsentPresent', function () {
+ it('Should return true if gdpr consent is present', function () {
+ expect(spec.isGdprConsentPresent(bid)).to.be.true;
+ });
+ });
+
+ describe('buildRequests', function () {
+ let serverRequest = spec.buildRequests([bid]);
+ serverRequest = serverRequest[0];
+ it('Creates a ServerRequest object with method, URL and data', function () {
+ expect(serverRequest).to.exist;
+ expect(serverRequest.method).to.exist;
+ expect(serverRequest.url).to.exist;
+ expect(serverRequest.data).to.exist;
+ });
+ it('Returns POST method', function () {
+ expect(serverRequest.method).to.equal('POST');
+ });
+ it('Returns valid URL', function () {
+ expect(serverRequest.url).to.equal('https://dai.doceree.com/drs/quest');
+ });
+ });
+ describe('interpretResponse', function () {
+ it('Should interpret banner response', function () {
+ const banner = {
+ body: {
+ cpm: 3.576,
+ currency: 'USD',
+ width: 250,
+ height: 300,
+ ad: '
I am an ad ',
+ ttl: 30,
+ creativeId: 'div-1',
+ netRevenue: false,
+ bidderCode: '123',
+ dealId: 232,
+ requestId: '123',
+ meta: {
+ brandId: null,
+ advertiserDomains: ['https://dai.doceree.com/drs/quest'],
+ },
+ },
+ };
+ let bannerResponses = spec.interpretResponse(banner);
+ expect(bannerResponses).to.be.an('array').that.is.not.empty;
+ let dataItem = bannerResponses[0];
+ expect(dataItem).to.have.all.keys(
+ 'requestId',
+ 'cpm',
+ 'width',
+ 'height',
+ 'ad',
+ 'ttl',
+ 'netRevenue',
+ 'currency',
+ 'mediaType',
+ 'creativeId',
+ 'meta'
+ );
+ expect(dataItem.requestId).to.equal('123');
+ expect(dataItem.cpm).to.equal(3.576);
+ expect(dataItem.width).to.equal(250);
+ expect(dataItem.height).to.equal(300);
+ expect(dataItem.ad).to.equal('
I am an ad ');
+ expect(dataItem.ttl).to.equal(30);
+ expect(dataItem.netRevenue).to.be.true;
+ expect(dataItem.currency).to.equal('USD');
+ expect(dataItem.creativeId).to.equal('div-1');
+ expect(dataItem.meta.advertiserDomains).to.be.an('array').that.is.not
+ .empty;
+ });
+ });
+});
diff --git a/test/spec/modules/docereeBidAdapter_spec.js b/test/spec/modules/docereeBidAdapter_spec.js
index dadbb56b0c0..25da8b256fc 100644
--- a/test/spec/modules/docereeBidAdapter_spec.js
+++ b/test/spec/modules/docereeBidAdapter_spec.js
@@ -1,6 +1,7 @@
import {expect} from 'chai';
import {spec} from '../../../modules/docereeBidAdapter.js';
import { config } from '../../../src/config.js';
+import * as utils from 'src/utils.js';
describe('BidlabBidAdapter', function () {
config.setConfig({
@@ -102,4 +103,36 @@ describe('BidlabBidAdapter', function () {
expect(dataItem.meta.advertiserDomains[0]).to.equal('doceree.com')
});
})
+ describe('onBidWon', function () {
+ beforeEach(function() {
+ sinon.stub(utils, 'triggerPixel');
+ });
+ afterEach(function() {
+ utils.triggerPixel.restore();
+ });
+ it('exists and is a function', () => {
+ expect(spec.onBidWon).to.exist.and.to.be.a('function');
+ });
+ it('should return nothing', function () {
+ var response = spec.onBidWon({});
+ expect(response).to.be.an('undefined')
+ expect(utils.triggerPixel.called).to.equal(true);
+ });
+ });
+ describe('onTimeout', function () {
+ beforeEach(function() {
+ sinon.stub(utils, 'triggerPixel');
+ });
+ afterEach(function() {
+ utils.triggerPixel.restore();
+ });
+ it('exists and is a function', () => {
+ expect(spec.onTimeout).to.exist.and.to.be.a('function');
+ });
+ it('should return nothing', function () {
+ var response = spec.onBidWon([]);
+ expect(response).to.be.an('undefined')
+ expect(utils.triggerPixel.called).to.equal(true);
+ });
+ });
});
diff --git a/test/spec/modules/dsaControl_spec.js b/test/spec/modules/dsaControl_spec.js
new file mode 100644
index 00000000000..0d7c52b5efd
--- /dev/null
+++ b/test/spec/modules/dsaControl_spec.js
@@ -0,0 +1,113 @@
+import {addBidResponseHook, setMetaDsa, reset} from '../../../modules/dsaControl.js';
+import CONSTANTS from 'src/constants.json';
+import {auctionManager} from '../../../src/auctionManager.js';
+import {AuctionIndex} from '../../../src/auctionIndex.js';
+
+describe('DSA transparency', () => {
+ let sandbox;
+ beforeEach(() => {
+ sandbox = sinon.sandbox.create();
+ });
+ afterEach(() => {
+ sandbox.restore();
+ reset();
+ });
+
+ describe('addBidResponseHook', () => {
+ const auctionId = 'auction-id';
+ let bid, auction, fpd, next, reject;
+ beforeEach(() => {
+ next = sinon.stub();
+ reject = sinon.stub();
+ fpd = {};
+ bid = {
+ auctionId
+ }
+ auction = {
+ getAuctionId: () => auctionId,
+ getFPD: () => ({global: fpd})
+ }
+ sandbox.stub(auctionManager, 'index').get(() => new AuctionIndex(() => [auction]));
+ });
+
+ function expectRejection(reason) {
+ addBidResponseHook(next, 'adUnit', bid, reject);
+ sinon.assert.calledWith(reject, reason);
+ sinon.assert.notCalled(next);
+ }
+
+ function expectAcceptance() {
+ addBidResponseHook(next, 'adUnit', bid, reject);
+ sinon.assert.notCalled(reject);
+ sinon.assert.calledWith(next, 'adUnit', bid, reject);
+ }
+
+ [2, 3].forEach(required => {
+ describe(`when regs.ext.dsa.dsarequired is ${required} (required)`, () => {
+ beforeEach(() => {
+ fpd = {
+ regs: {ext: {dsa: {dsarequired: required}}}
+ };
+ });
+
+ it('should reject bids that have no meta.dsa', () => {
+ expectRejection(CONSTANTS.REJECTION_REASON.DSA_REQUIRED);
+ });
+
+ it('should accept bids that do', () => {
+ bid.meta = {dsa: {}};
+ expectAcceptance();
+ });
+
+ describe('and pubrender = 0 (rendering by publisher not supported)', () => {
+ beforeEach(() => {
+ fpd.regs.ext.dsa.pubrender = 0;
+ });
+
+ it('should reject bids with adrender = 0 (advertiser will not render)', () => {
+ bid.meta = {dsa: {adrender: 0}};
+ expectRejection(CONSTANTS.REJECTION_REASON.DSA_MISMATCH);
+ });
+
+ it('should accept bids with adrender = 1 (advertiser will render)', () => {
+ bid.meta = {dsa: {adrender: 1}};
+ expectAcceptance();
+ });
+ });
+ describe('and pubrender = 2 (publisher will render)', () => {
+ beforeEach(() => {
+ fpd.regs.ext.dsa.pubrender = 2;
+ });
+
+ it('should reject bids with adrender = 1 (advertiser will render)', () => {
+ bid.meta = {dsa: {adrender: 1}};
+ expectRejection(CONSTANTS.REJECTION_REASON.DSA_MISMATCH);
+ });
+
+ it('should accept bids with adrender = 0 (advertiser will not render)', () => {
+ bid.meta = {dsa: {adrender: 0}};
+ expectAcceptance();
+ })
+ })
+ });
+ });
+ [undefined, 'garbage', 0, 1].forEach(required => {
+ describe(`when regs.ext.dsa.dsarequired is ${required}`, () => {
+ beforeEach(() => {
+ if (required != null) {
+ fpd = {
+ regs: {ext: {dsa: {dsarequired: required}}}
+ }
+ }
+ });
+
+ it('should accept bids regardless of their meta.dsa', () => {
+ addBidResponseHook(next, 'adUnit', bid, reject);
+ sinon.assert.notCalled(reject);
+ sinon.assert.calledWith(next, 'adUnit', bid, reject);
+ })
+ })
+ })
+ it('should accept bids regardless of dsa when "required" any other value')
+ });
+});
diff --git a/test/spec/modules/dsp_genieeBidAdapter_spec.js b/test/spec/modules/dsp_genieeBidAdapter_spec.js
new file mode 100644
index 00000000000..94ec1011fbf
--- /dev/null
+++ b/test/spec/modules/dsp_genieeBidAdapter_spec.js
@@ -0,0 +1,173 @@
+import { expect } from 'chai';
+import { spec } from 'modules/dsp_genieeBidAdapter.js';
+import { config } from 'src/config';
+
+describe('Geniee adapter tests', () => {
+ const validBidderRequest = {
+ code: 'sample_request',
+ bids: [{
+ bidId: 'bid-id',
+ bidder: 'dsp_geniee',
+ params: {
+ test: 1
+ }
+ }],
+ gdprConsent: {
+ gdprApplies: false
+ },
+ uspConsent: '1YNY'
+ };
+
+ describe('isBidRequestValid function test', () => {
+ it('valid', () => {
+ expect(spec.isBidRequestValid(validBidderRequest.bids[0])).equal(true);
+ });
+ });
+ describe('buildRequests function test', () => {
+ it('auction', () => {
+ const request = spec.buildRequests(validBidderRequest.bids, validBidderRequest);
+ const auction_id = request.data.id;
+ expect(request).deep.equal({
+ method: 'POST',
+ url: 'https://rt.gsspat.jp/prebid_auction',
+ data: {
+ at: 1,
+ id: auction_id,
+ imp: [
+ {
+ ext: {
+ test: 1
+ },
+ id: 'bid-id'
+ }
+ ],
+ test: 1
+ },
+ });
+ });
+ it('uncomfortable (gdpr)', () => {
+ validBidderRequest.gdprConsent.gdprApplies = true;
+ const request = spec.buildRequests(validBidderRequest.bids, validBidderRequest);
+ expect(request).deep.equal({
+ method: 'GET',
+ url: 'https://rt.gsspat.jp/prebid_uncomfortable',
+ });
+ validBidderRequest.gdprConsent.gdprApplies = false;
+ });
+ it('uncomfortable (usp)', () => {
+ validBidderRequest.uspConsent = '1YYY';
+ const request = spec.buildRequests(validBidderRequest.bids, validBidderRequest);
+ expect(request).deep.equal({
+ method: 'GET',
+ url: 'https://rt.gsspat.jp/prebid_uncomfortable',
+ });
+ validBidderRequest.uspConsent = '1YNY';
+ });
+ it('uncomfortable (coppa)', () => {
+ config.setConfig({ coppa: true });
+ const request = spec.buildRequests(validBidderRequest.bids, validBidderRequest);
+ expect(request).deep.equal({
+ method: 'GET',
+ url: 'https://rt.gsspat.jp/prebid_uncomfortable',
+ });
+ config.resetConfig();
+ });
+ it('uncomfortable (currency)', () => {
+ config.setConfig({ currency: { adServerCurrency: 'TWD' } });
+ const request = spec.buildRequests(validBidderRequest.bids, validBidderRequest);
+ expect(request).deep.equal({
+ method: 'GET',
+ url: 'https://rt.gsspat.jp/prebid_uncomfortable',
+ });
+ config.resetConfig();
+ });
+ });
+ describe('interpretResponse function test', () => {
+ it('sample bid', () => {
+ const request = spec.buildRequests(validBidderRequest.bids, validBidderRequest);
+ const auction_id = request.data.id;
+ const adm = "\n";
+ const serverResponse = {
+ body: {
+ id: auction_id,
+ cur: 'JPY',
+ seatbid: [{
+ bid: [{
+ id: '7b77235d599e06d289e58ddfa9390443e22d7071',
+ impid: 'bid-id',
+ price: 0.6666000000000001,
+ adid: '8405715',
+ adm: adm,
+ adomain: ['geniee.co.jp'],
+ iurl: 'http://img.gsspat.jp/e/068c8e1eafbf0cb6ac1ee95c36152bd2/04f4bd4e6b71f978d343d84ecede3877.png',
+ cid: '8405715',
+ crid: '1383823',
+ cat: ['IAB1'],
+ w: 300,
+ h: 250,
+ mtype: 1
+ }]
+ }]
+ }
+ };
+ const bids = spec.interpretResponse(serverResponse, request);
+ expect(bids).deep.equal([{
+ ad: adm,
+ cpm: 0.6666000000000001,
+ creativeId: '1383823',
+ creative_id: '1383823',
+ height: 250,
+ width: 300,
+ currency: 'JPY',
+ mediaType: 'banner',
+ meta: {
+ advertiserDomains: ['geniee.co.jp']
+ },
+ netRevenue: true,
+ requestId: 'bid-id',
+ seatBidId: '7b77235d599e06d289e58ddfa9390443e22d7071',
+ ttl: 300
+ }]);
+ });
+ it('no bid', () => {
+ const serverResponse = {};
+ const bids = spec.interpretResponse(serverResponse, validBidderRequest);
+ expect(bids).deep.equal([]);
+ });
+ });
+ describe('getUserSyncs function test', () => {
+ it('sync enabled', () => {
+ const syncOptions = {
+ iframeEnabled: true,
+ pixelEnabled: true
+ };
+ const serverResponses = [];
+ const syncs = spec.getUserSyncs(syncOptions, serverResponses);
+ expect(syncs).deep.equal([{
+ type: 'image',
+ url: 'https://rt.gsspat.jp/prebid_cs'
+ }]);
+ });
+ it('sync disabled (option false)', () => {
+ const syncOptions = {
+ iframeEnabled: false,
+ pixelEnabled: false
+ };
+ const serverResponses = [];
+ const syncs = spec.getUserSyncs(syncOptions, serverResponses);
+ expect(syncs).deep.equal([]);
+ });
+ it('sync disabled (gdpr)', () => {
+ const syncOptions = {
+ iframeEnabled: true,
+ pixelEnabled: true
+ };
+ const serverResponses = [];
+ const gdprConsent = {
+ gdprApplies: true
+ };
+ const syncs = spec.getUserSyncs(syncOptions, serverResponses, gdprConsent);
+ expect(syncs).deep.equal([]);
+ });
+ });
+});
diff --git a/test/spec/modules/dxkultureBidAdapter_spec.js b/test/spec/modules/dxkultureBidAdapter_spec.js
index ec7f6f146a3..a752c81cb6e 100644
--- a/test/spec/modules/dxkultureBidAdapter_spec.js
+++ b/test/spec/modules/dxkultureBidAdapter_spec.js
@@ -1,137 +1,198 @@
import {expect} from 'chai';
-import {spec} from 'modules/dxkultureBidAdapter.js';
-
-const BANNER_REQUEST = {
- 'bidderCode': 'dxkulture',
- 'auctionId': 'auctionId-56a2-4f71-9098-720a68f2f708',
- 'bidderRequestId': 'requestId',
- 'bidRequest': [{
- 'bidder': 'dxkulture',
- 'params': {
- 'placementId': 123456,
- },
- 'placementCode': 'div-gpt-dummy-placement-code',
- 'mediaTypes': {'banner': {'sizes': [[300, 250]]}},
- 'bidId': 'bidId1',
- 'bidderRequestId': 'bidderRequestId',
- 'auctionId': 'auctionId-56a2-4f71-9098-720a68f2f708'
- },
- {
- 'bidder': 'dxkulture',
- 'params': {
- 'placementId': 123456,
- },
- 'placementCode': 'div-gpt-dummy-placement-code',
- 'mediaTypes': {'banner': {'sizes': [[300, 250]]}},
- 'bidId': 'bidId2',
- 'bidderRequestId': 'bidderRequestId',
- 'auctionId': 'auctionId-56a2-4f71-9098-720a68f2f708'
- }],
- 'start': 1487883186070,
- 'auctionStart': 1487883186069,
- 'timeout': 3000
+import {spec, SYNC_URL} from 'modules/dxkultureBidAdapter.js';
+import {BANNER, VIDEO} from 'src/mediaTypes.js';
+
+const getBannerRequest = () => {
+ return {
+ bidderCode: 'dxkulture',
+ auctionId: 'ba87bfdf-493e-4a88-8e26-17b4cbc9adbd',
+ bidderRequestId: 'bidderRequestId',
+ bids: [
+ {
+ bidder: 'dxkulture',
+ params: {
+ placementId: 123456,
+ publisherId: 'publisherId',
+ bidfloor: 10,
+ },
+ auctionId: 'auctionId-56a2-4f71-9098-720a68f2f708',
+ placementCode: 'div-gpt-dummy-placement-code',
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [ 300, 250 ],
+ ]
+ }
+ },
+ bidId: '2e9f38ea93bb9e',
+ bidderRequestId: 'bidderRequestId',
+ }
+ ],
+ start: 1487883186070,
+ auctionStart: 1487883186069,
+ timeout: 3000
+ }
};
-const RESPONSE = {
- 'headers': null,
- 'body': {
- 'id': 'responseId',
- 'seatbid': [
- {
- 'bid': [
- {
- 'id': 'bidId1',
- 'impid': 'bidId1',
- 'price': 0.18,
- 'adm': '',
- 'adid': '144762342',
- 'adomain': [
- 'https://dummydomain.com'
- ],
- 'iurl': 'iurl',
- 'cid': '109',
- 'crid': 'creativeId',
- 'cat': [],
- 'w': 300,
- 'h': 250,
- 'ext': {
- 'prebid': {
- 'type': 'banner'
- },
- 'bidder': {
- 'appnexus': {
- 'brand_id': 334553,
- 'auction_id': 514667951122925701,
- 'bidder_id': 2,
- 'bid_ad_type': 0
+const getVideoRequest = () => {
+ return {
+ bidderCode: 'dxkulture',
+ auctionId: 'e158486f-8c7f-472f-94ce-b0cbfbb50ab4',
+ bidderRequestId: '34feaad34lkj2',
+ bids: [{
+ mediaTypes: {
+ video: {
+ context: 'instream',
+ playerSize: [[640, 480]],
+ }
+ },
+ bidder: 'dxkulture',
+ sizes: [640, 480],
+ bidId: '30b3efwfwe1e',
+ adUnitCode: 'video1',
+ params: {
+ video: {
+ playerWidth: 640,
+ playerHeight: 480,
+ mimes: ['video/mp4', 'application/javascript'],
+ protocols: [2, 5],
+ api: [2],
+ position: 1,
+ delivery: [2],
+ sid: 134,
+ rewarded: 1,
+ placement: 1,
+ plcmt: 1,
+ hp: 1,
+ inventoryid: 123
+ },
+ site: {
+ id: 1,
+ page: 'https://test.com',
+ referrer: 'http://test.com'
+ },
+ publisherId: 'km123',
+ bidfloor: 10,
+ }
+ }, {
+ mediaTypes: {
+ video: {
+ context: 'instream',
+ playerSize: [[640, 480]],
+ }
+ },
+ bidder: 'dxkulture',
+ sizes: [640, 480],
+ bidId: '30b3efwfwe2e',
+ adUnitCode: 'video1',
+ params: {
+ video: {
+ playerWidth: 640,
+ playerHeight: 480,
+ mimes: ['video/mp4', 'application/javascript'],
+ protocols: [2, 5],
+ api: [2],
+ position: 1,
+ delivery: [2],
+ sid: 134,
+ rewarded: 1,
+ placement: 1,
+ plcmt: 1,
+ hp: 1,
+ inventoryid: 123
+ },
+ site: {
+ id: 1,
+ page: 'https://test.com',
+ referrer: 'http://test.com'
+ },
+ publisherId: 'km123',
+ bidfloor: 10,
+ }
+ }],
+ auctionStart: 1520001292880,
+ timeout: 5000,
+ start: 1520001292884,
+ doneCbCallCount: 0,
+ refererInfo: {
+ numIframes: 1,
+ reachedTop: true,
+ referer: 'test.com'
+ }
+ };
+};
+
+const getBidderResponse = () => {
+ return {
+ headers: null,
+ body: {
+ id: 'bid-response',
+ seatbid: [
+ {
+ bid: [
+ {
+ id: '2e9f38ea93bb9e',
+ impid: '2e9f38ea93bb9e',
+ price: 0.18,
+ adm: '',
+ adid: '144762342',
+ adomain: [
+ 'https://dummydomain.com'
+ ],
+ iurl: 'iurl',
+ cid: '109',
+ crid: 'creativeId',
+ cat: [],
+ w: 300,
+ h: 250,
+ ext: {
+ prebid: {
+ type: 'banner'
+ },
+ bidder: {
+ appnexus: {
+ brand_id: 334553,
+ auction_id: 514667951122925701,
+ bidder_id: 2,
+ bid_ad_type: 0
+ }
}
}
}
+ ],
+ seat: 'dxkulture'
+ }
+ ],
+ ext: {
+ usersync: {
+ sovrn: {
+ status: 'none',
+ syncs: [
+ {
+ url: 'urlsovrn',
+ type: 'iframe'
+ }
+ ]
},
- {
- 'id': 'bidId2',
- 'impid': 'bidId2',
- 'price': 0.1,
- 'adm': '',
- 'adid': '144762342',
- 'adomain': [
- 'https://dummydomain.com'
- ],
- 'iurl': 'iurl',
- 'cid': '109',
- 'crid': 'creativeId',
- 'cat': [],
- 'w': 300,
- 'h': 250,
- 'ext': {
- 'prebid': {
- 'type': 'banner'
- },
- 'bidder': {
- 'appnexus': {
- 'brand_id': 386046,
- 'auction_id': 517067951122925501,
- 'bidder_id': 2,
- 'bid_ad_type': 0
- }
+ appnexus: {
+ status: 'none',
+ syncs: [
+ {
+ url: 'urlappnexus',
+ type: 'pixel'
}
- }
+ ]
}
- ],
- 'seat': 'dxkulture'
- }
- ],
- 'ext': {
- 'usersync': {
- 'sovrn': {
- 'status': 'none',
- 'syncs': [
- {
- 'url': 'urlsovrn',
- 'type': 'iframe'
- }
- ]
},
- 'appnexus': {
- 'status': 'none',
- 'syncs': [
- {
- 'url': 'urlappnexus',
- 'type': 'pixel'
- }
- ]
+ responsetimemillis: {
+ appnexus: 127
}
- },
- 'responsetimemillis': {
- 'appnexus': 127
}
}
- }
-};
-
-const DEFAULT_NETWORK_ID = 1;
+ };
+}
-describe('dxkultureBidAdapter:', function () {
+describe('dxkultureBidAdapter', function() {
let videoBidRequest;
const VIDEO_REQUEST = {
@@ -183,51 +244,86 @@ describe('dxkultureBidAdapter:', function () {
page: 'https://test.com',
referrer: 'http://test.com'
},
- publisherId: 'km123'
+ publisherId: 'km123',
+ bidfloor: 0
}
};
});
- describe('isBidRequestValid', function () {
- context('basic validation', function () {
- beforeEach(function () {
- // Basic Valid BidRequest
- this.bid = {
- bidder: 'dxkulture',
- mediaTypes: {
- banner: {
- sizes: [[250, 300]]
- }
- },
- params: {
- placementId: 'placementId',
- publisherId: 'publisherId',
- }
- };
- });
+ describe('isValidRequest', function() {
+ let bidderRequest;
- it('should accept request if placementId and publisherId are passed', function () {
- expect(spec.isBidRequestValid(this.bid)).to.be.true;
- });
+ beforeEach(function() {
+ bidderRequest = getBannerRequest();
+ });
- it('reject requests without params', function () {
- this.bid.params = {};
- expect(spec.isBidRequestValid(this.bid)).to.be.false;
- });
+ it('should accept request if placementId and publisherId are passed', function () {
+ expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.be.true;
+ });
- it('returns false when banner mediaType does not exist', function () {
- this.bid.mediaTypes = {}
- expect(spec.isBidRequestValid(this.bid)).to.be.false;
- });
+ it('reject requests without params', function () {
+ bidderRequest.bids[0].params = {};
+ expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.be.false;
});
- context('banner validation', function () {
- it('returns true when banner sizes are defined', function () {
+ it('returns false when banner mediaType does not exist', function () {
+ bidderRequest.bids[0].mediaTypes = {}
+ expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.be.false;
+ });
+ });
+
+ describe('buildRequests', function() {
+ let bidderRequest;
+
+ beforeEach(function() {
+ bidderRequest = getBannerRequest();
+ });
+
+ it('should return expected request object', function() {
+ const bidRequest = spec.buildRequests(bidderRequest.bids, bidderRequest);
+ expect(bidRequest.url).equal('https://ads.dxkulture.com/pbjs?pid=publisherId&placementId=123456');
+ expect(bidRequest.method).equal('POST');
+ });
+ });
+
+ context('banner validation', function () {
+ let bidderRequest;
+
+ beforeEach(function() {
+ bidderRequest = getBannerRequest();
+ });
+
+ it('returns true when banner sizes are defined', function () {
+ const bid = {
+ bidder: 'dxkulture',
+ mediaTypes: {
+ banner: {
+ sizes: [[250, 300]]
+ }
+ },
+ params: {
+ placementId: 'placementId',
+ publisherId: 'publisherId',
+ }
+ };
+
+ expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.be.true;
+ });
+
+ it('returns false when banner sizes are invalid', function () {
+ const invalidSizes = [
+ undefined,
+ '2:1',
+ 123,
+ 'test'
+ ];
+
+ invalidSizes.forEach((sizes) => {
const bid = {
bidder: 'dxkulture',
mediaTypes: {
banner: {
- sizes: [[250, 300]]
+ sizes
}
},
params: {
@@ -236,350 +332,288 @@ describe('dxkultureBidAdapter:', function () {
}
};
- expect(spec.isBidRequestValid(bid)).to.be.true;
+ expect(spec.isBidRequestValid(bid)).to.be.false;
});
+ });
+ });
- it('returns false when banner sizes are invalid', function () {
- const invalidSizes = [
- undefined,
- '2:1',
- 123,
- 'test'
- ];
-
- invalidSizes.forEach((sizes) => {
- const bid = {
- bidder: 'dxkulture',
- mediaTypes: {
- banner: {
- sizes
- }
- },
- params: {
- placementId: 'placementId',
- publisherId: 'publisherId',
- }
- };
+ context('video validation', function () {
+ beforeEach(function () {
+ // Basic Valid BidRequest
+ this.bid = {
+ bidder: 'dxkulture',
+ mediaTypes: {
+ video: {
+ playerSize: [[300, 50]],
+ context: 'instream',
+ mimes: ['foo', 'bar'],
+ protocols: [1, 2]
+ }
+ },
+ params: {
+ placementId: 'placementId',
+ publisherId: 'publisherId',
+ }
+ };
+ });
- expect(spec.isBidRequestValid(bid)).to.be.false;
- });
- });
+ it('should return true (skip validations) when e2etest = true', function () {
+ this.bid.params = {
+ e2etest: true
+ };
+ expect(spec.isBidRequestValid(this.bid)).to.equal(true);
});
- context('video validation', function () {
- beforeEach(function () {
- // Basic Valid BidRequest
- this.bid = {
- bidder: 'dxkulture',
- mediaTypes: {
- video: {
- playerSize: [[300, 50]],
- context: 'instream',
- mimes: ['foo', 'bar'],
- protocols: [1, 2]
- }
- },
- params: {
- placementId: 'placementId',
- publisherId: 'publisherId',
- }
- };
- });
+ it('returns false when video context is not defined', function () {
+ delete this.bid.mediaTypes.video.context;
- it('should return true (skip validations) when e2etest = true', function () {
- this.bid.params = {
- e2etest: true
- };
- expect(spec.isBidRequestValid(this.bid)).to.equal(true);
- });
+ expect(spec.isBidRequestValid(this.bid)).to.be.false;
+ });
- it('returns false when video context is not defined', function () {
- delete this.bid.mediaTypes.video.context;
+ it('returns false when video playserSize is invalid', function () {
+ const invalidSizes = [
+ undefined,
+ '2:1',
+ 123,
+ 'test'
+ ];
+ invalidSizes.forEach((playerSize) => {
+ this.bid.mediaTypes.video.playerSize = playerSize;
expect(spec.isBidRequestValid(this.bid)).to.be.false;
});
+ });
- it('returns false when video playserSize is invalid', function () {
- const invalidSizes = [
- undefined,
- '2:1',
- 123,
- 'test'
- ];
-
- invalidSizes.forEach((playerSize) => {
- this.bid.mediaTypes.video.playerSize = playerSize;
- expect(spec.isBidRequestValid(this.bid)).to.be.false;
- });
- });
+ it('returns false when video mimes is invalid', function () {
+ const invalidMimes = [
+ undefined,
+ 'test',
+ 1,
+ []
+ ]
- it('returns false when video mimes is invalid', function () {
- const invalidMimes = [
- undefined,
- 'test',
- 1,
- []
- ]
-
- invalidMimes.forEach((mimes) => {
- this.bid.mediaTypes.video.mimes = mimes;
- expect(spec.isBidRequestValid(this.bid)).to.be.false;
- })
- });
+ invalidMimes.forEach((mimes) => {
+ this.bid.mediaTypes.video.mimes = mimes;
+ expect(spec.isBidRequestValid(this.bid)).to.be.false;
+ })
+ });
- it('returns false when video protocols is invalid', function () {
- const invalidMimes = [
- undefined,
- 'test',
- 1,
- []
- ]
-
- invalidMimes.forEach((protocols) => {
- this.bid.mediaTypes.video.protocols = protocols;
- expect(spec.isBidRequestValid(this.bid)).to.be.false;
- })
- });
+ it('returns false when video protocols is invalid', function () {
+ const invalidMimes = [
+ undefined,
+ 'test',
+ 1,
+ []
+ ]
+
+ invalidMimes.forEach((protocols) => {
+ this.bid.mediaTypes.video.protocols = protocols;
+ expect(spec.isBidRequestValid(this.bid)).to.be.false;
+ })
});
});
describe('buildRequests', function () {
+ let bidderBannerRequest;
+ let bidRequestsWithMediaTypes;
+ let mockBidderRequest;
+
+ beforeEach(function() {
+ bidderBannerRequest = getBannerRequest();
+
+ mockBidderRequest = {refererInfo: {}};
+
+ bidRequestsWithMediaTypes = [{
+ bidder: 'dxkulture',
+ params: {
+ publisherId: 'km123',
+ },
+ 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',
+ transactionId: 'test-transactionId-1',
+ ortb2Imp: {
+ ext: {
+ ae: 2
+ }
+ }
+ }, {
+ bidder: 'dxkulture',
+ params: {
+ publisherId: 'km123',
+ },
+ adUnitCode: 'adunit-code',
+ mediaTypes: {
+ video: {
+ playerSize: [640, 480],
+ placement: 1,
+ plcmt: 1,
+ }
+ },
+ bidId: 'test-bid-id-2',
+ bidderRequestId: 'test-bid-request-2',
+ auctionId: 'test-auction-2',
+ transactionId: 'test-transactionId-2'
+ }];
+ });
+
context('when mediaType is banner', function () {
it('creates request data', function () {
- let request = spec.buildRequests(BANNER_REQUEST.bidRequest, BANNER_REQUEST);
+ let request = spec.buildRequests(bidderBannerRequest.bids, bidderBannerRequest)
expect(request).to.exist.and.to.be.a('object');
- const payload = JSON.parse(request.data);
- expect(payload.imp[0]).to.have.property('id', BANNER_REQUEST.bidRequest[0].bidId);
- expect(payload.imp[1]).to.have.property('id', BANNER_REQUEST.bidRequest[1].bidId);
+ const payload = request.data;
+ expect(payload.imp[0]).to.have.property('id', bidderBannerRequest.bids[0].bidId);
});
it('has gdpr data if applicable', function () {
- const req = Object.assign({}, BANNER_REQUEST, {
+ const req = Object.assign({}, getBannerRequest(), {
gdprConsent: {
consentString: 'consentString',
gdprApplies: true,
}
});
- let request = spec.buildRequests(BANNER_REQUEST.bidRequest, req);
+ let request = spec.buildRequests(bidderBannerRequest.bids, req);
- const payload = JSON.parse(request.data);
+ const payload = request.data;
expect(payload.user.ext).to.have.property('consent', req.gdprConsent.consentString);
expect(payload.regs.ext).to.have.property('gdpr', 1);
});
+ });
- it('should properly forward eids parameters', function () {
- const req = Object.assign({}, BANNER_REQUEST);
- req.bidRequest[0].userIdAsEids = [
- {
- source: 'dummy.com',
- uids: [
- {
- id: 'd6d0a86c-20c6-4410-a47b-5cba383a698a',
- atype: 1
- }
- ]
- }];
- let request = spec.buildRequests(req.bidRequest, req);
+ if (FEATURES.VIDEO) {
+ context('video', function () {
+ it('should create a POST request for every bid', function () {
+ const requests = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
+ expect(requests.method).to.equal('POST');
+ expect(requests.url.trim()).to.equal(spec.ENDPOINT + '?pid=' + videoBidRequest.params.publisherId);
+ });
- const payload = JSON.parse(request.data);
- expect(payload.user.ext.eids[0].source).to.equal('dummy.com');
- expect(payload.user.ext.eids[0].uids[0].id).to.equal('d6d0a86c-20c6-4410-a47b-5cba383a698a');
- expect(payload.user.ext.eids[0].uids[0].atype).to.equal(1);
- });
- });
+ it('should attach request data', function () {
+ const requests = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
+ const data = requests.data;
+ const [width, height] = videoBidRequest.sizes;
+ const VERSION = '1.0.0';
+
+ expect(data.imp[1].video.w).to.equal(width);
+ expect(data.imp[1].video.h).to.equal(height);
+ expect(data.imp[1].bidfloor).to.equal(videoBidRequest.params.bidfloor);
+ expect(data.imp[1]['video']['placement']).to.equal(videoBidRequest.params.video['placement']);
+ expect(data.imp[1]['video']['plcmt']).to.equal(videoBidRequest.params.video['plcmt']);
+ expect(data.ext.prebidver).to.equal('$prebid.version$');
+ expect(data.ext.adapterver).to.equal(spec.VERSION);
+ });
- context('when mediaType is video', function () {
- it('should create a POST request for every bid', function () {
- const requests = spec.buildRequests([videoBidRequest], VIDEO_REQUEST);
- expect(requests.method).to.equal('POST');
- expect(requests.url.trim()).to.equal(spec.ENDPOINT + '?pid=' + videoBidRequest.params.publisherId + '&nId=' + DEFAULT_NETWORK_ID);
- });
+ it('should set pubId to e2etest when bid.params.e2etest = true', function () {
+ bidRequestsWithMediaTypes[0].params.e2etest = true;
+ const requests = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
+ expect(requests.method).to.equal('POST');
+ expect(requests.url).to.equal(spec.ENDPOINT + '?pid=e2etest');
+ });
- it('should attach request data', function () {
- const requests = spec.buildRequests([videoBidRequest], VIDEO_REQUEST);
- const data = JSON.parse(requests.data);
- const [width, height] = videoBidRequest.sizes;
- const VERSION = '1.0.0';
- expect(data.imp[0].video.w).to.equal(width);
- expect(data.imp[0].video.h).to.equal(height);
- expect(data.imp[0].bidfloor).to.equal(videoBidRequest.params.bidfloor);
- expect(data.imp[0]['video']['placement']).to.equal(videoBidRequest.params.video['placement']);
- expect(data.imp[0]['video']['plcmt']).to.equal(videoBidRequest.params.video['plcmt']);
- expect(data.ext.prebidver).to.equal('$prebid.version$');
- expect(data.ext.adapterver).to.equal(spec.VERSION);
+ it('should attach End 2 End test data', function () {
+ bidRequestsWithMediaTypes[1].params.e2etest = true;
+ const requests = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
+ const data = requests.data;
+ expect(data.imp[1].bidfloor).to.equal(0);
+ expect(data.imp[1].video.w).to.equal(640);
+ expect(data.imp[1].video.h).to.equal(480);
+ });
});
+ }
+ });
- it('should set pubId to e2etest when bid.params.e2etest = true', function () {
- videoBidRequest.params.e2etest = true;
- const requests = spec.buildRequests([videoBidRequest], VIDEO_REQUEST);
- expect(requests.method).to.equal('POST');
- expect(requests.url).to.equal(spec.ENDPOINT + '?pid=e2etest&nId=' + DEFAULT_NETWORK_ID);
+ describe('interpretResponse', function() {
+ context('when mediaType is banner', function() {
+ let bidRequest, bidderResponse;
+ beforeEach(function() {
+ const bidderRequest = getBannerRequest();
+ bidRequest = spec.buildRequests(bidderRequest.bids, bidderRequest);
+ bidderResponse = getBidderResponse();
});
- it('should attach End 2 End test data', function () {
- videoBidRequest.params.e2etest = true;
- const requests = spec.buildRequests([videoBidRequest], VIDEO_REQUEST);
- const data = JSON.parse(requests.data);
- expect(data.imp[0].bidfloor).to.not.exist;
- expect(data.imp[0].video.w).to.equal(640);
- expect(data.imp[0].video.h).to.equal(480);
+ it('handles empty response', function () {
+ const EMPTY_RESP = Object.assign({}, bidderResponse, {'body': {}});
+ const bids = spec.interpretResponse(EMPTY_RESP, bidRequest);
+
+ expect(bids).to.be.empty;
});
- });
- });
- describe('interpretResponse', function () {
- context('when mediaType is banner', function () {
it('have bids', function () {
- let bids = spec.interpretResponse(RESPONSE, BANNER_REQUEST);
+ let bids = spec.interpretResponse(bidderResponse, bidRequest);
expect(bids).to.be.an('array').that.is.not.empty;
validateBidOnIndex(0);
- validateBidOnIndex(1);
function validateBidOnIndex(index) {
expect(bids[index]).to.have.property('currency', 'USD');
- expect(bids[index]).to.have.property('requestId', RESPONSE.body.seatbid[0].bid[index].impid);
- expect(bids[index]).to.have.property('cpm', RESPONSE.body.seatbid[0].bid[index].price);
- expect(bids[index]).to.have.property('width', RESPONSE.body.seatbid[0].bid[index].w);
- expect(bids[index]).to.have.property('height', RESPONSE.body.seatbid[0].bid[index].h);
- expect(bids[index]).to.have.property('ad', RESPONSE.body.seatbid[0].bid[index].adm);
- expect(bids[index]).to.have.property('creativeId', RESPONSE.body.seatbid[0].bid[index].crid);
- expect(bids[index].meta).to.have.property('advertiserDomains', RESPONSE.body.seatbid[0].bid[index].adomain);
+ expect(bids[index]).to.have.property('requestId', getBidderResponse().body.seatbid[0].bid[index].impid);
+ expect(bids[index]).to.have.property('cpm', getBidderResponse().body.seatbid[0].bid[index].price);
+ expect(bids[index]).to.have.property('width', getBidderResponse().body.seatbid[0].bid[index].w);
+ expect(bids[index]).to.have.property('height', getBidderResponse().body.seatbid[0].bid[index].h);
+ expect(bids[index]).to.have.property('ad', getBidderResponse().body.seatbid[0].bid[index].adm);
+ expect(bids[index]).to.have.property('creativeId', getBidderResponse().body.seatbid[0].bid[index].crid);
+ expect(bids[index].meta).to.have.property('advertiserDomains');
expect(bids[index]).to.have.property('ttl', 300);
expect(bids[index]).to.have.property('netRevenue', true);
}
});
+ });
+
+ context('when mediaType is video', function () {
+ let bidRequest, bidderResponse;
+ beforeEach(function() {
+ const bidderRequest = getVideoRequest();
+ bidRequest = spec.buildRequests(bidderRequest.bids, bidderRequest);
+ bidderResponse = getBidderResponse();
+ });
it('handles empty response', function () {
- const EMPTY_RESP = Object.assign({}, RESPONSE, {'body': {}});
- const bids = spec.interpretResponse(EMPTY_RESP, BANNER_REQUEST);
+ const EMPTY_RESP = Object.assign({}, bidderResponse, {'body': {}});
+ const bids = spec.interpretResponse(EMPTY_RESP, bidRequest);
expect(bids).to.be.empty;
});
- });
-
- context('when mediaType is video', function () {
- it('should return no bids if the response is not valid', function () {
- const bidResponse = spec.interpretResponse({
- body: null
- }, {
- videoBidRequest
- });
- expect(bidResponse.length).to.equal(0);
- });
it('should return no bids if the response "nurl" and "adm" are missing', function () {
- const serverResponse = {
+ const SERVER_RESP = Object.assign({}, bidderResponse, {'body': {
seatbid: [{
bid: [{
price: 6.01
}]
}]
- };
- const bidResponse = spec.interpretResponse({
- body: serverResponse
- }, {
- videoBidRequest
- });
- expect(bidResponse.length).to.equal(0);
+ }});
+ const bids = spec.interpretResponse(SERVER_RESP, bidRequest);
+ expect(bids.length).to.equal(0);
});
it('should return no bids if the response "price" is missing', function () {
- const serverResponse = {
+ const SERVER_RESP = Object.assign({}, bidderResponse, {'body': {
seatbid: [{
bid: [{
adm: '
'
}]
}]
- };
- const bidResponse = spec.interpretResponse({
- body: serverResponse
- }, {
- videoBidRequest
- });
- expect(bidResponse.length).to.equal(0);
- });
-
- it('should return a valid video bid response with just "adm"', function () {
- const serverResponse = {
- id: '123',
- seatbid: [{
- bid: [{
- id: 1,
- adid: 123,
- impid: 456,
- crid: 2,
- price: 6.01,
- adm: '
',
- adomain: [
- 'dxkulture.com'
- ],
- w: 640,
- h: 480,
- ext: {
- prebid: {
- type: 'video'
- },
- }
- }]
- }],
- cur: 'USD'
- };
- const bidResponse = spec.interpretResponse({
- body: serverResponse
- }, {
- videoBidRequest
- });
- let o = {
- requestId: serverResponse.seatbid[0].bid[0].impid,
- ad: '
',
- bidderCode: spec.code,
- cpm: serverResponse.seatbid[0].bid[0].price,
- creativeId: serverResponse.seatbid[0].bid[0].crid,
- vastXml: serverResponse.seatbid[0].bid[0].adm,
- width: 640,
- height: 480,
- mediaType: 'video',
- currency: 'USD',
- ttl: 300,
- netRevenue: true,
- meta: {
- advertiserDomains: ['dxkulture.com']
- }
- };
- expect(bidResponse[0]).to.deep.equal(o);
- });
-
- it('should default ttl to 300', function () {
- const serverResponse = {
- seatbid: [{bid: [{id: 1, adid: 123, crid: 2, price: 6.01, adm: '
'}]}],
- cur: 'USD'
- };
- const bidResponse = spec.interpretResponse({body: serverResponse}, {videoBidRequest});
- expect(bidResponse[0].ttl).to.equal(300);
- });
- it('should not allow ttl above 3601, default to 300', function () {
- videoBidRequest.params.video.ttl = 3601;
- const serverResponse = {
- seatbid: [{bid: [{id: 1, adid: 123, crid: 2, price: 6.01, adm: '
'}]}],
- cur: 'USD'
- };
- const bidResponse = spec.interpretResponse({body: serverResponse}, {videoBidRequest});
- expect(bidResponse[0].ttl).to.equal(300);
- });
- it('should not allow ttl below 1, default to 300', function () {
- videoBidRequest.params.video.ttl = 0;
- const serverResponse = {
- seatbid: [{bid: [{id: 1, adid: 123, crid: 2, price: 6.01, adm: '
'}]}],
- cur: 'USD'
- };
- const bidResponse = spec.interpretResponse({body: serverResponse}, {videoBidRequest});
- expect(bidResponse[0].ttl).to.equal(300);
+ }});
+ const bids = spec.interpretResponse(SERVER_RESP, bidRequest);
+ expect(bids.length).to.equal(0);
});
});
});
describe('getUserSyncs', function () {
+ let bidRequest, bidderResponse;
+ beforeEach(function() {
+ const bidderRequest = getVideoRequest();
+ bidRequest = spec.buildRequests(bidderRequest.bids, bidderRequest);
+ bidderResponse = getBidderResponse();
+ });
+
it('handles no parameters', function () {
let opts = spec.getUserSyncs({});
expect(opts).to.be.an('array').that.is.empty;
@@ -591,26 +625,25 @@ describe('dxkultureBidAdapter:', function () {
});
it('iframe sync enabled should return results', function () {
- let opts = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: false}, [RESPONSE]);
+ let opts = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: false}, [bidderResponse]);
expect(opts.length).to.equal(1);
expect(opts[0].type).to.equal('iframe');
- expect(opts[0].url).to.equal(RESPONSE.body.ext.usersync['sovrn'].syncs[0].url);
+ expect(opts[0].url).to.equal(bidderResponse.body.ext.usersync['sovrn'].syncs[0].url);
});
it('pixel sync enabled should return results', function () {
- let opts = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, [RESPONSE]);
+ let opts = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, [bidderResponse]);
expect(opts.length).to.equal(1);
expect(opts[0].type).to.equal('image');
- expect(opts[0].url).to.equal(RESPONSE.body.ext.usersync['appnexus'].syncs[0].url);
+ expect(opts[0].url).to.equal(bidderResponse.body.ext.usersync['appnexus'].syncs[0].url);
});
- it('all sync enabled should return all results', function () {
- let opts = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [RESPONSE]);
+ it('all sync enabled should prioritize iframe', function () {
+ let opts = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [bidderResponse]);
- expect(opts.length).to.equal(2);
+ expect(opts.length).to.equal(1);
});
});
-})
-;
+});
diff --git a/test/spec/modules/dynamicAdBoostRtdProvider_spec.js b/test/spec/modules/dynamicAdBoostRtdProvider_spec.js
new file mode 100644
index 00000000000..66c24435589
--- /dev/null
+++ b/test/spec/modules/dynamicAdBoostRtdProvider_spec.js
@@ -0,0 +1,77 @@
+import { subModuleObj as rtdProvider } from 'modules/dynamicAdBoostRtdProvider.js';
+import { loadExternalScript } from '../../../src/adloader.js';
+import { expect } from 'chai';
+
+const configWithParams = {
+ params: {
+ keyId: 'dynamic',
+ adUnits: ['gpt-123'],
+ threshold: 1
+ }
+};
+
+const configWithoutRequiredParams = {
+ params: {
+ keyId: ''
+ }
+};
+
+describe('dynamicAdBoost', function() {
+ let clock;
+ let sandbox;
+ beforeEach(function () {
+ sandbox = sinon.sandbox.create();
+ clock = sandbox.useFakeTimers(Date.now());
+ });
+ afterEach(function () {
+ sandbox.restore();
+ });
+ describe('init', function() {
+ describe('initialize without expected params', function() {
+ it('fails initalize when keyId is not present', function() {
+ expect(rtdProvider.init(configWithoutRequiredParams)).to.be.false;
+ })
+ })
+
+ describe('initialize with expected params', function() {
+ it('successfully initialize with load script', function() {
+ expect(rtdProvider.init(configWithParams)).to.be.true;
+ clock.tick(1000);
+ expect(loadExternalScript.called).to.be.true;
+ })
+ });
+ });
+})
+
+describe('markViewed tests', function() {
+ let sandbox;
+ const mockObserver = {
+ unobserve: sinon.spy()
+ };
+ const makeElement = (id) => {
+ const el = document.createElement('div');
+ el.setAttribute('id', id);
+ return el;
+ }
+ const mockEntry = {
+ target: makeElement('target_id')
+ };
+
+ beforeEach(function() {
+ sandbox = sinon.sandbox.create();
+ })
+
+ afterEach(function() {
+ sandbox.restore()
+ })
+
+ it('markViewed returns a function', function() {
+ expect(rtdProvider.markViewed(mockEntry, mockObserver)).to.be.a('function')
+ });
+
+ it('markViewed unobserves', function() {
+ const func = rtdProvider.markViewed(mockEntry, mockObserver);
+ func();
+ expect(mockObserver.unobserve.calledOnce).to.be.true;
+ });
+})
diff --git a/test/spec/modules/edge226BidAdapter_spec.js b/test/spec/modules/edge226BidAdapter_spec.js
new file mode 100644
index 00000000000..4819d8d4a4e
--- /dev/null
+++ b/test/spec/modules/edge226BidAdapter_spec.js
@@ -0,0 +1,373 @@
+import { expect } from 'chai';
+import { spec } from '../../../modules/edge226BidAdapter.js';
+import { BANNER, VIDEO, NATIVE } from '../../../src/mediaTypes.js';
+import { getUniqueIdentifierStr } from '../../../src/utils.js';
+
+const bidder = 'edge226'
+
+describe('Edge226BidAdapter', function () {
+ const bids = [
+ {
+ bidId: getUniqueIdentifierStr(),
+ bidder: bidder,
+ mediaTypes: {
+ [BANNER]: {
+ sizes: [[300, 250]]
+ }
+ },
+ params: {
+ placementId: 'testBanner',
+ }
+ },
+ {
+ bidId: getUniqueIdentifierStr(),
+ bidder: bidder,
+ mediaTypes: {
+ [VIDEO]: {
+ playerSize: [[300, 300]],
+ minduration: 5,
+ maxduration: 60
+ }
+ },
+ params: {
+ placementId: 'testVideo',
+ }
+ },
+ {
+ bidId: getUniqueIdentifierStr(),
+ bidder: bidder,
+ mediaTypes: {
+ [NATIVE]: {
+ native: {
+ title: {
+ required: true
+ },
+ body: {
+ required: true
+ },
+ icon: {
+ required: true,
+ size: [64, 64]
+ }
+ }
+ }
+ },
+ params: {
+ placementId: 'testNative',
+ }
+ }
+ ];
+
+ const invalidBid = {
+ bidId: getUniqueIdentifierStr(),
+ bidder: bidder,
+ mediaTypes: {
+ [BANNER]: {
+ sizes: [[300, 250]]
+ }
+ },
+ params: {
+
+ }
+ }
+
+ const bidderRequest = {
+ uspConsent: '1---',
+ gdprConsent: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw',
+ refererInfo: {
+ referer: 'https://test.com'
+ },
+ timeout: 500
+ };
+
+ describe('isBidRequestValid', function () {
+ it('Should return true if there are bidId, params and key parameters present', function () {
+ expect(spec.isBidRequestValid(bids[0])).to.be.true;
+ });
+ it('Should return false if at least one of parameters is not present', function () {
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+ });
+
+ describe('buildRequests', function () {
+ let serverRequest = spec.buildRequests(bids, bidderRequest);
+
+ it('Creates a ServerRequest object with method, URL and data', function () {
+ expect(serverRequest).to.exist;
+ expect(serverRequest.method).to.exist;
+ expect(serverRequest.url).to.exist;
+ expect(serverRequest.data).to.exist;
+ });
+
+ it('Returns POST method', function () {
+ expect(serverRequest.method).to.equal('POST');
+ });
+
+ it('Returns valid URL', function () {
+ expect(serverRequest.url).to.equal('https://ssp.dauup.com/pbjs');
+ });
+
+ it('Returns general data valid', function () {
+ let data = serverRequest.data;
+ expect(data).to.be.an('object');
+ expect(data).to.have.all.keys('deviceWidth',
+ 'deviceHeight',
+ 'language',
+ 'secure',
+ 'host',
+ 'page',
+ 'placements',
+ 'coppa',
+ 'ccpa',
+ 'gdpr',
+ 'tmax'
+ );
+ expect(data.deviceWidth).to.be.a('number');
+ expect(data.deviceHeight).to.be.a('number');
+ expect(data.language).to.be.a('string');
+ expect(data.secure).to.be.within(0, 1);
+ expect(data.host).to.be.a('string');
+ expect(data.page).to.be.a('string');
+ expect(data.coppa).to.be.a('number');
+ expect(data.gdpr).to.be.a('string');
+ expect(data.ccpa).to.be.a('string');
+ expect(data.tmax).to.be.a('number');
+ expect(data.placements).to.have.lengthOf(3);
+ });
+
+ it('Returns valid placements', function () {
+ const { placements } = serverRequest.data;
+ for (let i = 0, len = placements.length; i < len; i++) {
+ const placement = placements[i];
+ expect(placement.placementId).to.be.oneOf(['testBanner', 'testVideo', 'testNative']);
+ expect(placement.adFormat).to.be.oneOf([BANNER, VIDEO, NATIVE]);
+ expect(placement.bidId).to.be.a('string');
+ expect(placement.schain).to.be.an('object');
+ expect(placement.bidfloor).to.exist.and.to.equal(0);
+ expect(placement.type).to.exist.and.to.equal('publisher');
+
+ if (placement.adFormat === BANNER) {
+ expect(placement.sizes).to.be.an('array');
+ }
+ switch (placement.adFormat) {
+ case BANNER:
+ expect(placement.sizes).to.be.an('array');
+ break;
+ case VIDEO:
+ expect(placement.playerSize).to.be.an('array');
+ expect(placement.minduration).to.be.an('number');
+ expect(placement.maxduration).to.be.an('number');
+ break;
+ case NATIVE:
+ expect(placement.native).to.be.an('object');
+ break;
+ }
+ }
+ });
+
+ it('Returns data with gdprConsent and without uspConsent', function () {
+ delete bidderRequest.uspConsent;
+ serverRequest = spec.buildRequests(bids, bidderRequest);
+ let data = serverRequest.data;
+ expect(data.gdpr).to.exist;
+ expect(data.gdpr).to.be.a('string');
+ expect(data.gdpr).to.equal(bidderRequest.gdprConsent);
+ expect(data.ccpa).to.not.exist;
+ delete bidderRequest.gdprConsent;
+ });
+
+ it('Returns data with uspConsent and without gdprConsent', function () {
+ bidderRequest.uspConsent = '1---';
+ delete bidderRequest.gdprConsent;
+ serverRequest = spec.buildRequests(bids, bidderRequest);
+ let data = serverRequest.data;
+ expect(data.ccpa).to.exist;
+ expect(data.ccpa).to.be.a('string');
+ expect(data.ccpa).to.equal(bidderRequest.uspConsent);
+ expect(data.gdpr).to.not.exist;
+ });
+
+ it('Returns empty data if no valid requests are passed', function () {
+ serverRequest = spec.buildRequests([], bidderRequest);
+ let data = serverRequest.data;
+ expect(data.placements).to.be.an('array').that.is.empty;
+ });
+ });
+
+ describe('interpretResponse', function () {
+ it('Should interpret banner response', function () {
+ const banner = {
+ body: [{
+ mediaType: 'banner',
+ width: 300,
+ height: 250,
+ cpm: 0.4,
+ ad: 'Test',
+ requestId: '23fhj33i987f',
+ ttl: 120,
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ dealId: '1',
+ meta: {
+ advertiserDomains: ['google.com'],
+ advertiserId: 1234
+ }
+ }]
+ };
+ let bannerResponses = spec.interpretResponse(banner);
+ expect(bannerResponses).to.be.an('array').that.is.not.empty;
+ let dataItem = bannerResponses[0];
+ expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId',
+ 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta');
+ expect(dataItem.requestId).to.equal(banner.body[0].requestId);
+ expect(dataItem.cpm).to.equal(banner.body[0].cpm);
+ expect(dataItem.width).to.equal(banner.body[0].width);
+ expect(dataItem.height).to.equal(banner.body[0].height);
+ expect(dataItem.ad).to.equal(banner.body[0].ad);
+ expect(dataItem.ttl).to.equal(banner.body[0].ttl);
+ expect(dataItem.creativeId).to.equal(banner.body[0].creativeId);
+ expect(dataItem.netRevenue).to.be.true;
+ expect(dataItem.currency).to.equal(banner.body[0].currency);
+ expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains');
+ });
+ it('Should interpret video response', function () {
+ const video = {
+ body: [{
+ vastUrl: 'test.com',
+ mediaType: 'video',
+ cpm: 0.5,
+ requestId: '23fhj33i987f',
+ ttl: 120,
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ dealId: '1',
+ meta: {
+ advertiserDomains: ['google.com'],
+ advertiserId: 1234
+ }
+ }]
+ };
+ let videoResponses = spec.interpretResponse(video);
+ expect(videoResponses).to.be.an('array').that.is.not.empty;
+
+ let dataItem = videoResponses[0];
+ expect(dataItem).to.have.all.keys('requestId', 'cpm', 'vastUrl', 'ttl', 'creativeId',
+ 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta');
+ expect(dataItem.requestId).to.equal('23fhj33i987f');
+ expect(dataItem.cpm).to.equal(0.5);
+ expect(dataItem.vastUrl).to.equal('test.com');
+ expect(dataItem.ttl).to.equal(120);
+ expect(dataItem.creativeId).to.equal('2');
+ expect(dataItem.netRevenue).to.be.true;
+ expect(dataItem.currency).to.equal('USD');
+ expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains');
+ });
+ it('Should interpret native response', function () {
+ const native = {
+ body: [{
+ mediaType: 'native',
+ native: {
+ clickUrl: 'test.com',
+ title: 'Test',
+ image: 'test.com',
+ impressionTrackers: ['test.com'],
+ },
+ ttl: 120,
+ cpm: 0.4,
+ requestId: '23fhj33i987f',
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ meta: {
+ advertiserDomains: ['google.com'],
+ advertiserId: 1234
+ }
+ }]
+ };
+ let nativeResponses = spec.interpretResponse(native);
+ expect(nativeResponses).to.be.an('array').that.is.not.empty;
+
+ let dataItem = nativeResponses[0];
+ expect(dataItem).to.have.keys('requestId', 'cpm', 'ttl', 'creativeId', 'netRevenue', 'currency', 'mediaType', 'native', 'meta');
+ expect(dataItem.native).to.have.keys('clickUrl', 'impressionTrackers', 'title', 'image')
+ expect(dataItem.requestId).to.equal('23fhj33i987f');
+ expect(dataItem.cpm).to.equal(0.4);
+ expect(dataItem.native.clickUrl).to.equal('test.com');
+ expect(dataItem.native.title).to.equal('Test');
+ expect(dataItem.native.image).to.equal('test.com');
+ expect(dataItem.native.impressionTrackers).to.be.an('array').that.is.not.empty;
+ expect(dataItem.native.impressionTrackers[0]).to.equal('test.com');
+ expect(dataItem.ttl).to.equal(120);
+ expect(dataItem.creativeId).to.equal('2');
+ expect(dataItem.netRevenue).to.be.true;
+ expect(dataItem.currency).to.equal('USD');
+ expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains');
+ });
+ it('Should return an empty array if invalid banner response is passed', function () {
+ const invBanner = {
+ body: [{
+ width: 300,
+ cpm: 0.4,
+ ad: 'Test',
+ requestId: '23fhj33i987f',
+ ttl: 120,
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ dealId: '1'
+ }]
+ };
+
+ let serverResponses = spec.interpretResponse(invBanner);
+ expect(serverResponses).to.be.an('array').that.is.empty;
+ });
+ it('Should return an empty array if invalid video response is passed', function () {
+ const invVideo = {
+ body: [{
+ mediaType: 'video',
+ cpm: 0.5,
+ requestId: '23fhj33i987f',
+ ttl: 120,
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ dealId: '1'
+ }]
+ };
+ let serverResponses = spec.interpretResponse(invVideo);
+ expect(serverResponses).to.be.an('array').that.is.empty;
+ });
+ it('Should return an empty array if invalid native response is passed', function () {
+ const invNative = {
+ body: [{
+ mediaType: 'native',
+ clickUrl: 'test.com',
+ title: 'Test',
+ impressionTrackers: ['test.com'],
+ ttl: 120,
+ requestId: '23fhj33i987f',
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ }]
+ };
+ let serverResponses = spec.interpretResponse(invNative);
+ expect(serverResponses).to.be.an('array').that.is.empty;
+ });
+ it('Should return an empty array if invalid response is passed', function () {
+ const invalid = {
+ body: [{
+ ttl: 120,
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ dealId: '1'
+ }]
+ };
+ let serverResponses = spec.interpretResponse(invalid);
+ expect(serverResponses).to.be.an('array').that.is.empty;
+ });
+ });
+});
diff --git a/test/spec/modules/eids_spec.js b/test/spec/modules/eids_spec.js
index 1597790e652..e1f2394ab27 100644
--- a/test/spec/modules/eids_spec.js
+++ b/test/spec/modules/eids_spec.js
@@ -29,6 +29,18 @@ describe('eids array generation for known sub-modules', function() {
});
});
+ it('unifiedId: ext generation with provider', function() {
+ const userId = {
+ tdid: {'id': 'some-sample_id', 'ext': {'provider': 'some.provider.com'}}
+ };
+ const newEids = createEidsArray(userId);
+ expect(newEids.length).to.equal(1);
+ expect(newEids[0]).to.deep.equal({
+ source: 'adserver.org',
+ uids: [{id: 'some-sample_id', atype: 1, ext: { rtiPartner: 'TDID', provider: 'some.provider.com' }}]
+ });
+ });
+
describe('id5Id', function() {
it('does not include an ext if not provided', function() {
const userId = {
@@ -238,6 +250,39 @@ describe('eids array generation for known sub-modules', function() {
});
});
+ it('sovrn', function() {
+ const userId = {
+ sovrn: {'id': 'sample_id'}
+ };
+ const newEids = createEidsArray(userId);
+ expect(newEids.length).to.equal(1);
+ expect(newEids[0]).to.deep.equal({
+ source: 'liveintent.sovrn.com',
+ uids: [{
+ id: 'sample_id',
+ atype: 3
+ }]
+ });
+ });
+
+ it('sovrn with ext', function() {
+ const userId = {
+ sovrn: {'id': 'sample_id', 'ext': {'provider': 'some.provider.com'}}
+ };
+ const newEids = createEidsArray(userId);
+ expect(newEids.length).to.equal(1);
+ expect(newEids[0]).to.deep.equal({
+ source: 'liveintent.sovrn.com',
+ uids: [{
+ id: 'sample_id',
+ atype: 3,
+ ext: {
+ provider: 'some.provider.com'
+ }
+ }]
+ });
+ });
+
it('magnite', function() {
const userId = {
magnite: {'id': 'sample_id'}
@@ -304,6 +349,72 @@ describe('eids array generation for known sub-modules', function() {
});
});
+ it('openx', function () {
+ const userId = {
+ openx: { 'id': 'sample_id' }
+ };
+ const newEids = createEidsArray(userId);
+ expect(newEids.length).to.equal(1);
+ expect(newEids[0]).to.deep.equal({
+ source: 'openx.net',
+ uids: [{
+ id: 'sample_id',
+ atype: 3
+ }]
+ });
+ });
+
+ it('openx with ext', function () {
+ const userId = {
+ openx: { 'id': 'sample_id', 'ext': { 'provider': 'some.provider.com' } }
+ };
+ const newEids = createEidsArray(userId);
+ expect(newEids.length).to.equal(1);
+ expect(newEids[0]).to.deep.equal({
+ source: 'openx.net',
+ uids: [{
+ id: 'sample_id',
+ atype: 3,
+ ext: {
+ provider: 'some.provider.com'
+ }
+ }]
+ });
+ });
+
+ it('pubmatic', function() {
+ const userId = {
+ pubmatic: {'id': 'sample_id'}
+ };
+ const newEids = createEidsArray(userId);
+ expect(newEids.length).to.equal(1);
+ expect(newEids[0]).to.deep.equal({
+ source: 'pubmatic.com',
+ uids: [{
+ id: 'sample_id',
+ atype: 3
+ }]
+ });
+ });
+
+ it('pubmatic with ext', function() {
+ const userId = {
+ pubmatic: {'id': 'sample_id', 'ext': {'provider': 'some.provider.com'}}
+ };
+ const newEids = createEidsArray(userId);
+ expect(newEids.length).to.equal(1);
+ expect(newEids[0]).to.deep.equal({
+ source: 'pubmatic.com',
+ uids: [{
+ id: 'sample_id',
+ atype: 3,
+ ext: {
+ provider: 'some.provider.com'
+ }
+ }]
+ });
+ });
+
it('liveIntentId; getValue call and NO ext', function() {
const userId = {
lipb: {
diff --git a/test/spec/modules/enrichmentFpdModule_spec.js b/test/spec/modules/enrichmentFpdModule_spec.js
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/test/spec/modules/euidIdSystem_spec.js b/test/spec/modules/euidIdSystem_spec.js
index 4f6bacebe6a..9ad2b69e89c 100644
--- a/test/spec/modules/euidIdSystem_spec.js
+++ b/test/spec/modules/euidIdSystem_spec.js
@@ -3,9 +3,11 @@ import {config} from 'src/config.js';
import {euidIdSubmodule} from 'modules/euidIdSystem.js';
import 'modules/consentManagement.js';
import 'src/prebid.js';
+import * as utils from 'src/utils.js';
import {apiHelpers, cookieHelpers, runAuction, setGdprApplies} from './uid2IdSystem_helpers.js';
import {hook} from 'src/hook.js';
import {uninstall as uninstallGdprEnforcement} from 'modules/gdprEnforcement.js';
+import {server} from 'test/mocks/xhr';
let expect = require('chai').expect;
@@ -20,22 +22,31 @@ const refreshedToken = 'refreshed-advertising-token';
const auctionDelayMs = 10;
const makeEuidIdentityContainer = (token) => ({euid: {id: token}});
+const makeEuidOptoutContainer = (token) => ({euid: {optout: true}});
const useLocalStorage = true;
+
const makePrebidConfig = (params = null, extraSettings = {}, debug = false) => ({
userSync: { auctionDelay: auctionDelayMs, userIds: [{name: 'euid', params: {storage: useLocalStorage ? 'localStorage' : 'cookie', ...params}, ...extraSettings}] }, debug
});
+const cstgConfigParams = { serverPublicKey: 'UID2-X-L-24B8a/eLYBmRkXA9yPgRZt+ouKbXewG2OPs23+ov3JC8mtYJBCx6AxGwJ4MlwUcguebhdDp2CvzsCgS9ogwwGA==', subscriptionId: 'subscription-id' }
+const clientSideGeneratedToken = 'client-side-generated-advertising-token';
+const optoutToken = 'optout-token';
+
const apiUrl = 'https://prod.euid.eu/v2/token/refresh';
+const cstgApiUrl = 'https://prod.euid.eu/v2/token/client-generate';
const headers = { 'Content-Type': 'application/json' };
-const makeSuccessResponseBody = () => btoa(JSON.stringify({ status: 'success', body: { ...apiHelpers.makeTokenResponse(initialToken), advertising_token: refreshedToken } }));
+const makeSuccessResponseBody = (token) => btoa(JSON.stringify({ status: 'success', body: { ...apiHelpers.makeTokenResponse(initialToken), advertising_token: token } }));
+const makeOptoutResponseBody = (token) => btoa(JSON.stringify({ status: 'optout', body: { ...apiHelpers.makeTokenResponse(initialToken), advertising_token: token } }));
const expectToken = (bid, token) => expect(bid?.userId ?? {}).to.deep.include(makeEuidIdentityContainer(token));
+const expectOptout = (bid, token) => expect(bid?.userId ?? {}).to.deep.include(makeEuidOptoutContainer(token));
const expectNoIdentity = (bid) => expect(bid).to.not.haveOwnProperty('userId');
describe('EUID module', function() {
- let suiteSandbox, testSandbox, timerSpy, fullTestTitle, restoreSubtleToUndefined = false;
- let server;
+ let suiteSandbox, restoreSubtleToUndefined = false;
const configureEuidResponse = (httpStatus, response) => server.respondWith('POST', apiUrl, (xhr) => xhr.respond(httpStatus, headers, response));
+ const configureEuidCstgResponse = (httpStatus, response) => server.respondWith('POST', cstgApiUrl, (xhr) => xhr.respond(httpStatus, headers, response));
before(function() {
uninstallGdprEnforcement();
@@ -43,22 +54,28 @@ describe('EUID module', function() {
suiteSandbox = sinon.sandbox.create();
if (typeof window.crypto.subtle === 'undefined') {
restoreSubtleToUndefined = true;
- window.crypto.subtle = { importKey: () => {}, decrypt: () => {} };
+ window.crypto.subtle = { importKey: () => {}, digest: () => {}, decrypt: () => {}, deriveKey: () => {}, encrypt: () => {}, generateKey: () => {}, exportKey: () => {} };
}
suiteSandbox.stub(window.crypto.subtle, 'importKey').callsFake(() => Promise.resolve());
+ suiteSandbox.stub(window.crypto.subtle, 'digest').callsFake(() => Promise.resolve('hashed_value'));
suiteSandbox.stub(window.crypto.subtle, 'decrypt').callsFake((settings, key, data) => Promise.resolve(new Uint8Array([...settings.iv, ...data])));
+ suiteSandbox.stub(window.crypto.subtle, 'deriveKey').callsFake(() => Promise.resolve());
+ suiteSandbox.stub(window.crypto.subtle, 'exportKey').callsFake(() => Promise.resolve());
+ suiteSandbox.stub(window.crypto.subtle, 'encrypt').callsFake(() => Promise.resolve(new ArrayBuffer()));
+ suiteSandbox.stub(window.crypto.subtle, 'generateKey').callsFake(() => Promise.resolve({
+ privateKey: {},
+ publicKey: {}
+ }));
});
after(function() {
suiteSandbox.restore();
if (restoreSubtleToUndefined) window.crypto.subtle = undefined;
});
beforeEach(function() {
- server = sinon.createFakeServer();
init(config);
setSubmoduleRegistry([euidIdSubmodule]);
});
afterEach(function() {
- server.restore();
$$PREBID_GLOBAL$$.requestBids.removeAll();
config.resetConfig();
cookieHelpers.clearCookies(moduleCookieName, publisherCookieName);
@@ -115,10 +132,33 @@ describe('EUID module', function() {
it('When an expired token is provided and the API responds in time, the refreshed token is provided to the auction.', async function() {
setGdprApplies(true);
const euidToken = apiHelpers.makeTokenResponse(initialToken, true, true);
- configureEuidResponse(200, makeSuccessResponseBody());
+ configureEuidResponse(200, makeSuccessResponseBody(refreshedToken));
config.setConfig(makePrebidConfig({euidToken}));
apiHelpers.respondAfterDelay(1, server);
const bid = await runAuction();
expectToken(bid, refreshedToken);
});
+
+ if (FEATURES.UID2_CSTG) {
+ it('Should use client side generated EUID token in the auction.', async function() {
+ setGdprApplies(true);
+ const euidToken = apiHelpers.makeTokenResponse(initialToken, true, true);
+ configureEuidCstgResponse(200, makeSuccessResponseBody(clientSideGeneratedToken));
+ config.setConfig(makePrebidConfig({ euidToken, ...cstgConfigParams, email: 'test@test.com' }));
+ apiHelpers.respondAfterDelay(1, server);
+
+ const bid = await runAuction();
+ expectToken(bid, clientSideGeneratedToken);
+ });
+ it('Should receive an optout response when the user has opted out.', async function() {
+ setGdprApplies(true);
+ const euidToken = apiHelpers.makeTokenResponse(initialToken, true, true);
+ configureEuidCstgResponse(200, makeOptoutResponseBody(optoutToken));
+ config.setConfig(makePrebidConfig({ euidToken, ...cstgConfigParams, email: 'optout@test.com' }));
+ apiHelpers.respondAfterDelay(1, server);
+
+ const bid = await runAuction();
+ expectOptout(bid, optoutToken);
+ });
+ }
});
diff --git a/test/spec/modules/fledgeForGpt_spec.js b/test/spec/modules/fledgeForGpt_spec.js
index b4bff8e82f0..8ab11171121 100644
--- a/test/spec/modules/fledgeForGpt_spec.js
+++ b/test/spec/modules/fledgeForGpt_spec.js
@@ -1,430 +1,177 @@
-import {
- expect
-} from 'chai';
-import * as fledge from 'modules/fledgeForGpt.js';
-import {config} from '../../../src/config.js';
-import adapterManager from '../../../src/adapterManager.js';
-import * as utils from '../../../src/utils.js';
+import {onAuctionConfigFactory, setPAAPIConfigFactory, slotConfigurator} from 'modules/fledgeForGpt.js';
import * as gptUtils from '../../../libraries/gptUtils/gptUtils.js';
-import {hook} from '../../../src/hook.js';
import 'modules/appnexusBidAdapter.js';
import 'modules/rubiconBidAdapter.js';
-import {parseExtPrebidFledge, setImpExtAe, setResponseFledgeConfigs} from 'modules/fledgeForGpt.js';
-import * as events from 'src/events.js';
-import CONSTANTS from 'src/constants.json';
-import {getGlobal} from '../../../src/prebidGlobal.js';
+import {deepSetValue} from '../../../src/utils.js';
+import {config} from 'src/config.js';
describe('fledgeForGpt module', () => {
- let sandbox;
+ let sandbox, fledgeAuctionConfig;
beforeEach(() => {
sandbox = sinon.sandbox.create();
+ fledgeAuctionConfig = {
+ seller: 'bidder',
+ mock: 'config'
+ };
});
afterEach(() => {
sandbox.restore();
});
- describe('addComponentAuction', function () {
- before(() => {
- fledge.init({enabled: true});
- });
- const fledgeAuctionConfig = {
- seller: 'bidder',
- mock: 'config'
- };
-
- describe('addComponentAuctionHook', function () {
- let nextFnSpy, mockGptSlot;
- beforeEach(function () {
- nextFnSpy = sinon.spy();
- mockGptSlot = {
- setConfig: sinon.stub(),
- getAdUnitPath: () => 'mock/gpt/au'
- };
- sandbox.stub(gptUtils, 'getGptSlotForAdUnitCode').callsFake(() => mockGptSlot);
- });
-
- it('should call next()', function () {
- fledge.addComponentAuctionHook(nextFnSpy, 'aid', 'auc', fledgeAuctionConfig);
- sinon.assert.calledWith(nextFnSpy, 'aid', 'auc', fledgeAuctionConfig);
+ describe('slotConfigurator', () => {
+ let mockGptSlot, setGptConfig;
+ beforeEach(() => {
+ mockGptSlot = {
+ setConfig: sinon.stub(),
+ getAdUnitPath: () => 'mock/gpt/au'
+ };
+ sandbox.stub(gptUtils, 'getGptSlotForAdUnitCode').callsFake(() => mockGptSlot);
+ setGptConfig = slotConfigurator();
+ });
+ it('should set GPT slot config', () => {
+ setGptConfig('au', [fledgeAuctionConfig]);
+ sinon.assert.calledWith(gptUtils.getGptSlotForAdUnitCode, 'au');
+ sinon.assert.calledWith(mockGptSlot.setConfig, {
+ componentAuction: [{
+ configKey: 'bidder',
+ auctionConfig: fledgeAuctionConfig,
+ }]
});
+ });
- it('should collect auction configs and route them to GPT at end of auction', () => {
- events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: 'aid'});
- const cf1 = {...fledgeAuctionConfig, id: 1, seller: 'b1'};
- const cf2 = {...fledgeAuctionConfig, id: 2, seller: 'b2'};
- fledge.addComponentAuctionHook(nextFnSpy, 'aid', 'au1', cf1);
- fledge.addComponentAuctionHook(nextFnSpy, 'aid', 'au2', cf2);
- events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId: 'aid'});
- sinon.assert.calledWith(gptUtils.getGptSlotForAdUnitCode, 'au1');
- sinon.assert.calledWith(gptUtils.getGptSlotForAdUnitCode, 'au2');
+ describe('when reset = true', () => {
+ it('should reset GPT slot config', () => {
+ setGptConfig('au', [fledgeAuctionConfig]);
+ mockGptSlot.setConfig.resetHistory();
+ gptUtils.getGptSlotForAdUnitCode.resetHistory();
+ setGptConfig('au', [], true);
+ sinon.assert.calledWith(gptUtils.getGptSlotForAdUnitCode, 'au');
sinon.assert.calledWith(mockGptSlot.setConfig, {
componentAuction: [{
- configKey: 'b1',
- auctionConfig: cf1,
+ configKey: 'bidder',
+ auctionConfig: null
}]
});
+ });
+
+ it('should reset only sellers with no fresh config', () => {
+ setGptConfig('au', [{seller: 's1'}, {seller: 's2'}]);
+ mockGptSlot.setConfig.resetHistory();
+ setGptConfig('au', [{seller: 's1'}], true);
sinon.assert.calledWith(mockGptSlot.setConfig, {
componentAuction: [{
- configKey: 'b2',
- auctionConfig: cf2,
+ configKey: 's1',
+ auctionConfig: {seller: 's1'}
+ }, {
+ configKey: 's2',
+ auctionConfig: null
}]
- });
+ })
});
- it('should drop auction configs after end of auction', () => {
- events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: 'aid'});
- events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId: 'aid'});
- fledge.addComponentAuctionHook(nextFnSpy, 'aid', 'au', fledgeAuctionConfig);
- events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId: 'aid'});
+ it('should not reset sellers that were already reset', () => {
+ setGptConfig('au', [{seller: 's1'}]);
+ setGptConfig('au', [], true);
+ mockGptSlot.setConfig.resetHistory();
+ setGptConfig('au', [], true);
sinon.assert.notCalled(mockGptSlot.setConfig);
- });
-
- describe('floor signal', () => {
- before(() => {
- if (!getGlobal().convertCurrency) {
- getGlobal().convertCurrency = () => null;
- getGlobal().convertCurrency.mock = true;
- }
- });
- after(() => {
- if (getGlobal().convertCurrency.mock) {
- delete getGlobal().convertCurrency;
- }
- });
-
- beforeEach(() => {
- sandbox.stub(getGlobal(), 'convertCurrency').callsFake((amount, from, to) => {
- if (from === to) return amount;
- if (from === 'USD' && to === 'JPY') return amount * 100;
- if (from === 'JPY' && to === 'USD') return amount / 100;
- throw new Error('unexpected currency conversion');
- });
+ })
+
+ it('should keep track of configuration history by slot', () => {
+ setGptConfig('au1', [{seller: 's1'}]);
+ setGptConfig('au1', [{seller: 's2'}], false);
+ setGptConfig('au2', [{seller: 's3'}]);
+ mockGptSlot.setConfig.resetHistory();
+ setGptConfig('au1', [], true);
+ sinon.assert.calledWith(mockGptSlot.setConfig, {
+ componentAuction: [{
+ configKey: 's1',
+ auctionConfig: null
+ }, {
+ configKey: 's2',
+ auctionConfig: null
+ }]
});
-
+ })
+ });
+ });
+ describe('onAuctionConfig', () => {
+ [
+ 'fledgeForGpt',
+ 'paapi.gpt'
+ ].forEach(namespace => {
+ describe(`using ${namespace} config`, () => {
Object.entries({
- 'bids': (payload, values) => {
- payload.bidsReceived = values
- .map((val) => ({adUnitCode: 'au', cpm: val.amount, currency: val.cur}))
- .concat([{adUnitCode: 'other', cpm: 10000, currency: 'EUR'}])
- },
- 'no bids': (payload, values) => {
- payload.bidderRequests = values
- .map((val) => ({bids: [{adUnitCode: 'au', getFloor: () => ({floor: val.amount, currency: val.cur})}]}))
- .concat([{bids: {adUnitCode: 'other', getFloor: () => ({floor: -10000, currency: 'EUR'})}}])
- }
- }).forEach(([tcase, setup]) => {
- describe(`when auction has ${tcase}`, () => {
- Object.entries({
- 'no currencies': {
- values: [{amount: 1}, {amount: 100}, {amount: 10}, {amount: 100}],
- 'bids': {
- bidfloor: 100,
- bidfloorcur: undefined
- },
- 'no bids': {
- bidfloor: 1,
- bidfloorcur: undefined,
- }
- },
- 'only zero values': {
- values: [{amount: 0, cur: 'USD'}, {amount: 0, cur: 'JPY'}],
- 'bids': {
- bidfloor: undefined,
- bidfloorcur: undefined,
- },
- 'no bids': {
- bidfloor: undefined,
- bidfloorcur: undefined,
- }
- },
- 'matching currencies': {
- values: [{amount: 10, cur: 'JPY'}, {amount: 100, cur: 'JPY'}],
- 'bids': {
- bidfloor: 100,
- bidfloorcur: 'JPY',
- },
- 'no bids': {
- bidfloor: 10,
- bidfloorcur: 'JPY',
- }
- },
- 'mixed currencies': {
- values: [{amount: 10, cur: 'USD'}, {amount: 10, cur: 'JPY'}],
- 'bids': {
- bidfloor: 10,
- bidfloorcur: 'USD'
- },
- 'no bids': {
- bidfloor: 10,
- bidfloorcur: 'JPY',
- }
- }
- }).forEach(([t, testConfig]) => {
- const values = testConfig.values;
- const {bidfloor, bidfloorcur} = testConfig[tcase];
-
- describe(`with ${t}`, () => {
- let payload;
- beforeEach(() => {
- payload = {auctionId: 'aid'};
- setup(payload, values);
- });
+ 'omitted': [undefined, true],
+ 'enabled': [true, true],
+ 'disabled': [false, false]
+ }).forEach(([t, [autoconfig, shouldSetConfig]]) => {
+ describe(`when autoconfig is ${t}`, () => {
+ beforeEach(() => {
+ const cfg = {};
+ deepSetValue(cfg, `${namespace}.autoconfig`, autoconfig);
+ config.setConfig(cfg);
+ });
+ afterEach(() => {
+ config.resetConfig();
+ });
- it('should populate bidfloor/bidfloorcur', () => {
- events.emit(CONSTANTS.EVENTS.AUCTION_INIT, {auctionId: 'aid'});
- fledge.addComponentAuctionHook(nextFnSpy, 'aid', 'au', fledgeAuctionConfig);
- events.emit(CONSTANTS.EVENTS.AUCTION_END, payload);
- sinon.assert.calledWith(mockGptSlot.setConfig, sinon.match(arg => {
- return arg.componentAuction.some(au => au.auctionConfig.auctionSignals?.prebid?.bidfloor === bidfloor && au.auctionConfig.auctionSignals?.prebid?.bidfloorcur === bidfloorcur)
- }))
- })
- });
+ it(`should ${shouldSetConfig ? '' : 'NOT'} set GPT slot configuration`, () => {
+ const auctionConfig = {componentAuctions: [{seller: 'mock1'}, {seller: 'mock2'}]};
+ const setGptConfig = sinon.stub();
+ const markAsUsed = sinon.stub();
+ onAuctionConfigFactory(setGptConfig)('aid', {au1: auctionConfig, au2: null}, markAsUsed);
+ if (shouldSetConfig) {
+ sinon.assert.calledWith(setGptConfig, 'au1', auctionConfig.componentAuctions);
+ sinon.assert.calledWith(setGptConfig, 'au2', []);
+ sinon.assert.calledWith(markAsUsed, 'au1');
+ } else {
+ sinon.assert.notCalled(setGptConfig);
+ sinon.assert.notCalled(markAsUsed);
+ }
});
})
})
- });
- });
+ })
+ })
});
-
- describe('fledgeEnabled', function () {
- const navProps = Object.fromEntries(['runAdAuction', 'joinAdInterestGroup'].map(p => [p, navigator[p]]));
-
- before(function () {
- // navigator.runAdAuction & co may not exist, so we can't stub it normally with
- // sinon.stub(navigator, 'runAdAuction') or something
- Object.keys(navProps).forEach(p => {
- navigator[p] = sinon.stub();
- });
- hook.ready();
+ describe('setPAAPIConfigForGpt', () => {
+ let getPAAPIConfig, setGptConfig, setPAAPIConfigForGPT;
+ beforeEach(() => {
+ getPAAPIConfig = sinon.stub();
+ setGptConfig = sinon.stub();
+ setPAAPIConfigForGPT = setPAAPIConfigFactory(getPAAPIConfig, setGptConfig);
});
- after(function () {
- Object.entries(navProps).forEach(([p, orig]) => navigator[p] = orig);
+ Object.entries({
+ missing: null,
+ empty: {}
+ }).forEach(([t, configs]) => {
+ it(`does not set GPT slot config when config is ${t}`, () => {
+ getPAAPIConfig.returns(configs);
+ setPAAPIConfigForGPT('mock-filters');
+ sinon.assert.calledWith(getPAAPIConfig, 'mock-filters');
+ sinon.assert.notCalled(setGptConfig);
+ })
});
- afterEach(function () {
- config.resetConfig();
- });
-
- const adUnits = [{
- 'code': '/19968336/header-bid-tag1',
- 'mediaTypes': {
- 'banner': {
- 'sizes': [[728, 90]]
- },
- },
- 'bids': [
- {
- 'bidder': 'appnexus',
+ it('sets GPT slot config for each ad unit that has PAAPI config, and resets the rest', () => {
+ const cfg = {
+ au1: {
+ componentAuctions: [{seller: 's1'}, {seller: 's2'}]
},
- {
- 'bidder': 'rubicon',
+ au2: {
+ componentAuctions: [{seller: 's3'}]
},
- ]
- }];
-
- describe('with setBidderConfig()', () => {
- it('should set fledgeEnabled correctly per bidder', function () {
- config.setConfig({bidderSequence: 'fixed'});
- config.setBidderConfig({
- bidders: ['appnexus'],
- config: {
- fledgeEnabled: true,
- defaultForSlots: 1,
- }
- });
-
- const bidRequests = adapterManager.makeBidRequests(
- adUnits,
- Date.now(),
- utils.getUniqueIdentifierStr(),
- function callback() {
- },
- []
- );
-
- expect(bidRequests[0].bids[0].bidder).equals('appnexus');
- expect(bidRequests[0].fledgeEnabled).to.be.true;
- expect(bidRequests[0].defaultForSlots).to.equal(1);
-
- expect(bidRequests[1].bids[0].bidder).equals('rubicon');
- expect(bidRequests[1].fledgeEnabled).to.be.undefined;
- expect(bidRequests[1].defaultForSlots).to.be.undefined;
- });
- });
-
- describe('with setConfig()', () => {
- it('should set fledgeEnabled correctly per bidder', function () {
- config.setConfig({
- bidderSequence: 'fixed',
- fledgeForGpt: {
- enabled: true,
- bidders: ['appnexus'],
- defaultForSlots: 1,
- }
- });
-
- const bidRequests = adapterManager.makeBidRequests(
- adUnits,
- Date.now(),
- utils.getUniqueIdentifierStr(),
- function callback() {
- },
- []
- );
-
- expect(bidRequests[0].bids[0].bidder).equals('appnexus');
- expect(bidRequests[0].fledgeEnabled).to.be.true;
- expect(bidRequests[0].defaultForSlots).to.equal(1);
-
- expect(bidRequests[1].bids[0].bidder).equals('rubicon');
- expect(bidRequests[1].fledgeEnabled).to.be.undefined;
- expect(bidRequests[1].defaultForSlots).to.be.undefined;
- });
-
- it('should set fledgeEnabled correctly for all bidders', function () {
- config.setConfig({
- bidderSequence: 'fixed',
- fledgeForGpt: {
- enabled: true,
- defaultForSlots: 1,
- }
- });
-
- const bidRequests = adapterManager.makeBidRequests(
- adUnits,
- Date.now(),
- utils.getUniqueIdentifierStr(),
- function callback() {
- },
- []
- );
-
- expect(bidRequests[0].bids[0].bidder).equals('appnexus');
- expect(bidRequests[0].fledgeEnabled).to.be.true;
- expect(bidRequests[0].defaultForSlots).to.equal(1);
-
- expect(bidRequests[1].bids[0].bidder).equals('rubicon');
- expect(bidRequests[0].fledgeEnabled).to.be.true;
- expect(bidRequests[0].defaultForSlots).to.equal(1);
- });
- });
- });
-
- describe('ortb processors for fledge', () => {
- describe('when defaultForSlots is set', () => {
- it('imp.ext.ae should be set if fledge is enabled', () => {
- const imp = {};
- setImpExtAe(imp, {}, {bidderRequest: {fledgeEnabled: true, defaultForSlots: 1}});
- expect(imp.ext.ae).to.equal(1);
- });
- it('imp.ext.ae should be left intact if set on adunit and fledge is enabled', () => {
- const imp = {ext: {ae: 2}};
- setImpExtAe(imp, {}, {bidderRequest: {fledgeEnabled: true, defaultForSlots: 1}});
- expect(imp.ext.ae).to.equal(2);
- });
- });
- describe('when defaultForSlots is not defined', () => {
- it('imp.ext.ae should be removed if fledge is not enabled', () => {
- const imp = {ext: {ae: 1}};
- setImpExtAe(imp, {}, {bidderRequest: {}});
- expect(imp.ext.ae).to.not.exist;
- });
- it('imp.ext.ae should be left intact if fledge is enabled', () => {
- const imp = {ext: {ae: 2}};
- setImpExtAe(imp, {}, {bidderRequest: {fledgeEnabled: true}});
- expect(imp.ext.ae).to.equal(2);
- });
- });
- describe('parseExtPrebidFledge', () => {
- function packageConfigs(configs) {
- return {
- ext: {
- prebid: {
- fledge: {
- auctionconfigs: configs
- }
- }
- }
- };
+ au3: null
}
-
- function generateImpCtx(fledgeFlags) {
- return Object.fromEntries(Object.entries(fledgeFlags).map(([impid, fledgeEnabled]) => [impid, {imp: {ext: {ae: fledgeEnabled}}}]));
- }
-
- function generateCfg(impid, ...ids) {
- return ids.map((id) => ({impid, config: {id}}));
- }
-
- function extractResult(ctx) {
- return Object.fromEntries(
- Object.entries(ctx)
- .map(([impid, ctx]) => [impid, ctx.fledgeConfigs?.map(cfg => cfg.config.id)])
- .filter(([_, val]) => val != null)
- );
- }
-
- it('should collect fledge configs by imp', () => {
- const ctx = {
- impContext: generateImpCtx({e1: 1, e2: 1, d1: 0})
- };
- const resp = packageConfigs(
- generateCfg('e1', 1, 2, 3)
- .concat(generateCfg('e2', 4)
- .concat(generateCfg('d1', 5, 6)))
- );
- parseExtPrebidFledge({}, resp, ctx);
- expect(extractResult(ctx.impContext)).to.eql({
- e1: [1, 2, 3],
- e2: [4],
- });
- });
- it('should not choke if fledge config references unknown imp', () => {
- const ctx = {impContext: generateImpCtx({i: 1})};
- const resp = packageConfigs(generateCfg('unknown', 1));
- parseExtPrebidFledge({}, resp, ctx);
- expect(extractResult(ctx.impContext)).to.eql({});
- });
+ getPAAPIConfig.returns(cfg);
+ setPAAPIConfigForGPT('mock-filters');
+ sinon.assert.calledWith(getPAAPIConfig, 'mock-filters');
+ Object.entries(cfg).forEach(([au, config]) => {
+ sinon.assert.calledWith(setGptConfig, au, config?.componentAuctions ?? [], true);
+ })
});
- describe('setResponseFledgeConfigs', () => {
- it('should set fledgeAuctionConfigs paired with their corresponding bid id', () => {
- const ctx = {
- impContext: {
- 1: {
- bidRequest: {bidId: 'bid1'},
- fledgeConfigs: [{config: {id: 1}}, {config: {id: 2}}]
- },
- 2: {
- bidRequest: {bidId: 'bid2'},
- fledgeConfigs: [{config: {id: 3}}]
- },
- 3: {
- bidRequest: {bidId: 'bid3'}
- }
- }
- };
- const resp = {};
- setResponseFledgeConfigs(resp, {}, ctx);
- expect(resp.fledgeAuctionConfigs).to.eql([
- {bidId: 'bid1', config: {id: 1}},
- {bidId: 'bid1', config: {id: 2}},
- {bidId: 'bid2', config: {id: 3}},
- ]);
- });
- it('should not set fledgeAuctionConfigs if none exist', () => {
- const resp = {};
- setResponseFledgeConfigs(resp, {}, {
- impContext: {
- 1: {
- fledgeConfigs: []
- },
- 2: {}
- }
- });
- expect(resp).to.eql({});
- });
- });
- });
+ })
});
diff --git a/test/spec/modules/freewheel-sspBidAdapter_spec.js b/test/spec/modules/freewheel-sspBidAdapter_spec.js
index c42c5e2528d..90ebe0b80ee 100644
--- a/test/spec/modules/freewheel-sspBidAdapter_spec.js
+++ b/test/spec/modules/freewheel-sspBidAdapter_spec.js
@@ -2,6 +2,7 @@ import { expect } from 'chai';
import { spec } from 'modules/freewheel-sspBidAdapter.js';
import { newBidder } from 'src/adapters/bidderFactory.js';
import { createEidsArray } from 'modules/userId/eids.js';
+import { config } from 'src/config.js';
const ENDPOINT = '//ads.stickyadstv.com/www/delivery/swfIndex.php';
const PREBID_VERSION = '$prebid.version$';
@@ -203,6 +204,14 @@ describe('freewheelSSP BidAdapter Test', () => {
let bidderRequest = {
'gdprConsent': {
'consentString': gdprConsentString
+ },
+ 'ortb2': {
+ 'site': {
+ 'content': {
+ 'test': 'news',
+ 'test2': 'param'
+ }
+ }
}
};
@@ -216,6 +225,7 @@ describe('freewheelSSP BidAdapter Test', () => {
expect(payload.playerSize).to.equal('300x600');
expect(payload._fw_gdpr_consent).to.exist.and.to.be.a('string');
expect(payload._fw_gdpr_consent).to.equal(gdprConsentString);
+ expect(payload._fw_prebid_content).to.deep.equal('{\"test\":\"news\",\"test2\":\"param\"}');
let gdprConsent = {
'gdprApplies': true,
diff --git a/test/spec/modules/gammaBidAdapter_spec.js b/test/spec/modules/gammaBidAdapter_spec.js
index 35394df7d11..f3a28c08576 100644
--- a/test/spec/modules/gammaBidAdapter_spec.js
+++ b/test/spec/modules/gammaBidAdapter_spec.js
@@ -8,8 +8,9 @@ describe('gammaBidAdapter', function() {
let bid = {
'bidder': 'gamma',
'params': {
- siteId: '1465446377',
- zoneId: '1515999290'
+ siteId: '1398219351',
+ zoneId: '1398219417',
+ region: 'SGP'
},
'adUnitCode': 'adunit-code',
'sizes': [
@@ -84,7 +85,7 @@ describe('gammaBidAdapter', function() {
'width': 300,
'height': 250,
'creativeId': '1515999070',
- 'dealId': 'gax-paj2qarjf2g',
+ 'dealId': 'gax-lvpjgs5b9k4n',
'currency': 'USD',
'netRevenue': true,
'ttl': 300,
diff --git a/test/spec/modules/gdprEnforcement_spec.js b/test/spec/modules/gdprEnforcement_spec.js
index 2880b2fac5d..4caf0276874 100644
--- a/test/spec/modules/gdprEnforcement_spec.js
+++ b/test/spec/modules/gdprEnforcement_spec.js
@@ -26,7 +26,7 @@ import * as events from 'src/events.js';
import 'modules/appnexusBidAdapter.js'; // some tests expect this to be in the adapter registry
import 'src/prebid.js';
import {hook} from '../../../src/hook.js';
-import {GDPR_GVLIDS, VENDORLESS_GVLID} from '../../../src/consentHandler.js';
+import {GDPR_GVLIDS, VENDORLESS_GVLID, FIRST_PARTY_GVLID} from '../../../src/consentHandler.js';
import {validateStorageEnforcement} from '../../../src/storageManager.js';
import {activityParams} from '../../../src/activities/activityParams.js';
@@ -37,7 +37,6 @@ describe('gdpr enforcement', function () {
let staticConfig = {
cmpApi: 'static',
timeout: 7500,
- allowAuctionWithoutConsent: false,
consentData: {
getTCData: {
'tcString': 'COuqj-POu90rDBcBkBENAZCgAPzAAAPAACiQFwwBAABAA1ADEAbQC4YAYAAgAxAG0A',
@@ -789,6 +788,21 @@ describe('gdpr enforcement', function () {
})
})
+ it('if validateRules is passed FIRST_PARTY_GVLID, it will use publisher.consents', () => {
+ const rule = createGdprRule();
+ const consentData = {
+ 'vendorData': {
+ 'publisher': {
+ 'consents': {
+ '1': true
+ }
+ },
+ },
+ };
+ const result = validateRules(rule, consentData, 'cdep', FIRST_PARTY_GVLID);
+ expect(result).to.equal(true);
+ });
+
describe('validateRules', function () {
Object.entries({
'1 (which does not consider LI)': [1, 'storage', false],
@@ -879,7 +893,6 @@ describe('gdpr enforcement', function () {
setEnforcementConfig({
gdpr: {
cmpApi: 'iab',
- allowAuctionWithoutConsent: true,
timeout: 5000
}
});
diff --git a/test/spec/modules/genericAnalyticsAdapter_spec.js b/test/spec/modules/genericAnalyticsAdapter_spec.js
index a5a6074c425..79874f5d756 100644
--- a/test/spec/modules/genericAnalyticsAdapter_spec.js
+++ b/test/spec/modules/genericAnalyticsAdapter_spec.js
@@ -75,7 +75,7 @@ describe('Generic analytics', () => {
options: {
url: 'mock',
events: {
- bidResponse: null
+ mockEvent: null
}
}
});
diff --git a/test/spec/modules/geoedgeRtdProvider_spec.js b/test/spec/modules/geoedgeRtdProvider_spec.js
index 96da2e3dbd7..211a3efa3c6 100644
--- a/test/spec/modules/geoedgeRtdProvider_spec.js
+++ b/test/spec/modules/geoedgeRtdProvider_spec.js
@@ -1,17 +1,21 @@
import * as utils from '../../../src/utils.js';
import {loadExternalScript} from '../../../src/adloader.js';
-import {
+import * as geoedgeRtdModule from '../../../modules/geoedgeRtdProvider.js';
+import {server} from '../../../test/mocks/xhr.js';
+import * as events from '../../../src/events.js';
+import CONSTANTS from '../../../src/constants.json';
+
+let {
geoedgeSubmodule,
getClientUrl,
getInPageUrl,
htmlPlaceholder,
setWrapper,
- wrapper,
- WRAPPER_URL
-} from '../../../modules/geoedgeRtdProvider.js';
-import {server} from '../../../test/mocks/xhr.js';
-import * as events from '../../../src/events.js';
-import CONSTANTS from '../../../src/constants.json';
+ getMacros,
+ WRAPPER_URL,
+ preloadClient,
+ markAsLoaded
+} = geoedgeRtdModule;
let key = '123123123';
function makeConfig(gpt) {
@@ -64,13 +68,11 @@ describe('Geoedge RTD module', function () {
});
});
describe('init', function () {
- let insertElementStub;
-
before(function () {
- insertElementStub = sinon.stub(utils, 'insertElement');
+ sinon.spy(geoedgeRtdModule, 'preloadClient');
});
after(function () {
- utils.insertElement.restore();
+ geoedgeRtdModule.preloadClient.restore();
});
it('should return false when missing params or key', function () {
let missingParams = geoedgeSubmodule.init({});
@@ -86,14 +88,13 @@ describe('Geoedge RTD module', function () {
let isWrapperRequest = request && request.url && request.url && request.url === WRAPPER_URL;
expect(isWrapperRequest).to.equal(true);
});
- it('should preload the client', function () {
- let isLinkPreloadAsScript = arg => arg.tagName === 'LINK' && arg.rel === 'preload' && arg.as === 'script' && arg.href === getClientUrl(key);
- expect(insertElementStub.calledWith(sinon.match(isLinkPreloadAsScript))).to.equal(true);
+ it('should call preloadClient', function () {
+ expect(preloadClient.called);
});
it('should emit billable events with applicable winning bids', function (done) {
let counter = 0;
events.on(CONSTANTS.EVENTS.BILLABLE_EVENT, function (event) {
- if (event.vendor === 'geoedge' && event.type === 'impression') {
+ if (event.vendor === geoedgeSubmodule.name && event.type === 'impression') {
counter += 1;
}
expect(counter).to.equal(1);
@@ -103,7 +104,7 @@ describe('Geoedge RTD module', function () {
});
it('should load the in page code when gpt params is true', function () {
geoedgeSubmodule.init(makeConfig(true));
- let isInPageUrl = arg => arg == getInPageUrl(key);
+ let isInPageUrl = arg => arg === getInPageUrl(key);
expect(loadExternalScript.calledWith(sinon.match(isInPageUrl))).to.equal(true);
});
it('should set the window.grumi config object when gpt params is true', function () {
@@ -111,10 +112,36 @@ describe('Geoedge RTD module', function () {
expect(hasGrumiObj && window.grumi.key === key && window.grumi.fromPrebid).to.equal(true);
});
});
+ describe('preloadClient', function () {
+ let iframe;
+ preloadClient(key);
+ let loadExternalScriptCall = loadExternalScript.getCall(0);
+ it('should create an invisible iframe and insert it to the DOM', function () {
+ iframe = document.getElementById('grumiFrame');
+ expect(iframe && iframe.style.display === 'none');
+ });
+ it('should assign params object to the iframe\'s window', function () {
+ let grumi = iframe.contentWindow.grumi;
+ expect(grumi.key).to.equal(key);
+ });
+ it('should preload the client into the iframe', function () {
+ let isClientUrl = arg => arg === getClientUrl(key);
+ expect(loadExternalScriptCall.calledWithMatch(isClientUrl)).to.equal(true);
+ });
+ });
describe('setWrapper', function () {
it('should set the wrapper', function () {
setWrapper(mockWrapper);
- expect(wrapper).to.equal(mockWrapper);
+ expect(geoedgeRtdModule.wrapper).to.equal(mockWrapper);
+ });
+ });
+ describe('getMacros', function () {
+ it('return a dictionary of macros replaced with values from bid object', function () {
+ let bid = mockBid('testBidder');
+ let dict = getMacros(bid, key);
+ let hasCpm = dict['%_hbCpm!'] === bid.cpm;
+ let hasCurrency = dict['%_hbCurrency!'] === bid.currency;
+ expect(hasCpm && hasCurrency);
});
});
describe('onBidResponseEvent', function () {
diff --git a/test/spec/modules/goldfishAdsRtdProvider_spec.js b/test/spec/modules/goldfishAdsRtdProvider_spec.js
new file mode 100755
index 00000000000..39a1e0c9b33
--- /dev/null
+++ b/test/spec/modules/goldfishAdsRtdProvider_spec.js
@@ -0,0 +1,163 @@
+import {
+ goldfishAdsSubModule,
+ manageCallbackResponse,
+} from 'modules/goldfishAdsRtdProvider.js';
+import { getStorageManager } from '../../../src/storageManager.js';
+import { expect } from 'chai';
+import { server } from 'test/mocks/xhr.js';
+import { config as _config } from 'src/config.js';
+import { DATA_STORAGE_KEY, MODULE_NAME, MODULE_TYPE, getStorageData, updateUserData } from '../../../modules/goldfishAdsRtdProvider';
+
+const responseHeader = { 'Content-Type': 'application/json' };
+
+const sampleConfig = {
+ name: 'golfishAds',
+ waitForIt: true,
+ params: {
+ key: 'testkey'
+ }
+};
+
+const sampleAdUnits = [
+ {
+ code: 'one-div-id',
+ mediaTypes: {
+ banner: {
+ sizes: [970, 250]
+ }
+ },
+ bids: [
+ {
+ bidder: 'appnexus',
+ params: {
+ placementId: 12345370,
+ }
+ }]
+ },
+ {
+ code: 'two-div-id',
+ mediaTypes: {
+ banner: { sizes: [300, 250] }
+ },
+ bids: [
+ {
+ bidder: 'appnexus',
+ params: {
+ placementId: 12345370,
+ }
+ }]
+ }];
+
+const sampleOutputData = [1, 2, 3]
+
+describe('goldfishAdsRtdProvider is a RTD provider that', function () {
+ describe('has a method `init` that', function () {
+ it('exists', function () {
+ expect(goldfishAdsSubModule.init).to.be.a('function');
+ });
+ it('returns false missing config params', function () {
+ const config = {
+ name: 'goldfishAds',
+ waitForIt: true,
+ };
+ const value = goldfishAdsSubModule.init(config);
+ expect(value).to.equal(false);
+ });
+ it('returns false if missing providers param', function () {
+ const config = {
+ name: 'goldfishAds',
+ waitForIt: true,
+ params: {}
+ };
+ const value = goldfishAdsSubModule.init(config);
+ expect(value).to.equal(false);
+ });
+ it('returns false if wrong providers param included', function () {
+ const config = {
+ name: 'goldfishAds',
+ waitForIt: true,
+ params: {
+ account: 'test'
+ }
+ };
+ const value = goldfishAdsSubModule.init(config);
+ expect(value).to.equal(false);
+ });
+ it('returns true if good providers param included', function () {
+ const config = {
+ name: 'goldfishAds',
+ waitForIt: true,
+ params: {
+ key: 'testkey'
+ }
+ };
+ const value = goldfishAdsSubModule.init(config);
+ expect(value).to.equal(true);
+ });
+ });
+
+ describe('has a method `getBidRequestData` that', function () {
+ it('exists', function () {
+ expect(goldfishAdsSubModule.getBidRequestData).to.be.a('function');
+ });
+
+ it('send correct request', function () {
+ const callback = sinon.spy();
+ let request;
+ const reqBidsConfigObj = { adUnits: sampleAdUnits };
+ goldfishAdsSubModule.getBidRequestData(reqBidsConfigObj, callback, sampleConfig);
+ request = server.requests[0];
+ request.respond(200, responseHeader, JSON.stringify(sampleOutputData));
+ expect(request.url).to.be.include(`?key=testkey`);
+ });
+ });
+
+ describe('has a manageCallbackResponse that', function () {
+ it('properly transforms the response', function () {
+ const response = { response: '[\"1\", \"2\", \"3\"]' };
+ const output = manageCallbackResponse(response);
+ expect(output.name).to.be.equal('goldfishads.com');
+ });
+ });
+
+ describe('has an updateUserData that', function () {
+ it('properly transforms the response', function () {
+ const userData = {
+ segment: [{id: '1'}, {id: '2'}],
+ ext: {
+ segtax: 4,
+ }
+ };
+ const reqBidsConfigObj = { ortb2Fragments: { bidder: { appnexus: { user: { data: [] } } } } };
+ const output = updateUserData(userData, reqBidsConfigObj);
+ expect(output.ortb2Fragments.bidder.appnexus.user.data[0].segment).to.be.length(2);
+ expect(output.ortb2Fragments.bidder.appnexus.user.data[0].segment[0].id).to.be.eql('1');
+ });
+ });
+
+ describe('uses Local Storage to ', function () {
+ const sandbox = sinon.createSandbox();
+ const storage = getStorageManager({ moduleType: MODULE_TYPE, moduleName: MODULE_NAME })
+ beforeEach(() => {
+ storage.setDataInLocalStorage(DATA_STORAGE_KEY, JSON.stringify({
+ targeting: {
+ name: 'goldfishads.com',
+ segment: [{id: '1'}, {id: '2'}],
+ ext: {
+ segtax: 4,
+ }
+ },
+ expiry: new Date().getTime() + 1000 * 60 * 60 * 24 * 30,
+ }));
+ });
+ afterEach(() => {
+ sandbox.restore();
+ });
+ it('get data from local storage', function () {
+ const output = getStorageData();
+ expect(output.name).to.be.equal('goldfishads.com');
+ expect(output.segment).to.be.length(2);
+ expect(output.ext.segtax).to.be.equal(4);
+ });
+ });
+});
diff --git a/test/spec/modules/greenbidsAnalyticsAdapter_spec.js b/test/spec/modules/greenbidsAnalyticsAdapter_spec.js
index 870fbd23870..7b68b0dea46 100644
--- a/test/spec/modules/greenbidsAnalyticsAdapter_spec.js
+++ b/test/spec/modules/greenbidsAnalyticsAdapter_spec.js
@@ -1,8 +1,11 @@
import {
- greenbidsAnalyticsAdapter, parseBidderCode,
+ greenbidsAnalyticsAdapter,
+ isSampled,
ANALYTICS_VERSION, BIDDER_STATUS
} from 'modules/greenbidsAnalyticsAdapter.js';
-
+import {
+ generateUUID,
+} from '../../../src/utils.js';
import {expect} from 'chai';
import sinon from 'sinon';
@@ -13,11 +16,42 @@ const pbuid = 'pbuid-AA778D8A796AEA7A0843E2BBEB677766';
const auctionId = 'b0b39610-b941-4659-a87c-de9f62d3e13e';
describe('Greenbids Prebid AnalyticsAdapter Testing', function () {
+ describe('enableAnalytics and config parser', function () {
+ const configOptions = {
+ pbuid: pbuid,
+ greenbidsSampling: 1,
+ };
+ beforeEach(function () {
+ greenbidsAnalyticsAdapter.enableAnalytics({
+ provider: 'greenbidsAnalytics',
+ options: configOptions
+ });
+ });
+
+ afterEach(function () {
+ greenbidsAnalyticsAdapter.disableAnalytics();
+ });
+
+ it('should parse config correctly with optional values', function () {
+ expect(greenbidsAnalyticsAdapter.getAnalyticsOptions().options).to.deep.equal(configOptions);
+ expect(greenbidsAnalyticsAdapter.getAnalyticsOptions().pbuid).to.equal(configOptions.pbuid);
+ });
+
+ it('should not enable Analytics when pbuid is missing', function () {
+ const configOptions = {
+ options: {
+ }
+ };
+ const validConfig = greenbidsAnalyticsAdapter.initConfig(configOptions);
+ expect(validConfig).to.equal(false);
+ });
+ });
+
describe('event tracking and message cache manager', function () {
beforeEach(function () {
const configOptions = {
pbuid: pbuid,
- sampling: 0,
+ greenbidsSampling: 1,
};
greenbidsAnalyticsAdapter.enableAnalytics({
@@ -30,43 +64,6 @@ describe('Greenbids Prebid AnalyticsAdapter Testing', function () {
greenbidsAnalyticsAdapter.disableAnalytics();
});
- describe('#parseBidderCode()', function() {
- it('should get lower case bidder code from bidderCode field value', function() {
- const receivedBids = [
- {
- auctionId: auctionId,
- adUnitCode: 'adunit_1',
- bidder: 'greenbids',
- bidderCode: 'GREENBIDS',
- requestId: 'a1b2c3d4',
- timeToRespond: 72,
- cpm: 0.1,
- currency: 'USD',
- ad: 'fake ad1'
- },
- ];
- const result = parseBidderCode(receivedBids[0]);
- expect(result).to.equal('greenbids');
- });
- it('should get lower case bidder code from bidder field value as bidderCode field is missing', function() {
- const receivedBids = [
- {
- auctionId: auctionId,
- adUnitCode: 'adunit_1',
- bidder: 'greenbids',
- bidderCode: '',
- requestId: 'a1b2c3d4',
- timeToRespond: 72,
- cpm: 0.1,
- currency: 'USD',
- ad: 'fake ad1'
- },
- ];
- const result = parseBidderCode(receivedBids[0]);
- expect(result).to.equal('greenbids');
- });
- });
-
describe('#getCachedAuction()', function() {
const existing = {timeoutBids: [{}]};
greenbidsAnalyticsAdapter.cachedAuctions['test_auction_id'] = existing;
@@ -146,7 +143,7 @@ describe('Greenbids Prebid AnalyticsAdapter Testing', function () {
auctionId: auctionId,
pbuid: pbuid,
referrer: window.location.href,
- sampling: 0,
+ sampling: 1,
prebid: '$prebid.version$',
});
}
@@ -246,6 +243,13 @@ describe('Greenbids Prebid AnalyticsAdapter Testing', function () {
skip: 1,
protocols: [1, 2, 3, 4]
},
+ },
+ ortb2Imp: {
+ ext: {
+ data: {
+ adunitDFP: 'adunitcustomPathExtension'
+ }
+ }
}
},
],
@@ -253,7 +257,9 @@ describe('Greenbids Prebid AnalyticsAdapter Testing', function () {
noBids: noBids
};
+ sinon.stub(greenbidsAnalyticsAdapter, 'getCachedAuction').returns({timeoutBids: timeoutBids});
const result = greenbidsAnalyticsAdapter.createBidMessage(args, timeoutBids);
+ greenbidsAnalyticsAdapter.getCachedAuction.restore();
assertHavingRequiredMessageFields(result);
expect(result).to.deep.include({
@@ -266,6 +272,7 @@ describe('Greenbids Prebid AnalyticsAdapter Testing', function () {
sizes: [[300, 250], [300, 600]]
}
},
+ ortb2Imp: {},
bidders: [
{
bidder: 'greenbids',
@@ -281,6 +288,13 @@ describe('Greenbids Prebid AnalyticsAdapter Testing', function () {
},
{
code: 'adunit-2',
+ ortb2Imp: {
+ ext: {
+ data: {
+ adunitDFP: 'adunitcustomPathExtension'
+ }
+ }
+ },
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
@@ -315,7 +329,7 @@ describe('Greenbids Prebid AnalyticsAdapter Testing', function () {
timeout: 3000,
auctionEnd: 1234567990,
bidsReceived: receivedBids,
- noBids: noBids
+ noBids: noBids,
}];
greenbidsAnalyticsAdapter.handleBidTimeout(args);
@@ -338,7 +352,7 @@ describe('Greenbids Prebid AnalyticsAdapter Testing', function () {
describe('greenbids Analytics Adapter track handler ', function () {
const configOptions = {
pbuid: pbuid,
- sampling: 1,
+ greenbidsSampling: 1,
};
beforeEach(function () {
@@ -354,50 +368,60 @@ describe('Greenbids Prebid AnalyticsAdapter Testing', function () {
events.getEvents.restore();
});
+ it('should call handleAuctionInit as AUCTION_INIT trigger event', function() {
+ sinon.spy(greenbidsAnalyticsAdapter, 'handleAuctionInit');
+ events.emit(constants.EVENTS.AUCTION_INIT, {auctionId: 'auctionId'});
+ sinon.assert.callCount(greenbidsAnalyticsAdapter.handleAuctionInit, 1);
+ greenbidsAnalyticsAdapter.handleAuctionInit.restore();
+ });
+
it('should call handleBidTimeout as BID_TIMEOUT trigger event', function() {
sinon.spy(greenbidsAnalyticsAdapter, 'handleBidTimeout');
- events.emit(constants.EVENTS.BID_TIMEOUT, {});
+ events.emit(constants.EVENTS.BID_TIMEOUT, {auctionId: 'auctionId'});
sinon.assert.callCount(greenbidsAnalyticsAdapter.handleBidTimeout, 1);
greenbidsAnalyticsAdapter.handleBidTimeout.restore();
});
it('should call handleAuctionEnd as AUCTION_END trigger event', function() {
sinon.spy(greenbidsAnalyticsAdapter, 'handleAuctionEnd');
- events.emit(constants.EVENTS.AUCTION_END, {});
+ events.emit(constants.EVENTS.AUCTION_END, {auctionId: 'auctionId'});
sinon.assert.callCount(greenbidsAnalyticsAdapter.handleAuctionEnd, 1);
greenbidsAnalyticsAdapter.handleAuctionEnd.restore();
});
+
+ it('should call handleBillable as BILLABLE_EVENT trigger event', function() {
+ sinon.spy(greenbidsAnalyticsAdapter, 'handleBillable');
+ events.emit(constants.EVENTS.BILLABLE_EVENT, {
+ type: 'auction',
+ billingId: generateUUID(),
+ auctionId: 'auctionId',
+ vendor: 'greenbidsRtdProvider'
+ });
+ sinon.assert.callCount(greenbidsAnalyticsAdapter.handleBillable, 1);
+ greenbidsAnalyticsAdapter.handleBillable.restore();
+ });
});
- describe('enableAnalytics and config parser', function () {
- const configOptions = {
- pbuid: pbuid,
- sampling: 0,
- };
+ describe('isSampled', function() {
+ it('should return true for invalid sampling rates', function() {
+ expect(isSampled('ce1f3692-632c-4cfd-9e40-0c2ad625ec56', -1, 0.0)).to.be.true;
+ expect(isSampled('ce1f3692-632c-4cfd-9e40-0c2ad625ec56', 1.2, 0.0)).to.be.true;
+ });
- beforeEach(function () {
- greenbidsAnalyticsAdapter.enableAnalytics({
- provider: 'greenbidsAnalytics',
- options: configOptions
- });
+ it('should return determinist falsevalue for valid sampling rate given the predifined id and rate', function() {
+ expect(isSampled('ce1f3692-632c-4cfd-9e40-0c2ad625ec56', 0.0001, 0.0)).to.be.false;
});
- afterEach(function () {
- greenbidsAnalyticsAdapter.disableAnalytics();
+ it('should return determinist true value for valid sampling rate given the predifined id and rate', function() {
+ expect(isSampled('ce1f3692-632c-4cfd-9e40-0c2ad625ec56', 0.9999, 0.0)).to.be.true;
});
- it('should parse config correctly with optional values', function () {
- expect(greenbidsAnalyticsAdapter.getAnalyticsOptions().options).to.deep.equal(configOptions);
- expect(greenbidsAnalyticsAdapter.getAnalyticsOptions().pbuid).to.equal(configOptions.pbuid);
+ it('should return determinist true value for valid sampling rate given the predifined id and rate when we split to non exploration first', function() {
+ expect(isSampled('ce1f3692-632c-4cfd-9e40-0c2ad625ec56', 0.9999, 0.0, 1.0)).to.be.true;
});
- it('should not enable Analytics when pbuid is missing', function () {
- const configOptions = {
- options: {
- }
- };
- const validConfig = greenbidsAnalyticsAdapter.initConfig(configOptions);
- expect(validConfig).to.equal(false);
+ it('should return determinist false value for valid sampling rate given the predifined id and rate when we split to non exploration first', function() {
+ expect(isSampled('ce1f3692-632c-4cfd-9e40-0c2ad625ec56', 0.0001, 0.0, 1.0)).to.be.false;
});
});
});
diff --git a/test/spec/modules/greenbidsRtdProvider_spec.js b/test/spec/modules/greenbidsRtdProvider_spec.js
index cd93e9013c0..d0083d4dc7a 100644
--- a/test/spec/modules/greenbidsRtdProvider_spec.js
+++ b/test/spec/modules/greenbidsRtdProvider_spec.js
@@ -6,7 +6,9 @@ import {
import {
greenbidsSubmodule
} from 'modules/greenbidsRtdProvider.js';
-import {server} from '../../mocks/xhr.js';
+import { server } from '../../mocks/xhr.js';
+import * as events from '../../../src/events.js';
+import CONSTANTS from '../../../src/constants.json';
describe('greenbidsRtdProvider', () => {
const endPoint = 't.greenbids.ai';
@@ -39,14 +41,36 @@ describe('greenbidsRtdProvider', () => {
}]
};
- const SAMPLE_RESPONSE_ADUNITS = [
+ const SAMPLE_RESPONSE_ADUNITS_NOT_EXPLORED = [
{
code: 'adUnit1',
bidders: {
'appnexus': true,
'rubicon': false,
'ix': true
- }
+ },
+ isExploration: false
+ },
+ {
+ code: 'adUnit2',
+ bidders: {
+ 'appnexus': false,
+ 'rubicon': true,
+ 'openx': true
+ },
+ isExploration: false
+
+ }];
+
+ const SAMPLE_RESPONSE_ADUNITS_EXPLORED = [
+ {
+ code: 'adUnit1',
+ bidders: {
+ 'appnexus': true,
+ 'rubicon': false,
+ 'ix': true
+ },
+ isExploration: true
},
{
code: 'adUnit2',
@@ -54,7 +78,9 @@ describe('greenbidsRtdProvider', () => {
'appnexus': false,
'rubicon': true,
'openx': true
- }
+ },
+ isExploration: true
+
}];
describe('init', () => {
@@ -70,22 +96,37 @@ describe('greenbidsRtdProvider', () => {
});
describe('updateAdUnitsBasedOnResponse', () => {
- it('should update ad units based on response', () => {
+ it('should update ad units based on response if not exploring', () => {
const adUnits = JSON.parse(JSON.stringify(SAMPLE_REQUEST_BIDS_CONFIG_OBJ.adUnits));
- greenbidsSubmodule.updateAdUnitsBasedOnResponse(adUnits, SAMPLE_RESPONSE_ADUNITS);
+ greenbidsSubmodule.updateAdUnitsBasedOnResponse(adUnits, SAMPLE_RESPONSE_ADUNITS_NOT_EXPLORED);
expect(adUnits[0].bids).to.have.length(2);
expect(adUnits[1].bids).to.have.length(2);
});
+
+ it('should not update ad units based on response if exploring', () => {
+ const adUnits = JSON.parse(JSON.stringify(SAMPLE_REQUEST_BIDS_CONFIG_OBJ.adUnits));
+ greenbidsSubmodule.updateAdUnitsBasedOnResponse(adUnits, SAMPLE_RESPONSE_ADUNITS_EXPLORED);
+
+ expect(adUnits[0].bids).to.have.length(3);
+ expect(adUnits[1].bids).to.have.length(3);
+ expect(adUnits[0].ortb2Imp.ext.greenbids.greenbidsId).to.be.a.string;
+ expect(adUnits[1].ortb2Imp.ext.greenbids.greenbidsId).to.be.a.string;
+ expect(adUnits[0].ortb2Imp.ext.greenbids.greenbidsId).to.equal(adUnits[0].ortb2Imp.ext.greenbids.greenbidsId);
+ expect(adUnits[0].ortb2Imp.ext.greenbids.keptInAuction).to.deep.equal(SAMPLE_RESPONSE_ADUNITS_EXPLORED[0].bidders);
+ expect(adUnits[1].ortb2Imp.ext.greenbids.keptInAuction).to.deep.equal(SAMPLE_RESPONSE_ADUNITS_EXPLORED[1].bidders);
+ expect(adUnits[0].ortb2Imp.ext.greenbids.isExploration).to.equal(SAMPLE_RESPONSE_ADUNITS_EXPLORED[0].isExploration);
+ expect(adUnits[1].ortb2Imp.ext.greenbids.isExploration).to.equal(SAMPLE_RESPONSE_ADUNITS_EXPLORED[1].isExploration);
+ });
});
describe('findMatchingAdUnit', () => {
it('should find matching ad unit by code', () => {
- const matchingAdUnit = greenbidsSubmodule.findMatchingAdUnit(SAMPLE_RESPONSE_ADUNITS, 'adUnit1');
- expect(matchingAdUnit).to.deep.equal(SAMPLE_RESPONSE_ADUNITS[0]);
+ const matchingAdUnit = greenbidsSubmodule.findMatchingAdUnit(SAMPLE_RESPONSE_ADUNITS_NOT_EXPLORED, 'adUnit1');
+ expect(matchingAdUnit).to.deep.equal(SAMPLE_RESPONSE_ADUNITS_NOT_EXPLORED[0]);
});
it('should return undefined if no matching ad unit is found', () => {
- const matchingAdUnit = greenbidsSubmodule.findMatchingAdUnit(SAMPLE_RESPONSE_ADUNITS, 'nonexistent');
+ const matchingAdUnit = greenbidsSubmodule.findMatchingAdUnit(SAMPLE_RESPONSE_ADUNITS_NOT_EXPLORED, 'nonexistent');
expect(matchingAdUnit).to.be.undefined;
});
});
@@ -93,7 +134,7 @@ describe('greenbidsRtdProvider', () => {
describe('removeFalseBidders', () => {
it('should remove bidders with false value', () => {
const adUnit = JSON.parse(JSON.stringify(SAMPLE_REQUEST_BIDS_CONFIG_OBJ.adUnits[0]));
- const matchingAdUnit = SAMPLE_RESPONSE_ADUNITS[0];
+ const matchingAdUnit = SAMPLE_RESPONSE_ADUNITS_NOT_EXPLORED[0];
greenbidsSubmodule.removeFalseBidders(adUnit, matchingAdUnit);
expect(adUnit.bids).to.have.length(2);
expect(adUnit.bids.map((bid) => bid.bidder)).to.not.include('rubicon');
@@ -125,14 +166,15 @@ describe('greenbidsRtdProvider', () => {
setTimeout(() => {
server.requests[0].respond(
200,
- {'Content-Type': 'application/json'},
- JSON.stringify(SAMPLE_RESPONSE_ADUNITS)
+ { 'Content-Type': 'application/json' },
+ JSON.stringify(SAMPLE_RESPONSE_ADUNITS_NOT_EXPLORED)
);
}, 50);
setTimeout(() => {
const requestUrl = new URL(server.requests[0].url);
expect(requestUrl.host).to.be.eq(endPoint);
+ expect(requestBids.greenbidsId).to.be.a.string;
expect(requestBids.adUnits[0].bids).to.have.length(2);
expect(requestBids.adUnits[0].bids.map((bid) => bid.bidder)).to.not.include('rubicon');
expect(requestBids.adUnits[0].bids.map((bid) => bid.bidder)).to.include('ix');
@@ -157,8 +199,8 @@ describe('greenbidsRtdProvider', () => {
setTimeout(() => {
server.requests[0].respond(
200,
- {'Content-Type': 'application/json'},
- JSON.stringify(SAMPLE_RESPONSE_ADUNITS)
+ { 'Content-Type': 'application/json' },
+ JSON.stringify(SAMPLE_RESPONSE_ADUNITS_NOT_EXPLORED)
);
done();
}, 300);
@@ -166,6 +208,7 @@ describe('greenbidsRtdProvider', () => {
setTimeout(() => {
const requestUrl = new URL(server.requests[0].url);
expect(requestUrl.host).to.be.eq(endPoint);
+ expect(requestBids.greenbidsId).to.be.a.string;
expect(requestBids.adUnits[0].bids).to.have.length(3);
expect(requestBids.adUnits[1].bids).to.have.length(3);
expect(callback.calledOnce).to.be.true;
@@ -183,14 +226,15 @@ describe('greenbidsRtdProvider', () => {
setTimeout(() => {
server.requests[0].respond(
500,
- {'Content-Type': 'application/json'},
- JSON.stringify({'failure': 'fail'})
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({ 'failure': 'fail' })
);
}, 50);
setTimeout(() => {
const requestUrl = new URL(server.requests[0].url);
expect(requestUrl.host).to.be.eq(endPoint);
+ expect(requestBids.greenbidsId).to.be.a.string;
expect(requestBids.adUnits[0].bids).to.have.length(3);
expect(requestBids.adUnits[1].bids).to.have.length(3);
expect(callback.calledOnce).to.be.true;
@@ -198,4 +242,116 @@ describe('greenbidsRtdProvider', () => {
}, 60);
});
});
+
+ describe('stripAdUnits', function () {
+ it('should strip all properties except bidder from each bid in adUnits', function () {
+ const adUnits =
+ [
+ {
+ bids: [
+ { bidder: 'bidder1', otherProp: 'value1' },
+ { bidder: 'bidder2', otherProp: 'value2' }
+ ],
+ mediaTypes: { 'banner': { prop: 'value3' } }
+ }
+ ];
+ const expectedOutput = [
+ {
+ bids: [
+ { bidder: 'bidder1' },
+ { bidder: 'bidder2' }
+ ],
+ mediaTypes: { 'banner': { prop: 'value3' } }
+ }
+ ];
+
+ // Perform the test
+ const output = greenbidsSubmodule.stripAdUnits(adUnits);
+ expect(output).to.deep.equal(expectedOutput);
+ });
+
+ it('should strip all properties except bidder from each bid in adUnits but keep ortb2Imp', function () {
+ const adUnits =
+ [
+ {
+ bids: [
+ { bidder: 'bidder1', otherProp: 'value1' },
+ { bidder: 'bidder2', otherProp: 'value2' }
+ ],
+ mediaTypes: { 'banner': { prop: 'value3' } },
+ ortb2Imp: {
+ ext: {
+ greenbids: {
+ greenbidsId: 'test'
+ }
+ }
+ }
+ }
+ ];
+ const expectedOutput = [
+ {
+ bids: [
+ { bidder: 'bidder1' },
+ { bidder: 'bidder2' }
+ ],
+ mediaTypes: { 'banner': { prop: 'value3' } },
+ ortb2Imp: {
+ ext: {
+ greenbids: {
+ greenbidsId: 'test'
+ }
+ }
+ }
+ }
+ ];
+
+ // Perform the test
+ const output = greenbidsSubmodule.stripAdUnits(adUnits);
+ expect(output).to.deep.equal(expectedOutput);
+ });
+ });
+
+ describe('onAuctionInitEvent', function () {
+ it('should not emit billable event if greenbids hasn\'t set the adunit.ext value', function () {
+ sinon.spy(events, 'emit');
+ greenbidsSubmodule.onAuctionInitEvent({
+ auctionId: 'test',
+ adUnits: [
+ {
+ bids: [
+ { bidder: 'bidder1', otherProp: 'value1' },
+ { bidder: 'bidder2', otherProp: 'value2' }
+ ],
+ mediaTypes: { 'banner': { prop: 'value3' } },
+ }
+ ]
+ });
+ sinon.assert.callCount(events.emit, 0);
+ events.emit.restore();
+ });
+
+ it('should emit billable event if greenbids has set the adunit.ext value', function (done) {
+ let counter = 0;
+ events.on(CONSTANTS.EVENTS.BILLABLE_EVENT, function (event) {
+ if (event.vendor === 'greenbidsRtdProvider' && event.type === 'auction') {
+ counter += 1;
+ }
+ expect(counter).to.equal(1);
+ done();
+ });
+ greenbidsSubmodule.onAuctionInitEvent({
+ auctionId: 'test',
+ adUnits: [
+ {
+ bids: [
+ { bidder: 'bidder1', otherProp: 'value1' },
+ { bidder: 'bidder2', otherProp: 'value2' }
+ ],
+ mediaTypes: { 'banner': { prop: 'value3' } },
+ ortb2Imp: { ext: { greenbids: { greenbidsId: 'b0b39610-b941-4659-a87c-de9f62d3e13e' } } }
+ }
+ ]
+ });
+ });
+ });
});
diff --git a/test/spec/modules/gridBidAdapter_spec.js b/test/spec/modules/gridBidAdapter_spec.js
index b12083236a2..abaa4b37fcd 100644
--- a/test/spec/modules/gridBidAdapter_spec.js
+++ b/test/spec/modules/gridBidAdapter_spec.js
@@ -1352,7 +1352,7 @@ describe('TheMediaGrid Adapter', function () {
it('complicated case', function () {
const fullResponse = [
- {'bid': [{'impid': '2164be6358b9', 'adid': '32_52_7543', 'price': 1.15, 'adm': '
test content 1
', 'auid': 1, 'h': 250, 'w': 300, dealid: 11}], 'seat': '1'},
+ {'bid': [{'impid': '2164be6358b9', 'adid': '32_52_7543', 'price': 1.15, 'adm': '
test content 1
', 'auid': 1, 'h': 250, 'w': 300, dealid: 11, 'ext': {'dsa': {'adrender': 1}}}], 'seat': '1'},
{'bid': [{'impid': '4e111f1b66e4', 'adid': '32_54_4535', 'price': 0.5, 'adm': '
test content 2
', 'auid': 2, 'h': 600, 'w': 300, dealid: 12}], 'seat': '1'},
{'bid': [{'impid': '26d6f897b516', 'adid': '32_53_75467', 'price': 0.15, 'adm': '
test content 3
', 'auid': 1, 'h': 90, 'w': 728}], 'seat': '1'},
{'bid': [{'impid': '326bde7fbf69', 'adid': '32_54_12342', 'price': 0.15, 'adm': '
test content 4
', 'auid': 1, 'h': 600, 'w': 300}], 'seat': '1'},
@@ -1430,6 +1430,7 @@ describe('TheMediaGrid Adapter', function () {
'netRevenue': true,
'ttl': 360,
'meta': {
+ adrender: 1,
advertiserDomains: []
},
},
@@ -1559,37 +1560,9 @@ describe('TheMediaGrid Adapter', function () {
});
it('should send right request on onDataDeletionRequest call', function() {
- spec.onDataDeletionRequest([{
- bids: [
- {
- bidder: 'grid',
- params: {
- uid: 1
- }
- },
- {
- bidder: 'grid',
- params: {
- uid: 2
- }
- },
- {
- bidder: 'another',
- params: {
- uid: 3
- }
- },
- {
- bidder: 'gridNM',
- params: {
- uid: 4
- }
- }
- ],
- }]);
+ spec.onDataDeletionRequest([{}]);
expect(ajaxStub.calledOnce).to.equal(true);
- expect(ajaxStub.firstCall.args[0]).to.equal('https://media.grid.bidswitch.net/uspapi_delete');
- expect(ajaxStub.firstCall.args[2]).to.equal('{"uids":[1,2,4]}');
+ expect(ajaxStub.firstCall.args[0]).to.equal('https://media.grid.bidswitch.net/uspapi_delete_c2s');
});
});
diff --git a/test/spec/modules/growthCodeIdSystem_spec.js b/test/spec/modules/growthCodeIdSystem_spec.js
index 97083047d4e..e3848dc4844 100644
--- a/test/spec/modules/growthCodeIdSystem_spec.js
+++ b/test/spec/modules/growthCodeIdSystem_spec.js
@@ -6,9 +6,12 @@ import {expect} from 'chai';
import {getStorageManager} from '../../../src/storageManager.js';
import {MODULE_TYPE_UID} from '../../../src/activities/modules.js';
-const GCID_EXPIRY = 45;
const MODULE_NAME = 'growthCodeId';
-const SHAREDID = 'fe9c5c89-7d56-4666-976d-e07e73b3b664';
+const EIDS = '[{"source":"domain.com","uids":[{"id":"8212212191539393121","ext":{"stype":"ppuid"}}]}]';
+const GCID = 'e06e9e5a-273c-46f8-aace-6f62cf13ea71'
+
+const GCID_EID = '{"id": [{"source": "growthcode.io", "uids": [{"atype": 3,"id": "e06e9e5a-273c-46f8-aace-6f62cf13ea71"}]}]}'
+const GCID_EID_EID = '{"id": [{"source": "growthcode.io", "uids": [{"atype": 3,"id": "e06e9e5a-273c-46f8-aace-6f62cf13ea71"}]},{"source": "domain.com", "uids": [{"id": "8212212191539393121", "ext": {"stype":"ppuid"}}]}]}'
const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME });
@@ -23,11 +26,8 @@ describe('growthCodeIdSystem', () => {
beforeEach(function () {
logErrorStub = sinon.stub(utils, 'logError');
- storage.setDataInLocalStorage('_sharedid', SHAREDID);
- const expiresStr = (new Date(Date.now() + (GCID_EXPIRY * (60 * 60 * 24 * 1000)))).toUTCString();
- if (storage.cookiesAreEnabled()) {
- storage.setCookie('_sharedid', SHAREDID, expiresStr, 'LAX');
- }
+ storage.setDataInLocalStorage('gcid', GCID, null);
+ storage.setDataInLocalStorage('customerEids', EIDS, null);
});
afterEach(function () {
@@ -40,45 +40,33 @@ describe('growthCodeIdSystem', () => {
});
});
- it('should NOT call the growthcode id endpoint if gdpr applies but consent string is missing', function () {
- let submoduleCallback = growthCodeIdSubmodule.getId(getIdParams, { gdprApplies: true }, undefined);
- expect(submoduleCallback).to.be.undefined;
- });
-
- it('should log an error if pid configParam was not passed when getId', function () {
- growthCodeIdSubmodule.getId();
- expect(logErrorStub.callCount).to.be.equal(1);
+ it('test return of GCID', function () {
+ let ids;
+ ids = growthCodeIdSubmodule.getId();
+ expect(ids).to.deep.equal(JSON.parse(GCID_EID));
});
- it('should log an error if sharedId (LocalStore) is not setup correctly', function () {
- growthCodeIdSubmodule.getId({params: {
- pid: 'TEST01',
- publisher_id: '_sharedid_bad',
- publisher_id_storage: 'html5',
+ it('test return of the GCID and an additional EID', function () {
+ let ids;
+ ids = growthCodeIdSubmodule.getId({params: {
+ customerEids: 'customerEids',
}});
- expect(logErrorStub.callCount).to.be.equal(1);
+ expect(ids).to.deep.equal(JSON.parse(GCID_EID_EID));
});
- it('should log an error if sharedId (LocalStore) is not setup correctly', function () {
- growthCodeIdSubmodule.getId({params: {
- pid: 'TEST01',
- publisher_id: '_sharedid_bad',
- publisher_id_storage: 'cookie',
+ it('test return of the GCID and an additional EID (bad Local Store name)', function () {
+ let ids;
+ ids = growthCodeIdSubmodule.getId({params: {
+ customerEids: 'customerEidsBad',
}});
- expect(logErrorStub.callCount).to.be.equal(1);
+ expect(ids).to.deep.equal(JSON.parse(GCID_EID));
});
- it('should call the growthcode id endpoint', function () {
- let callBackSpy = sinon.spy();
- let submoduleCallback = growthCodeIdSubmodule.getId(getIdParams).callback;
- submoduleCallback(callBackSpy);
- let request = server.requests[0];
- expect(request.url.substr(0, 85)).to.be.eq('https://p2.gcprivacy.com/v1/pb?pid=TEST01&uid=' + SHAREDID + '&u=');
- request.respond(
- 200,
- {},
- JSON.stringify({})
- );
- expect(callBackSpy.calledOnce).to.be.true;
+ it('test decode function)', function () {
+ let ids;
+ ids = growthCodeIdSubmodule.decode(GCID, {params: {
+ customerEids: 'customerEids',
+ }});
+ expect(ids).to.deep.equal(JSON.parse('{"growthCodeId":"' + GCID + '"}'));
});
})
diff --git a/test/spec/modules/gumgumBidAdapter_spec.js b/test/spec/modules/gumgumBidAdapter_spec.js
index 2b12547ca8f..29e372d0f87 100644
--- a/test/spec/modules/gumgumBidAdapter_spec.js
+++ b/test/spec/modules/gumgumBidAdapter_spec.js
@@ -121,6 +121,30 @@ describe('gumgumAdapter', function () {
}
}
},
+ pubProvidedId: [
+ {
+ uids: [
+ {
+ ext: {
+ stype: 'ppuid',
+ },
+ id: 'aac4504f-ef89-401b-a891-ada59db44336',
+ },
+ ],
+ source: 'sonobi.com',
+ },
+ {
+ uids: [
+ {
+ ext: {
+ stype: 'ppuid',
+ },
+ id: 'y-zqTHmW9E2uG3jEETC6i6BjGcMhPXld2F~A',
+ },
+ ],
+ source: 'aol.com',
+ },
+ ],
adUnitCode: 'adunit-code',
sizes: sizesArray,
bidId: '30b31c1838de1e',
@@ -157,6 +181,7 @@ describe('gumgumAdapter', function () {
linearity: 1,
startdelay: 1,
placement: 123456,
+ plcmt: 3,
protocols: [1, 2]
}
};
@@ -167,6 +192,13 @@ describe('gumgumAdapter', function () {
const request = { ...bidRequests[0] };
const bidRequest = spec.buildRequests([request])[0];
expect(bidRequest.data.aun).to.equal(bidRequests[0].adUnitCode);
+ expect(bidRequest.data.displaymanager).to.equal('Prebid.js - gumgum');
+ expect(bidRequest.data.displaymanagerver).to.equal(JCSI.pbv);
+ });
+ it('should set pubProvidedId if the uid and pubProvidedId are available', function () {
+ const request = { ...bidRequests[0] };
+ const bidRequest = spec.buildRequests([request])[0];
+ expect(bidRequest.data.pubProvidedId).to.equal(JSON.stringify(bidRequests[0].userId.pubProvidedId));
});
it('should set id5Id and id5IdLinkType if the uid and linkType are available', function () {
const request = { ...bidRequests[0] };
@@ -267,6 +299,14 @@ describe('gumgumAdapter', function () {
expect(bidRequest.data.gpid).to.equal(pbadslot);
});
+ it('should set the global placement id (gpid) if media type is video', function () {
+ const pbadslot = 'cde456'
+ const req = { ...bidRequests[0], ortb2Imp: { ext: { data: { pbadslot } } }, params: zoneParam, mediaTypes: vidMediaTypes }
+ const bidRequest = spec.buildRequests([req])[0];
+ expect(bidRequest.data).to.have.property('gpid');
+ expect(bidRequest.data.gpid).to.equal(pbadslot);
+ });
+
it('should set the bid floor if getFloor module is not present but static bid floor is defined', function () {
const req = { ...bidRequests[0], params: { bidfloor: 42 } }
const bidRequest = spec.buildRequests([req])[0];
@@ -428,6 +468,7 @@ describe('gumgumAdapter', function () {
linearity: 1,
startdelay: 1,
placement: 123456,
+ plcmt: 3,
protocols: [1, 2]
};
const request = Object.assign({}, bidRequests[0]);
@@ -446,6 +487,7 @@ describe('gumgumAdapter', function () {
expect(bidRequest.data.li).to.eq(videoVals.linearity);
expect(bidRequest.data.sd).to.eq(videoVals.startdelay);
expect(bidRequest.data.pt).to.eq(videoVals.placement);
+ expect(bidRequest.data.vplcmt).to.eq(videoVals.plcmt);
expect(bidRequest.data.pr).to.eq(videoVals.protocols.join(','));
expect(bidRequest.data.viw).to.eq(videoVals.playerSize[0].toString());
expect(bidRequest.data.vih).to.eq(videoVals.playerSize[1].toString());
@@ -459,6 +501,7 @@ describe('gumgumAdapter', function () {
linearity: 1,
startdelay: 1,
placement: 123456,
+ plcmt: 3,
protocols: [1, 2]
};
const request = Object.assign({}, bidRequests[0]);
@@ -477,6 +520,7 @@ describe('gumgumAdapter', function () {
expect(bidRequest.data.li).to.eq(inVideoVals.linearity);
expect(bidRequest.data.sd).to.eq(inVideoVals.startdelay);
expect(bidRequest.data.pt).to.eq(inVideoVals.placement);
+ expect(bidRequest.data.vplcmt).to.eq(inVideoVals.plcmt);
expect(bidRequest.data.pr).to.eq(inVideoVals.protocols.join(','));
expect(bidRequest.data.viw).to.eq(inVideoVals.playerSize[0].toString());
expect(bidRequest.data.vih).to.eq(inVideoVals.playerSize[1].toString());
@@ -488,6 +532,12 @@ describe('gumgumAdapter', function () {
expect(request.data).to.not.include.any.keys('eAdBuyId');
expect(request.data).to.not.include.any.keys('adBuyId');
});
+ it('should set pubProvidedId if the uid and pubProvidedId are available', function () {
+ const request = { ...bidRequests[0] };
+ const bidRequest = spec.buildRequests([request])[0];
+ expect(bidRequest.data.pubProvidedId).to.equal(JSON.stringify(bidRequests[0].userId.pubProvidedId));
+ });
+
it('should add gdpr consent parameters if gdprConsent is present', function () {
const gdprConsent = { consentString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', gdprApplies: true };
const fakeBidRequest = { gdprConsent: gdprConsent };
@@ -832,6 +882,19 @@ describe('gumgumAdapter', function () {
expect(result.height = expectedSize[1]);
})
+ it('request size that matches response size for in-slot', function () {
+ const request = { ...bidRequest };
+ const body = { ...serverResponse };
+ const expectedSize = [[ 320, 50 ], [300, 600], [300, 250]];
+ let result;
+ request.pi = 3;
+ body.ad.width = 300;
+ body.ad.height = 600;
+ result = spec.interpretResponse({ body }, request)[0];
+ expect(result.width = expectedSize[1][0]);
+ expect(result.height = expectedSize[1][1]);
+ })
+
it('defaults to use bidRequest sizes', function () {
const { ad, jcsi, pag, thms, meta } = serverResponse
const noAdSizes = { ...ad }
diff --git a/test/spec/modules/hadronIdSystem_spec.js b/test/spec/modules/hadronIdSystem_spec.js
index cc0118d4659..85c8cc11c9e 100644
--- a/test/spec/modules/hadronIdSystem_spec.js
+++ b/test/spec/modules/hadronIdSystem_spec.js
@@ -22,7 +22,7 @@ describe('HadronIdSystem', function () {
const callback = hadronIdSubmodule.getId(config).callback;
callback(callbackSpy);
const request = server.requests[0];
- expect(request.url).to.eq(`https://id.hadron.ad.gt/api/v1/pbhid?partner_id=0&_it=prebid`);
+ expect(request.url).to.match(/^https:\/\/id\.hadron\.ad\.gt\/api\/v1\/pbhid/);
request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({ hadronId: 'testHadronId1' }));
expect(callbackSpy.lastCall.lastArg).to.deep.equal({ id: { hadronId: 'testHadronId1' } });
});
@@ -47,7 +47,7 @@ describe('HadronIdSystem', function () {
const callback = hadronIdSubmodule.getId(config).callback;
callback(callbackSpy);
const request = server.requests[0];
- expect(request.url).to.eq('https://hadronid.publync.com/?partner_id=0&_it=prebid');
+ expect(request.url).to.match(/^https:\/\/hadronid\.publync\.com\//);
request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({ hadronId: 'testHadronId1' }));
expect(callbackSpy.lastCall.lastArg).to.deep.equal({ id: { hadronId: 'testHadronId1' } });
});
diff --git a/test/spec/modules/hypelabBidAdapter_spec.js b/test/spec/modules/hypelabBidAdapter_spec.js
index 4522073a2db..28d0739de79 100644
--- a/test/spec/modules/hypelabBidAdapter_spec.js
+++ b/test/spec/modules/hypelabBidAdapter_spec.js
@@ -92,7 +92,7 @@ const mockBidRequest = {
placement_slug: 'test_placement',
provider_version: '0.0.1',
provider_name: 'prebid',
- referrer: 'https://example.com',
+ location: 'https://example.com',
sdk_version: '7.51.0-pre',
sizes: [[728, 90]],
wids: [],
@@ -160,6 +160,9 @@ describe('hypelabBidAdapter', function () {
expect(data.bidRequestsCount).to.be.a('number');
expect(data.bidderRequestsCount).to.be.a('number');
expect(data.bidderWinsCount).to.be.a('number');
+ expect(data.dpr).to.be.a('number');
+ expect(data.location).to.be.a('string');
+ expect(data.floor).to.equal(null);
});
describe('should set uuid to the first id in userIdAsEids', () => {
@@ -211,6 +214,7 @@ describe('hypelabBidAdapter', function () {
expect(data.ad).to.be.a('string');
expect(data.mediaType).to.be.a('string');
expect(data.meta.advertiserDomains).to.be.an('array');
+ expect(data.meta.advertiserDomains[0]).to.be.a('string');
});
describe('should return a blank array if cpm is not set', () => {
diff --git a/test/spec/modules/id5IdSystem_spec.js b/test/spec/modules/id5IdSystem_spec.js
index 56b23ba9634..af468f2fe4d 100644
--- a/test/spec/modules/id5IdSystem_spec.js
+++ b/test/spec/modules/id5IdSystem_spec.js
@@ -1,26 +1,24 @@
+import * as id5System from '../../../modules/id5IdSystem.js';
import {
- expDaysStr,
- getFromLocalStorage,
- getNbFromCache,
- ID5_PRIVACY_STORAGE_NAME,
- ID5_STORAGE_NAME,
- id5IdSubmodule,
- nbCacheName,
- storage,
- storeInLocalStorage,
- storeNbInCache,
-} from 'modules/id5IdSystem.js';
-import {coreStorage, getConsentHash, init, requestBidsHook, setSubmoduleRegistry} from 'modules/userId/index.js';
-import {config} from 'src/config.js';
-import * as events from 'src/events.js';
-import CONSTANTS from 'src/constants.json';
-import * as utils from 'src/utils.js';
-import {uspDataHandler} from 'src/adapterManager.js';
-import 'src/prebid.js';
+ coreStorage,
+ getConsentHash,
+ init,
+ requestBidsHook,
+ setSubmoduleRegistry
+} from '../../../modules/userId/index.js';
+import {config} from '../../../src/config.js';
+import * as events from '../../../src/events.js';
+import CONSTANTS from '../../../src/constants.json';
+import * as utils from '../../../src/utils.js';
+import {uspDataHandler, gppDataHandler} from '../../../src/adapterManager.js';
+import '../../../src/prebid.js';
import {hook} from '../../../src/hook.js';
import {mockGdprConsent} from '../../helpers/consentData.js';
import {server} from '../../mocks/xhr.js';
import {expect} from 'chai';
+import {GreedyPromise} from '../../../src/utils/promise.js';
+
+const IdFetchFlow = id5System.IdFetchFlow;
describe('ID5 ID System', function () {
const ID5_MODULE_NAME = 'id5Id';
@@ -35,7 +33,6 @@ describe('ID5 ID System', function () {
url: ID5_ENDPOINT
}
};
- const ID5_NB_STORAGE_NAME = nbCacheName(ID5_TEST_PARTNER_ID);
const ID5_STORED_ID = 'storedid5id';
const ID5_STORED_SIGNATURE = '123456';
const ID5_STORED_LINK_TYPE = 1;
@@ -46,6 +43,22 @@ describe('ID5 ID System', function () {
'linkType': ID5_STORED_LINK_TYPE
}
};
+ const EUID_STORED_ID = 'EUID_1';
+ const EUID_SOURCE = 'uidapi.com';
+ const ID5_STORED_OBJ_WITH_EUID = {
+ 'universal_uid': ID5_STORED_ID,
+ 'signature': ID5_STORED_SIGNATURE,
+ 'ext': {
+ 'linkType': ID5_STORED_LINK_TYPE,
+ 'euid': {
+ 'source': EUID_SOURCE,
+ 'uids': [{
+ 'id': EUID_STORED_ID,
+ 'aType': 3
+ }]
+ }
+ }
+ };
const ID5_RESPONSE_ID = 'newid5id';
const ID5_RESPONSE_SIGNATURE = 'abcdef';
const ID5_RESPONSE_LINK_TYPE = 2;
@@ -74,11 +87,11 @@ describe('ID5 ID System', function () {
'Content-Type': 'application/json'
}
- function getId5FetchConfig(storageName = ID5_STORAGE_NAME, storageType = 'html5') {
+ function getId5FetchConfig(partner = ID5_TEST_PARTNER_ID, storageName = id5System.ID5_STORAGE_NAME, storageType = 'html5') {
return {
name: ID5_MODULE_NAME,
params: {
- partner: ID5_TEST_PARTNER_ID
+ partner
},
storage: {
name: storageName,
@@ -109,7 +122,7 @@ describe('ID5 ID System', function () {
}
function getFetchLocalStorageConfig() {
- return getUserSyncConfig([getId5FetchConfig(ID5_STORAGE_NAME, 'html5')]);
+ return getUserSyncConfig([getId5FetchConfig()]);
}
function getValueConfig(value) {
@@ -126,67 +139,66 @@ describe('ID5 ID System', function () {
}
function callSubmoduleGetId(config, consentData, cacheIdObj) {
- return new Promise((resolve) => {
- id5IdSubmodule.getId(config, consentData, cacheIdObj).callback((response) => {
- resolve(response)
- })
+ return new GreedyPromise((resolve) => {
+ id5System.id5IdSubmodule.getId(config, consentData, cacheIdObj).callback((response) => {
+ resolve(response);
+ });
});
}
class XhrServerMock {
+ currentRequestIdx = 0;
+ server;
+
constructor(server) {
- this.currentRequestIdx = 0
- this.server = server
+ this.currentRequestIdx = 0;
+ this.server = server;
}
- expectFirstRequest() {
- return this.#expectRequest(0);
+ async expectFirstRequest() {
+ return this.#waitOnRequest(0);
}
- expectNextRequest() {
- return this.#expectRequest(++this.currentRequestIdx)
+ async expectNextRequest() {
+ return this.#waitOnRequest(++this.currentRequestIdx);
}
- expectConfigRequest() {
- return this.expectFirstRequest()
- .then(configRequest => {
- expect(configRequest.url).is.eq(ID5_API_CONFIG_URL);
- expect(configRequest.method).is.eq('POST');
- return configRequest;
- })
+ async expectConfigRequest() {
+ const configRequest = await this.expectFirstRequest();
+ expect(configRequest.url).is.eq(ID5_API_CONFIG_URL);
+ expect(configRequest.method).is.eq('POST');
+ return configRequest;
}
- respondWithConfigAndExpectNext(configRequest, config = ID5_API_CONFIG) {
+ async respondWithConfigAndExpectNext(configRequest, config = ID5_API_CONFIG) {
configRequest.respond(200, HEADERS_CONTENT_TYPE_JSON, JSON.stringify(config));
- return this.expectNextRequest()
+ return this.expectNextRequest();
}
- expectFetchRequest() {
- return this.expectConfigRequest()
- .then(configRequest => {
- return this.respondWithConfigAndExpectNext(configRequest, ID5_API_CONFIG);
- }).then(request => {
- expect(request.url).is.eq(ID5_API_CONFIG.fetchCall.url);
- expect(request.method).is.eq('POST');
- return request;
- })
+ async expectFetchRequest() {
+ const configRequest = await this.expectFirstRequest();
+ const fetchRequest = await this.respondWithConfigAndExpectNext(configRequest);
+ expect(fetchRequest.method).is.eq('POST');
+ expect(fetchRequest.url).is.eq(ID5_API_CONFIG.fetchCall.url);
+ return fetchRequest;
}
- #expectRequest(index) {
- let server = this.server
- return new Promise(function (resolve) {
- (function waitForCondition() {
- if (server.requests && server.requests.length > index) return resolve(server.requests[index]);
- setTimeout(waitForCondition, 30);
- })();
- })
- .then(request => {
- return request
- });
+ async #waitOnRequest(index) {
+ const server = this.server
+ return new GreedyPromise((resolve) => {
+ const waitForCondition = () => {
+ if (server.requests && server.requests.length > index) {
+ resolve(server.requests[index]);
+ } else {
+ setTimeout(waitForCondition, 30);
+ }
+ };
+ waitForCondition();
+ });
}
hasReceivedAnyRequest() {
- let requests = this.server.requests;
+ const requests = this.server.requests;
return requests && requests.length > 0;
}
}
@@ -198,29 +210,29 @@ describe('ID5 ID System', function () {
describe('Check for valid publisher config', function () {
it('should fail with invalid config', function () {
// no config
- expect(id5IdSubmodule.getId()).is.eq(undefined);
- expect(id5IdSubmodule.getId({})).is.eq(undefined);
-
- // valid params, invalid storage
- expect(id5IdSubmodule.getId({ params: { partner: 123 } })).to.be.eq(undefined);
- expect(id5IdSubmodule.getId({ params: { partner: 123 }, storage: {} })).to.be.eq(undefined);
- expect(id5IdSubmodule.getId({ params: { partner: 123 }, storage: { name: '' } })).to.be.eq(undefined);
- expect(id5IdSubmodule.getId({ params: { partner: 123 }, storage: { type: '' } })).to.be.eq(undefined);
-
- // valid storage, invalid params
- expect(id5IdSubmodule.getId({ storage: { name: 'name', type: 'html5', }, })).to.be.eq(undefined);
- expect(id5IdSubmodule.getId({ storage: { name: 'name', type: 'html5', }, params: { } })).to.be.eq(undefined);
- expect(id5IdSubmodule.getId({ storage: { name: 'name', type: 'html5', }, params: { partner: 'abc' } })).to.be.eq(undefined);
+ expect(id5System.id5IdSubmodule.getId()).is.eq(undefined);
+ expect(id5System.id5IdSubmodule.getId({})).is.eq(undefined);
+
+ // valid params, invalid id5System.storage
+ expect(id5System.id5IdSubmodule.getId({ params: { partner: 123 } })).to.be.eq(undefined);
+ expect(id5System.id5IdSubmodule.getId({ params: { partner: 123 }, storage: {} })).to.be.eq(undefined);
+ expect(id5System.id5IdSubmodule.getId({ params: { partner: 123 }, storage: { name: '' } })).to.be.eq(undefined);
+ expect(id5System.id5IdSubmodule.getId({ params: { partner: 123 }, storage: { type: '' } })).to.be.eq(undefined);
+
+ // valid id5System.storage, invalid params
+ expect(id5System.id5IdSubmodule.getId({ storage: { name: 'name', type: 'html5', }, })).to.be.eq(undefined);
+ expect(id5System.id5IdSubmodule.getId({ storage: { name: 'name', type: 'html5', }, params: { } })).to.be.eq(undefined);
+ expect(id5System.id5IdSubmodule.getId({ storage: { name: 'name', type: 'html5', }, params: { partner: 'abc' } })).to.be.eq(undefined);
});
- it('should warn with non-recommended storage params', function () {
- let logWarnStub = sinon.stub(utils, 'logWarn');
+ it('should warn with non-recommended id5System.storage params', function () {
+ const logWarnStub = sinon.stub(utils, 'logWarn');
- id5IdSubmodule.getId({ storage: { name: 'name', type: 'html5', }, params: { partner: 123 } });
+ id5System.id5IdSubmodule.getId({ storage: { name: 'name', type: 'html5', }, params: { partner: 123 } });
expect(logWarnStub.calledOnce).to.be.true;
logWarnStub.restore();
- id5IdSubmodule.getId({ storage: { name: ID5_STORAGE_NAME, type: 'cookie', }, params: { partner: 123 } });
+ id5System.id5IdSubmodule.getId({ storage: { name: id5System.ID5_STORAGE_NAME, type: 'cookie', }, params: { partner: 123 } });
expect(logWarnStub.calledOnce).to.be.true;
logWarnStub.restore();
});
@@ -240,152 +252,150 @@ describe('ID5 ID System', function () {
dataConsentVals.forEach(function([purposeConsent, vendorConsent, caseName]) {
it('should fail with invalid consent because of ' + caseName, function() {
- let dataConsent = {
+ const dataConsent = {
gdprApplies: true,
consentString: 'consentString',
vendorData: {
purposeConsent, vendorConsent
}
}
- expect(id5IdSubmodule.getId(config)).is.eq(undefined);
- expect(id5IdSubmodule.getId(config, dataConsent)).is.eq(undefined);
+ expect(id5System.id5IdSubmodule.getId(config)).is.eq(undefined);
+ expect(id5System.id5IdSubmodule.getId(config, dataConsent)).is.eq(undefined);
- let cacheIdObject = 'cacheIdObject';
- expect(id5IdSubmodule.extendId(config)).is.eq(undefined);
- expect(id5IdSubmodule.extendId(config, dataConsent, cacheIdObject)).is.eq(cacheIdObject);
+ const cacheIdObject = 'cacheIdObject';
+ expect(id5System.id5IdSubmodule.extendId(config)).is.eq(undefined);
+ expect(id5System.id5IdSubmodule.extendId(config, dataConsent, cacheIdObject)).is.eq(cacheIdObject);
});
});
});
describe('Xhr Requests from getId()', function () {
const responseHeader = HEADERS_CONTENT_TYPE_JSON
+ let gppStub
beforeEach(function () {
});
afterEach(function () {
uspDataHandler.reset()
+ gppStub?.restore()
});
- it('should call the ID5 server and handle a valid response', function () {
- let xhrServerMock = new XhrServerMock(server)
- let config = getId5FetchConfig();
- let submoduleResponse = callSubmoduleGetId(config, undefined, undefined);
+ it('should call the ID5 server and handle a valid response', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+ const config = getId5FetchConfig();
- return xhrServerMock.expectFetchRequest()
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(fetchRequest.url).to.contain(ID5_ENDPOINT);
- expect(fetchRequest.withCredentials).is.true;
- expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID);
- expect(requestBody.o).is.eq('pbjs');
- expect(requestBody.pd).is.undefined;
- expect(requestBody.s).is.undefined;
- expect(requestBody.provider).is.undefined
- expect(requestBody.v).is.eq('$prebid.version$');
- expect(requestBody.gdpr).is.eq(0);
- expect(requestBody.gdpr_consent).is.undefined;
- expect(requestBody.us_privacy).is.undefined;
- expect(requestBody.storage).is.deep.eq(config.storage)
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(config, undefined, undefined);
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
- .then(submoduleResponse => {
- expect(submoduleResponse).is.deep.equal(ID5_JSON_RESPONSE);
- });
+ const fetchRequest = await xhrServerMock.expectFetchRequest()
+
+ expect(fetchRequest.url).to.contain(ID5_ENDPOINT);
+ expect(fetchRequest.withCredentials).is.true;
+
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID);
+ expect(requestBody.o).is.eq('pbjs');
+ expect(requestBody.pd).is.undefined;
+ expect(requestBody.s).is.undefined;
+ expect(requestBody.provider).is.undefined
+ expect(requestBody.v).is.eq('$prebid.version$');
+ expect(requestBody.gdpr).is.eq(0);
+ expect(requestBody.gdpr_consent).is.undefined;
+ expect(requestBody.us_privacy).is.undefined;
+ expect(requestBody.storage).is.deep.eq(config.storage)
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+
+ const submoduleResponse = await submoduleResponsePromise;
+ expect(submoduleResponse).is.deep.equal(ID5_JSON_RESPONSE);
});
- it('should call the ID5 server with gdpr data ', function () {
- let xhrServerMock = new XhrServerMock(server)
- let consentData = {
+ it('should call the ID5 server with gdpr data ', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+ const consentData = {
gdprApplies: true,
consentString: 'consentString',
vendorData: ALLOWED_ID5_VENDOR_DATA
}
- let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), consentData, undefined);
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), consentData, undefined);
- return xhrServerMock.expectFetchRequest()
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID);
- expect(requestBody.gdpr).to.eq(1);
- expect(requestBody.gdpr_consent).is.eq(consentData.consentString);
+ const fetchRequest = await xhrServerMock.expectFetchRequest()
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID);
+ expect(requestBody.gdpr).to.eq(1);
+ expect(requestBody.gdpr_consent).is.eq(consentData.consentString);
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
- .then(submoduleResponse => {
- expect(submoduleResponse).is.deep.equal(ID5_JSON_RESPONSE);
- });
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+
+ const submoduleResponse = await submoduleResponsePromise;
+ expect(submoduleResponse).is.deep.equal(ID5_JSON_RESPONSE);
});
- it('should call the ID5 server without gdpr data when gdpr not applies ', function () {
- let xhrServerMock = new XhrServerMock(server)
- let consentData = {
+ it('should call the ID5 server without gdpr data when gdpr not applies ', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+ const consentData = {
gdprApplies: false,
consentString: 'consentString'
}
- let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), consentData, undefined);
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), consentData, undefined);
- return xhrServerMock.expectFetchRequest()
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.gdpr).to.eq(0);
- expect(requestBody.gdpr_consent).is.undefined
+ const fetchRequest = await xhrServerMock.expectFetchRequest()
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.gdpr).to.eq(0);
+ expect(requestBody.gdpr_consent).is.undefined
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
- .then(submoduleResponse => {
- expect(submoduleResponse).is.deep.equal(ID5_JSON_RESPONSE);
- });
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+
+ const submoduleResponse = await submoduleResponsePromise;
+ expect(submoduleResponse).is.deep.equal(ID5_JSON_RESPONSE);
});
- it('should call the ID5 server with us privacy consent', function () {
- let usPrivacyString = '1YN-';
+ it('should call the ID5 server with us privacy consent', async function () {
+ const usPrivacyString = '1YN-';
uspDataHandler.setConsentData(usPrivacyString)
- let xhrServerMock = new XhrServerMock(server)
- let consentData = {
+ const xhrServerMock = new XhrServerMock(server)
+ const consentData = {
gdprApplies: true,
consentString: 'consentString',
vendorData: ALLOWED_ID5_VENDOR_DATA
}
- let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), consentData, undefined);
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), consentData, undefined);
- return xhrServerMock.expectFetchRequest()
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID);
- expect(requestBody.us_privacy).to.eq(usPrivacyString);
+ const fetchRequest = await xhrServerMock.expectFetchRequest()
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID);
+ expect(requestBody.us_privacy).to.eq(usPrivacyString);
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
- .then(submoduleResponse => {
- expect(submoduleResponse).is.deep.equal(ID5_JSON_RESPONSE);
- });
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+
+ const submoduleResponse = await submoduleResponsePromise;
+ expect(submoduleResponse).is.deep.equal(ID5_JSON_RESPONSE);
});
- it('should call the ID5 server with no signature field when no stored object', function () {
- let xhrServerMock = new XhrServerMock(server)
- let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), undefined, undefined);
+ it('should call the ID5 server with no signature field when no stored object', async function () {
+ const xhrServerMock = new XhrServerMock(server)
- return xhrServerMock.expectFetchRequest()
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.s).is.undefined;
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, undefined);
+
+ const fetchRequest = await xhrServerMock.expectFetchRequest()
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.s).is.undefined;
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
});
- it('should call the ID5 server for config with submodule config object', function () {
- let xhrServerMock = new XhrServerMock(server)
- let id5FetchConfig = getId5FetchConfig();
+ it('should call the ID5 server for config with submodule config object', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+ const id5FetchConfig = getId5FetchConfig();
id5FetchConfig.params.extraParam = {
x: 'X',
y: {
@@ -393,340 +403,410 @@ describe('ID5 ID System', function () {
b: '3'
}
}
- let submoduleResponse = callSubmoduleGetId(id5FetchConfig, undefined, undefined);
- return xhrServerMock.expectConfigRequest()
- .then(configRequest => {
- let requestBody = JSON.parse(configRequest.requestBody)
- expect(requestBody).is.deep.eq(id5FetchConfig)
- return xhrServerMock.respondWithConfigAndExpectNext(configRequest)
- })
- .then(fetchRequest => {
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(id5FetchConfig, undefined, undefined);
+
+ const configRequest = await xhrServerMock.expectConfigRequest();
+ const requestBody = JSON.parse(configRequest.requestBody);
+ expect(requestBody).is.deep.eq(id5FetchConfig)
+
+ const fetchRequest = await xhrServerMock.respondWithConfigAndExpectNext(configRequest)
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
});
- it('should call the ID5 server for config with partner id being a string', function () {
- let xhrServerMock = new XhrServerMock(server)
- let id5FetchConfig = getId5FetchConfig();
+ it('should call the ID5 server for config with partner id being a string', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+ const id5FetchConfig = getId5FetchConfig();
id5FetchConfig.params.partner = '173';
- let submoduleResponse = callSubmoduleGetId(id5FetchConfig, undefined, undefined);
- return xhrServerMock.expectConfigRequest()
- .then(configRequest => {
- let requestBody = JSON.parse(configRequest.requestBody)
- expect(requestBody.params.partner).is.eq(173)
- return xhrServerMock.respondWithConfigAndExpectNext(configRequest)
- })
- .then(fetchRequest => {
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(id5FetchConfig, undefined, undefined);
+
+ const configRequest = await xhrServerMock.expectConfigRequest();
+ const requestBody = JSON.parse(configRequest.requestBody)
+ expect(requestBody.params.partner).is.eq(173)
+
+ const fetchRequest = await xhrServerMock.respondWithConfigAndExpectNext(configRequest)
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
});
- it('should call the ID5 server for config with overridden url', function () {
- let xhrServerMock = new XhrServerMock(server)
- let id5FetchConfig = getId5FetchConfig();
+ it('should call the ID5 server for config with overridden url', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+ const id5FetchConfig = getId5FetchConfig();
id5FetchConfig.params.configUrl = 'http://localhost/x/y/z'
- let submoduleResponse = callSubmoduleGetId(id5FetchConfig, undefined, undefined);
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(id5FetchConfig, undefined, undefined);
- return xhrServerMock.expectFirstRequest()
- .then(configRequest => {
- expect(configRequest.url).is.eq('http://localhost/x/y/z')
- return xhrServerMock.respondWithConfigAndExpectNext(configRequest)
- })
- .then(fetchRequest => {
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
+ const configRequest = await xhrServerMock.expectFirstRequest();
+ expect(configRequest.url).is.eq('http://localhost/x/y/z');
+
+ const fetchRequest = await xhrServerMock.respondWithConfigAndExpectNext(configRequest)
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
});
- it('should call the ID5 server with additional data when provided', function () {
- let xhrServerMock = new XhrServerMock(server)
- let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), undefined, undefined);
-
- return xhrServerMock.expectConfigRequest()
- .then(configRequest => {
- return xhrServerMock.respondWithConfigAndExpectNext(configRequest, {
- fetchCall: {
- url: ID5_ENDPOINT,
- overrides: {
- arg1: '123',
- arg2: {
- x: '1',
- y: 2
- }
- }
+ it('should call the ID5 server with additional data when provided', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, undefined);
+
+ const configRequest = await xhrServerMock.expectConfigRequest();
+ const fetchRequest = await xhrServerMock.respondWithConfigAndExpectNext(configRequest, {
+ fetchCall: {
+ url: ID5_ENDPOINT,
+ overrides: {
+ arg1: '123',
+ arg2: {
+ x: '1',
+ y: 2
}
- });
- })
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID);
- expect(requestBody.o).is.eq('pbjs');
- expect(requestBody.v).is.eq('$prebid.version$');
- expect(requestBody.arg1).is.eq('123')
- expect(requestBody.arg2).is.deep.eq({
- x: '1',
- y: 2
- })
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
+ }
+ }
+ });
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID);
+ expect(requestBody.o).is.eq('pbjs');
+ expect(requestBody.v).is.eq('$prebid.version$');
+ expect(requestBody.arg1).is.eq('123')
+ expect(requestBody.arg2).is.deep.eq({
+ x: '1',
+ y: 2
+ })
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
});
- it('should call the ID5 server with extensions', function () {
- let xhrServerMock = new XhrServerMock(server)
- let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), undefined, undefined);
-
- return xhrServerMock.expectConfigRequest()
- .then(configRequest => {
- return xhrServerMock.respondWithConfigAndExpectNext(configRequest, {
- fetchCall: {
- url: ID5_ENDPOINT
- },
- extensionsCall: {
- url: ID5_EXTENSIONS_ENDPOINT,
- method: 'GET'
- }
- });
- })
- .then(extensionsRequest => {
- expect(extensionsRequest.url).is.eq(ID5_EXTENSIONS_ENDPOINT)
- expect(extensionsRequest.method).is.eq('GET')
- extensionsRequest.respond(200, responseHeader, JSON.stringify({
- lb: 'ex'
- }))
- return xhrServerMock.expectNextRequest();
- })
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID);
- expect(requestBody.o).is.eq('pbjs');
- expect(requestBody.v).is.eq('$prebid.version$');
- expect(requestBody.extensions).is.deep.eq({
- lb: 'ex'
- })
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
+ it('should call the ID5 server with extensions', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, undefined);
+
+ const configRequest = await xhrServerMock.expectConfigRequest();
+ const extensionsRequest = await xhrServerMock.respondWithConfigAndExpectNext(configRequest, {
+ fetchCall: {
+ url: ID5_ENDPOINT
+ },
+ extensionsCall: {
+ url: ID5_EXTENSIONS_ENDPOINT,
+ method: 'GET'
+ }
+ });
+ expect(extensionsRequest.url).is.eq(ID5_EXTENSIONS_ENDPOINT)
+ expect(extensionsRequest.method).is.eq('GET')
+
+ extensionsRequest.respond(200, responseHeader, JSON.stringify({
+ lb: 'ex'
+ }));
+ const fetchRequest = await xhrServerMock.expectNextRequest();
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID);
+ expect(requestBody.o).is.eq('pbjs');
+ expect(requestBody.v).is.eq('$prebid.version$');
+ expect(requestBody.extensions).is.deep.eq({
+ lb: 'ex'
+ })
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
});
- it('should call the ID5 server with extensions fetched with POST', function () {
- let xhrServerMock = new XhrServerMock(server)
- let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), undefined, undefined);
-
- return xhrServerMock.expectConfigRequest()
- .then(configRequest => {
- return xhrServerMock.respondWithConfigAndExpectNext(configRequest, {
- fetchCall: {
- url: ID5_ENDPOINT
- },
- extensionsCall: {
- url: ID5_EXTENSIONS_ENDPOINT,
- method: 'POST',
- body: {
- x: '1',
- y: 2
- }
- }
- });
- })
- .then(extensionsRequest => {
- expect(extensionsRequest.url).is.eq(ID5_EXTENSIONS_ENDPOINT)
- expect(extensionsRequest.method).is.eq('POST')
- let requestBody = JSON.parse(extensionsRequest.requestBody)
- expect(requestBody).is.deep.eq({
+ it('should call the ID5 server with extensions fetched using method POST', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, undefined);
+
+ const configRequest = await xhrServerMock.expectConfigRequest();
+ const extensionsRequest = await xhrServerMock.respondWithConfigAndExpectNext(configRequest, {
+ fetchCall: {
+ url: ID5_ENDPOINT
+ },
+ extensionsCall: {
+ url: ID5_EXTENSIONS_ENDPOINT,
+ method: 'POST',
+ body: {
x: '1',
y: 2
- })
- extensionsRequest.respond(200, responseHeader, JSON.stringify({
- lb: 'post',
- }))
- return xhrServerMock.expectNextRequest();
- })
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID);
- expect(requestBody.o).is.eq('pbjs');
- expect(requestBody.v).is.eq('$prebid.version$');
- expect(requestBody.extensions).is.deep.eq({
- lb: 'post'
- })
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
+ }
+ }
+ });
+ expect(extensionsRequest.url).is.eq(ID5_EXTENSIONS_ENDPOINT)
+ expect(extensionsRequest.method).is.eq('POST')
+ const extRequestBody = JSON.parse(extensionsRequest.requestBody)
+ expect(extRequestBody).is.deep.eq({
+ x: '1',
+ y: 2
+ })
+ extensionsRequest.respond(200, responseHeader, JSON.stringify({
+ lb: 'post',
+ }));
+
+ const fetchRequest = await xhrServerMock.expectNextRequest();
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.partner).is.eq(ID5_TEST_PARTNER_ID);
+ expect(requestBody.o).is.eq('pbjs');
+ expect(requestBody.v).is.eq('$prebid.version$');
+ expect(requestBody.extensions).is.deep.eq({
+ lb: 'post'
+ });
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
});
- it('should call the ID5 server with signature field from stored object', function () {
- let xhrServerMock = new XhrServerMock(server)
- let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), undefined, ID5_STORED_OBJ);
+ it('should call the ID5 server with signature field from stored object', async function () {
+ const xhrServerMock = new XhrServerMock(server)
- return xhrServerMock.expectFetchRequest()
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.s).is.eq(ID5_STORED_SIGNATURE);
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, ID5_STORED_OBJ);
+
+ const fetchRequest = await xhrServerMock.expectFetchRequest()
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.s).is.eq(ID5_STORED_SIGNATURE);
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
});
- it('should call the ID5 server with pd field when pd config is set', function () {
- let xhrServerMock = new XhrServerMock(server)
+ it('should call the ID5 server with pd field when pd config is set', async function () {
+ const xhrServerMock = new XhrServerMock(server)
const pubData = 'b50ca08271795a8e7e4012813f23d505193d75c0f2e2bb99baa63aa822f66ed3';
- let id5Config = getId5FetchConfig();
+ const id5Config = getId5FetchConfig();
id5Config.params.pd = pubData;
- let submoduleResponse = callSubmoduleGetId(id5Config, undefined, ID5_STORED_OBJ);
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(id5Config, undefined, undefined);
- return xhrServerMock.expectFetchRequest()
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.pd).is.eq(pubData);
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse;
- })
+ const fetchRequest = await xhrServerMock.expectFetchRequest();
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.pd).is.eq(pubData);
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
});
- it('should call the ID5 server with no pd field when pd config is not set', function () {
- let xhrServerMock = new XhrServerMock(server)
- let id5Config = getId5FetchConfig();
+ it('should call the ID5 server with no pd field when pd config is not set', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+ const id5Config = getId5FetchConfig();
id5Config.params.pd = undefined;
- let submoduleResponse = callSubmoduleGetId(id5Config, undefined, ID5_STORED_OBJ);
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(id5Config, undefined, ID5_STORED_OBJ);
- return xhrServerMock.expectFetchRequest()
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.pd).is.undefined;
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse;
- })
+ const fetchRequest = await xhrServerMock.expectFetchRequest();
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.pd).is.undefined;
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
});
- it('should call the ID5 server with nb=1 when no stored value exists and reset after', function () {
- let xhrServerMock = new XhrServerMock(server)
- coreStorage.removeDataFromLocalStorage(ID5_NB_STORAGE_NAME);
+ it('should call the ID5 server with nb=1 when no stored value exists and reset after', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+ const TEST_PARTNER_ID = 189;
+ coreStorage.removeDataFromLocalStorage(id5System.nbCacheName(TEST_PARTNER_ID));
- let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), undefined, ID5_STORED_OBJ);
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, ID5_STORED_OBJ);
- return xhrServerMock.expectFetchRequest()
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.nbPage).is.eq(1);
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
- .then(() => {
- expect(getNbFromCache(ID5_TEST_PARTNER_ID)).is.eq(0);
- })
+ const fetchRequest = await xhrServerMock.expectFetchRequest();
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.nbPage).is.eq(1);
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
+
+ expect(id5System.getNbFromCache(TEST_PARTNER_ID)).is.eq(0);
});
- it('should call the ID5 server with incremented nb when stored value exists and reset after', function () {
- let xhrServerMock = new XhrServerMock(server)
- storeNbInCache(ID5_TEST_PARTNER_ID, 1);
+ it('should call the ID5 server with incremented nb when stored value exists and reset after', async function () {
+ const xhrServerMock = new XhrServerMock(server);
+ const TEST_PARTNER_ID = 189;
+ const config = getId5FetchConfig(TEST_PARTNER_ID);
+ id5System.storeNbInCache(TEST_PARTNER_ID, 1);
- let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), undefined, ID5_STORED_OBJ);
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(config, undefined, ID5_STORED_OBJ);
- return xhrServerMock.expectFetchRequest()
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.nbPage).is.eq(2);
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
- .then(() => {
- expect(getNbFromCache(ID5_TEST_PARTNER_ID)).is.eq(0);
- })
+ const fetchRequest = await xhrServerMock.expectFetchRequest();
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.nbPage).is.eq(2);
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
+
+ expect(id5System.getNbFromCache(TEST_PARTNER_ID)).is.eq(0);
});
- it('should call the ID5 server with ab_testing object when abTesting is turned on', function () {
- let xhrServerMock = new XhrServerMock(server)
- let id5Config = getId5FetchConfig();
+ it('should call the ID5 server with ab_testing object when abTesting is turned on', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+ const id5Config = getId5FetchConfig();
id5Config.params.abTesting = {enabled: true, controlGroupPct: 0.234}
- let submoduleResponse = callSubmoduleGetId(id5Config, undefined, ID5_STORED_OBJ);
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(id5Config, undefined, ID5_STORED_OBJ);
- return xhrServerMock.expectFetchRequest()
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.ab_testing.enabled).is.eq(true);
- expect(requestBody.ab_testing.control_group_pct).is.eq(0.234);
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse;
- });
+ const fetchRequest = await xhrServerMock.expectFetchRequest();
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.ab_testing.enabled).is.eq(true);
+ expect(requestBody.ab_testing.control_group_pct).is.eq(0.234);
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
});
- it('should call the ID5 server without ab_testing object when abTesting is turned off', function () {
- let xhrServerMock = new XhrServerMock(server)
- let id5Config = getId5FetchConfig();
+ it('should call the ID5 server without ab_testing object when abTesting is turned off', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+ const id5Config = getId5FetchConfig();
id5Config.params.abTesting = {enabled: false, controlGroupPct: 0.55}
- let submoduleResponse = callSubmoduleGetId(id5Config, undefined, ID5_STORED_OBJ);
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(id5Config, undefined, ID5_STORED_OBJ);
- return xhrServerMock.expectFetchRequest()
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.ab_testing).is.undefined;
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- });
+ const fetchRequest = await xhrServerMock.expectFetchRequest();
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.ab_testing).is.undefined;
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
});
- it('should call the ID5 server without ab_testing when when abTesting is not set', function () {
- let xhrServerMock = new XhrServerMock(server)
- let id5Config = getId5FetchConfig();
+ it('should call the ID5 server without ab_testing when when abTesting is not set', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+ const id5Config = getId5FetchConfig();
- let submoduleResponse = callSubmoduleGetId(id5Config, undefined, ID5_STORED_OBJ);
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(id5Config, undefined, ID5_STORED_OBJ);
- return xhrServerMock.expectFetchRequest()
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.ab_testing).is.undefined;
- fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- });
+ const fetchRequest = await xhrServerMock.expectFetchRequest();
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.ab_testing).is.undefined;
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+ await submoduleResponsePromise;
});
- it('should store the privacy object from the ID5 server response', function () {
- let xhrServerMock = new XhrServerMock(server)
- let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), undefined, ID5_STORED_OBJ);
+ it('should store the privacy object from the ID5 server response', async function () {
+ const xhrServerMock = new XhrServerMock(server)
+
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, ID5_STORED_OBJ);
const privacy = {
jurisdiction: 'gdpr',
id5_consent: true
};
- return xhrServerMock.expectFetchRequest()
- .then(request => {
- let responseObject = utils.deepClone(ID5_JSON_RESPONSE);
- responseObject.privacy = privacy;
- request.respond(200, responseHeader, JSON.stringify(responseObject));
- return submoduleResponse
- })
- .then(() => {
- expect(getFromLocalStorage(ID5_PRIVACY_STORAGE_NAME)).is.eq(JSON.stringify(privacy));
- coreStorage.removeDataFromLocalStorage(ID5_PRIVACY_STORAGE_NAME);
- })
+ const fetchRequest = await xhrServerMock.expectFetchRequest();
+ const responseObject = utils.deepClone(ID5_JSON_RESPONSE);
+ responseObject.privacy = privacy;
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(responseObject));
+ await submoduleResponsePromise;
+
+ expect(id5System.getFromLocalStorage(id5System.ID5_PRIVACY_STORAGE_NAME)).is.eq(JSON.stringify(privacy));
+ coreStorage.removeDataFromLocalStorage(id5System.ID5_PRIVACY_STORAGE_NAME);
+ });
+
+ it('should not store a privacy object if not part of ID5 server response', async function () {
+ const xhrServerMock = new XhrServerMock(server);
+ coreStorage.removeDataFromLocalStorage(id5System.ID5_PRIVACY_STORAGE_NAME);
+
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, ID5_STORED_OBJ);
+
+ const fetchRequest = await xhrServerMock.expectFetchRequest();
+ const responseObject = utils.deepClone(ID5_JSON_RESPONSE);
+ responseObject.privacy = undefined;
+
+ fetchRequest.respond(200, responseHeader, JSON.stringify(responseObject));
+ await submoduleResponsePromise;
+
+ expect(id5System.getFromLocalStorage(id5System.ID5_PRIVACY_STORAGE_NAME)).is.null;
+ });
+
+ describe('with successful external module call', function() {
+ const MOCK_RESPONSE = {
+ ...ID5_JSON_RESPONSE,
+ universal_uid: 'my_mock_reponse'
+ };
+ let mockId5ExternalModule;
+
+ beforeEach(() => {
+ window.id5Prebid = {
+ integration: {
+ fetchId5Id: function() {}
+ }
+ };
+ mockId5ExternalModule = sinon.stub(window.id5Prebid.integration, 'fetchId5Id')
+ .resolves(MOCK_RESPONSE);
+ });
+
+ this.afterEach(() => {
+ mockId5ExternalModule.restore();
+ delete window.id5Prebid;
+ });
+
+ it('should retrieve the response from the external module interface', async function() {
+ const xhrServerMock = new XhrServerMock(server);
+ const config = getId5FetchConfig();
+ config.params.externalModuleUrl = 'https://test-me.test';
+
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(config, undefined, undefined);
+
+ const configRequest = await xhrServerMock.expectConfigRequest();
+ configRequest.respond(200, HEADERS_CONTENT_TYPE_JSON, JSON.stringify(ID5_API_CONFIG));
+
+ const submoduleResponse = await submoduleResponsePromise;
+ expect(submoduleResponse).to.deep.equal(MOCK_RESPONSE);
+ expect(mockId5ExternalModule.calledOnce);
+ });
+ });
+
+ describe('with failing external module loading', function() {
+ it('should fallback to regular logic if external module fails to load', async function() {
+ const xhrServerMock = new XhrServerMock(server);
+ const config = getId5FetchConfig();
+ config.params.externalModuleUrl = 'https://test-me.test'; // Fails by loading this fake URL
+
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(config, undefined, undefined);
+
+ // Still we have a server-side request triggered as fallback
+ const fetchRequest = await xhrServerMock.expectFetchRequest();
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
+
+ const submoduleResponse = await submoduleResponsePromise;
+ expect(submoduleResponse).to.deep.equal(ID5_JSON_RESPONSE);
+ });
});
- it('should not store a privacy object if not part of ID5 server response', function () {
+ it('should pass gpp_string and gpp_sid to ID5 server', function () {
let xhrServerMock = new XhrServerMock(server)
- coreStorage.removeDataFromLocalStorage(ID5_PRIVACY_STORAGE_NAME);
+ gppStub = sinon.stub(gppDataHandler, 'getConsentData');
+ gppStub.returns({
+ ready: true,
+ gppString: 'GPP_STRING',
+ applicableSections: [2]
+ });
let submoduleResponse = callSubmoduleGetId(getId5FetchConfig(), undefined, ID5_STORED_OBJ);
return xhrServerMock.expectFetchRequest()
- .then(request => {
- let responseObject = utils.deepClone(ID5_JSON_RESPONSE);
- responseObject.privacy = undefined;
- request.respond(200, responseHeader, JSON.stringify(responseObject));
+ .then(fetchRequest => {
+ let requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.gpp_string).is.equal('GPP_STRING');
+ expect(requestBody.gpp_sid).contains(2);
+ fetchRequest.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE));
return submoduleResponse
- })
- .then(() => {
- expect(getFromLocalStorage(ID5_PRIVACY_STORAGE_NAME)).is.null;
});
});
@@ -734,14 +814,14 @@ describe('ID5 ID System', function () {
let sandbox;
beforeEach(() => {
sandbox = sinon.sandbox.create();
- sandbox.stub(storage, 'getCookie');
+ sandbox.stub(id5System.storage, 'getCookie');
});
afterEach(() => {
sandbox.restore();
});
it('should not throw if malformed JSON is forced into cookies', () => {
- storage.getCookie.callsFake(() => ' Not JSON ');
- id5IdSubmodule.getId(getId5FetchConfig());
+ id5System.storage.getCookie.callsFake(() => ' Not JSON ');
+ id5System.id5IdSubmodule.getId(getId5FetchConfig());
});
})
});
@@ -750,7 +830,7 @@ describe('ID5 ID System', function () {
let sandbox;
beforeEach(() => {
sandbox = sinon.sandbox.create();
- sandbox.stub(storage, 'localStorageIsEnabled');
+ sandbox.stub(id5System.storage, 'localStorageIsEnabled');
});
afterEach(() => {
sandbox.restore();
@@ -758,26 +838,23 @@ describe('ID5 ID System', function () {
[
[true, 1],
[false, 0]
- ].forEach(function ([isEnabled, expectedValue]) {
- it(`should check localStorage availability and log in request. Available=${isEnabled}`, () => {
- let xhrServerMock = new XhrServerMock(server)
- let config = getId5FetchConfig();
- let submoduleResponse = callSubmoduleGetId(config, undefined, undefined);
- storage.localStorageIsEnabled.callsFake(() => isEnabled)
-
- return xhrServerMock.expectFetchRequest()
- .then(fetchRequest => {
- let requestBody = JSON.parse(fetchRequest.requestBody);
- expect(requestBody.localStorage).is.eq(expectedValue);
-
- fetchRequest.respond(200, HEADERS_CONTENT_TYPE_JSON, JSON.stringify(ID5_JSON_RESPONSE));
- return submoduleResponse
- })
- .then(submoduleResponse => {
- expect(submoduleResponse).is.deep.equal(ID5_JSON_RESPONSE);
- });
- })
- })
+ ].forEach(([isEnabled, expectedValue]) => {
+ it(`should check localStorage availability and log in request. Available=${isEnabled}`, async function() {
+ const xhrServerMock = new XhrServerMock(server)
+ id5System.storage.localStorageIsEnabled.callsFake(() => isEnabled)
+
+ // Trigger the fetch but we await on it later
+ const submoduleResponsePromise = callSubmoduleGetId(getId5FetchConfig(), undefined, ID5_STORED_OBJ);
+
+ const fetchRequest = await xhrServerMock.expectFetchRequest();
+ const requestBody = JSON.parse(fetchRequest.requestBody);
+ expect(requestBody.localStorage).is.eq(expectedValue);
+
+ fetchRequest.respond(200, HEADERS_CONTENT_TYPE_JSON, JSON.stringify(ID5_JSON_RESPONSE));
+ const submoduleResponse = await submoduleResponsePromise;
+ expect(submoduleResponse).is.deep.equal(ID5_JSON_RESPONSE);
+ });
+ });
});
describe('Request Bids Hook', function () {
@@ -788,26 +865,26 @@ describe('ID5 ID System', function () {
sandbox = sinon.sandbox.create();
mockGdprConsent(sandbox);
sinon.stub(events, 'getEvents').returns([]);
- coreStorage.removeDataFromLocalStorage(ID5_STORAGE_NAME);
- coreStorage.removeDataFromLocalStorage(`${ID5_STORAGE_NAME}_last`);
- coreStorage.removeDataFromLocalStorage(ID5_NB_STORAGE_NAME);
- coreStorage.setDataInLocalStorage(ID5_STORAGE_NAME + '_cst', getConsentHash())
+ coreStorage.removeDataFromLocalStorage(id5System.ID5_STORAGE_NAME);
+ coreStorage.removeDataFromLocalStorage(`${id5System.ID5_STORAGE_NAME}_last`);
+ coreStorage.removeDataFromLocalStorage(id5System.nbCacheName(ID5_TEST_PARTNER_ID));
+ coreStorage.setDataInLocalStorage(id5System.ID5_STORAGE_NAME + '_cst', getConsentHash())
adUnits = [getAdUnitMock()];
});
afterEach(function () {
events.getEvents.restore();
- coreStorage.removeDataFromLocalStorage(ID5_STORAGE_NAME);
- coreStorage.removeDataFromLocalStorage(`${ID5_STORAGE_NAME}_last`);
- coreStorage.removeDataFromLocalStorage(ID5_NB_STORAGE_NAME);
- coreStorage.removeDataFromLocalStorage(ID5_STORAGE_NAME + '_cst')
+ coreStorage.removeDataFromLocalStorage(id5System.ID5_STORAGE_NAME);
+ coreStorage.removeDataFromLocalStorage(`${id5System.ID5_STORAGE_NAME}_last`);
+ coreStorage.removeDataFromLocalStorage(id5System.nbCacheName(ID5_TEST_PARTNER_ID));
+ coreStorage.removeDataFromLocalStorage(id5System.ID5_STORAGE_NAME + '_cst')
sandbox.restore();
});
it('should add stored ID from cache to bids', function (done) {
- storeInLocalStorage(ID5_STORAGE_NAME, JSON.stringify(ID5_STORED_OBJ), 1);
+ id5System.storeInLocalStorage(id5System.ID5_STORAGE_NAME, JSON.stringify(ID5_STORED_OBJ), 1);
init(config);
- setSubmoduleRegistry([id5IdSubmodule]);
+ setSubmoduleRegistry([id5System.id5IdSubmodule]);
config.setConfig(getFetchLocalStorageConfig());
requestBidsHook(function () {
@@ -831,9 +908,38 @@ describe('ID5 ID System', function () {
}, {adUnits});
});
+ it('should add stored EUID from cache to bids', function (done) {
+ id5System.storeInLocalStorage(id5System.ID5_STORAGE_NAME, JSON.stringify(ID5_STORED_OBJ_WITH_EUID), 1);
+
+ init(config);
+ setSubmoduleRegistry([id5System.id5IdSubmodule]);
+ config.setConfig(getFetchLocalStorageConfig());
+
+ requestBidsHook(function () {
+ adUnits.forEach(unit => {
+ unit.bids.forEach(bid => {
+ expect(bid).to.have.deep.nested.property(`userId.euid`);
+ expect(bid.userId.euid.uid).is.equal(EUID_STORED_ID);
+ expect(bid.userIdAsEids[0].uids[0].id).is.equal(ID5_STORED_ID);
+ expect(bid.userIdAsEids[1]).is.deep.equal({
+ source: EUID_SOURCE,
+ uids: [{
+ id: EUID_STORED_ID,
+ atype: 3,
+ ext: {
+ provider: ID5_SOURCE
+ }
+ }]
+ })
+ });
+ });
+ done();
+ }, {adUnits});
+ });
+
it('should add config value ID to bids', function (done) {
init(config);
- setSubmoduleRegistry([id5IdSubmodule]);
+ setSubmoduleRegistry([id5System.id5IdSubmodule]);
config.setConfig(getValueConfig(ID5_STORED_ID));
requestBidsHook(function () {
@@ -852,44 +958,44 @@ describe('ID5 ID System', function () {
});
it('should set nb=1 in cache when no stored nb value exists and cached ID', function (done) {
- storeInLocalStorage(ID5_STORAGE_NAME, JSON.stringify(ID5_STORED_OBJ), 1);
- coreStorage.removeDataFromLocalStorage(ID5_NB_STORAGE_NAME);
+ id5System.storeInLocalStorage(id5System.ID5_STORAGE_NAME, JSON.stringify(ID5_STORED_OBJ), 1);
+ coreStorage.removeDataFromLocalStorage(id5System.nbCacheName(ID5_TEST_PARTNER_ID));
init(config);
- setSubmoduleRegistry([id5IdSubmodule]);
+ setSubmoduleRegistry([id5System.id5IdSubmodule]);
config.setConfig(getFetchLocalStorageConfig());
requestBidsHook((adUnitConfig) => {
- expect(getNbFromCache(ID5_TEST_PARTNER_ID)).is.eq(1);
+ expect(id5System.getNbFromCache(ID5_TEST_PARTNER_ID)).is.eq(1);
done()
}, {adUnits});
});
it('should increment nb in cache when stored nb value exists and cached ID', function (done) {
- storeInLocalStorage(ID5_STORAGE_NAME, JSON.stringify(ID5_STORED_OBJ), 1);
- storeNbInCache(ID5_TEST_PARTNER_ID, 1);
+ id5System.storeInLocalStorage(id5System.ID5_STORAGE_NAME, JSON.stringify(ID5_STORED_OBJ), 1);
+ id5System.storeNbInCache(ID5_TEST_PARTNER_ID, 1);
init(config);
- setSubmoduleRegistry([id5IdSubmodule]);
+ setSubmoduleRegistry([id5System.id5IdSubmodule]);
config.setConfig(getFetchLocalStorageConfig());
requestBidsHook(() => {
- expect(getNbFromCache(ID5_TEST_PARTNER_ID)).is.eq(2);
+ expect(id5System.getNbFromCache(ID5_TEST_PARTNER_ID)).is.eq(2);
done()
}, {adUnits});
});
it('should call ID5 servers with signature and incremented nb post auction if refresh needed', function () {
- let xhrServerMock = new XhrServerMock(server)
- let initialLocalStorageValue = JSON.stringify(ID5_STORED_OBJ);
- storeInLocalStorage(ID5_STORAGE_NAME, initialLocalStorageValue, 1);
- storeInLocalStorage(`${ID5_STORAGE_NAME}_last`, expDaysStr(-1), 1);
+ const xhrServerMock = new XhrServerMock(server)
+ const initialLocalStorageValue = JSON.stringify(ID5_STORED_OBJ);
+ id5System.storeInLocalStorage(id5System.ID5_STORAGE_NAME, initialLocalStorageValue, 1);
+ id5System.storeInLocalStorage(`${id5System.ID5_STORAGE_NAME}_last`, id5System.expDaysStr(-1), 1);
- storeNbInCache(ID5_TEST_PARTNER_ID, 1);
+ id5System.storeNbInCache(ID5_TEST_PARTNER_ID, 1);
let id5Config = getFetchLocalStorageConfig();
id5Config.userSync.userIds[0].storage.refreshInSeconds = 2;
init(config);
- setSubmoduleRegistry([id5IdSubmodule]);
+ setSubmoduleRegistry([id5System.id5IdSubmodule]);
config.setConfig(id5Config);
return new Promise((resolve) => {
@@ -899,23 +1005,23 @@ describe('ID5 ID System', function () {
}).then(() => {
expect(xhrServerMock.hasReceivedAnyRequest()).is.false;
events.emit(CONSTANTS.EVENTS.AUCTION_END, {});
- return xhrServerMock.expectFetchRequest()
+ return xhrServerMock.expectFetchRequest();
}).then(request => {
- let requestBody = JSON.parse(request.requestBody);
+ const requestBody = JSON.parse(request.requestBody);
expect(requestBody.s).is.eq(ID5_STORED_SIGNATURE);
expect(requestBody.nbPage).is.eq(2);
- expect(getNbFromCache(ID5_TEST_PARTNER_ID)).is.eq(2);
+ expect(id5System.getNbFromCache(ID5_TEST_PARTNER_ID)).is.eq(0);
request.respond(200, HEADERS_CONTENT_TYPE_JSON, JSON.stringify(ID5_JSON_RESPONSE));
return new Promise(function (resolve) {
(function waitForCondition() {
- if (getFromLocalStorage(ID5_STORAGE_NAME) !== initialLocalStorageValue) return resolve();
+ if (id5System.getFromLocalStorage(id5System.ID5_STORAGE_NAME) !== initialLocalStorageValue) return resolve();
setTimeout(waitForCondition, 30);
})();
})
}).then(() => {
- expect(decodeURIComponent(getFromLocalStorage(ID5_STORAGE_NAME))).is.eq(JSON.stringify(ID5_JSON_RESPONSE));
- expect(getNbFromCache(ID5_TEST_PARTNER_ID)).is.eq(0);
+ expect(decodeURIComponent(id5System.getFromLocalStorage(id5System.ID5_STORAGE_NAME))).is.eq(JSON.stringify(ID5_JSON_RESPONSE));
+ expect(id5System.getNbFromCache(ID5_TEST_PARTNER_ID)).is.eq(0);
})
});
});
@@ -924,10 +1030,17 @@ describe('ID5 ID System', function () {
const expectedDecodedObject = {id5id: {uid: ID5_STORED_ID, ext: {linkType: ID5_STORED_LINK_TYPE}}};
it('should properly decode from a stored object', function () {
- expect(id5IdSubmodule.decode(ID5_STORED_OBJ, getId5FetchConfig())).is.deep.equal(expectedDecodedObject);
+ expect(id5System.id5IdSubmodule.decode(ID5_STORED_OBJ, getId5FetchConfig())).is.deep.equal(expectedDecodedObject);
});
it('should return undefined if passed a string', function () {
- expect(id5IdSubmodule.decode('somestring', getId5FetchConfig())).is.eq(undefined);
+ expect(id5System.id5IdSubmodule.decode('somestring', getId5FetchConfig())).is.eq(undefined);
+ });
+ it('should decode euid from a stored object with EUID', function () {
+ expect(id5System.id5IdSubmodule.decode(ID5_STORED_OBJ_WITH_EUID, getId5FetchConfig()).euid).is.deep.equal({
+ 'source': EUID_SOURCE,
+ 'uid': EUID_STORED_ID,
+ 'ext': {'provider': ID5_SOURCE}
+ });
});
});
@@ -970,13 +1083,13 @@ describe('ID5 ID System', function () {
});
it('should not set abTestingControlGroup extension when A/B testing is off', function () {
- let decoded = id5IdSubmodule.decode(storedObject, testConfig);
+ const decoded = id5System.id5IdSubmodule.decode(storedObject, testConfig);
expect(decoded).is.deep.equal(expectedDecodedObjectWithIdAbOff);
});
it('should set abTestingControlGroup to false when A/B testing is on but in normal group', function () {
storedObject.ab_testing = {result: 'normal'};
- let decoded = id5IdSubmodule.decode(storedObject, testConfig);
+ const decoded = id5System.id5IdSubmodule.decode(storedObject, testConfig);
expect(decoded).is.deep.equal(expectedDecodedObjectWithIdAbOn);
});
@@ -986,13 +1099,13 @@ describe('ID5 ID System', function () {
storedObject.ext = {
'linkType': 0
};
- let decoded = id5IdSubmodule.decode(storedObject, testConfig);
+ const decoded = id5System.id5IdSubmodule.decode(storedObject, testConfig);
expect(decoded).is.deep.equal(expectedDecodedObjectWithoutIdAbOn);
});
it('should log A/B testing errors', function () {
storedObject.ab_testing = {result: 'error'};
- let decoded = id5IdSubmodule.decode(storedObject, testConfig);
+ const decoded = id5System.id5IdSubmodule.decode(storedObject, testConfig);
expect(decoded).is.deep.equal(expectedDecodedObjectWithIdAbOff);
sinon.assert.calledOnce(logErrorSpy);
});
diff --git a/test/spec/modules/identityLinkIdSystem_spec.js b/test/spec/modules/identityLinkIdSystem_spec.js
index a273f26b28b..66d5a3edd00 100644
--- a/test/spec/modules/identityLinkIdSystem_spec.js
+++ b/test/spec/modules/identityLinkIdSystem_spec.js
@@ -3,6 +3,7 @@ import * as utils from 'src/utils.js';
import {server} from 'test/mocks/xhr.js';
import {getCoreStorageManager} from '../../../src/storageManager.js';
import {stub} from 'sinon';
+import { gppDataHandler } from '../../../src/adapterManager.js';
const storage = getCoreStorageManager();
@@ -20,6 +21,7 @@ function setTestEnvelopeCookie () {
describe('IdentityLinkId tests', function () {
let logErrorStub;
+ let gppConsentDataStub;
beforeEach(function () {
defaultConfigParams = { params: {pid: pid} };
@@ -73,16 +75,19 @@ describe('IdentityLinkId tests', function () {
expect(submoduleCallback).to.be.undefined;
});
- it('should call the LiveRamp envelope endpoint with IAB consent string v1', function () {
+ it('should call the LiveRamp envelope endpoint with IAB consent string v2', function () {
let callBackSpy = sinon.spy();
let consentData = {
gdprApplies: true,
- consentString: 'BOkIpDSOkIpDSADABAENCc-AAAApOAFAAMAAsAMIAcAA_g'
+ consentString: 'CO4VThZO4VTiuADABBENAzCgAP_AAEOAAAAAAwwAgAEABhAAgAgAAA.YAAAAAAAAAA',
+ vendorData: {
+ tcfPolicyVersion: 2
+ }
};
let submoduleCallback = identityLinkSubmodule.getId(defaultConfigParams, consentData).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
- expect(request.url).to.be.eq('https://api.rlcdn.com/api/identity/envelope?pid=14&ct=1&cv=BOkIpDSOkIpDSADABAENCc-AAAApOAFAAMAAsAMIAcAA_g');
+ expect(request.url).to.be.eq('https://api.rlcdn.com/api/identity/envelope?pid=14&ct=4&cv=CO4VThZO4VTiuADABBENAzCgAP_AAEOAAAAAAwwAgAEABhAAgAgAAA.YAAAAAAAAAA');
request.respond(
200,
responseHeader,
@@ -91,25 +96,46 @@ describe('IdentityLinkId tests', function () {
expect(callBackSpy.calledOnce).to.be.true;
});
- it('should call the LiveRamp envelope endpoint with IAB consent string v2', function () {
+ it('should call the LiveRamp envelope endpoint with GPP consent string', function() {
+ gppConsentDataStub = sinon.stub(gppDataHandler, 'getConsentData');
+ gppConsentDataStub.returns({
+ ready: true,
+ gppString: 'DBABLA~BVVqAAAACqA.QA',
+ applicableSections: [7]
+ });
let callBackSpy = sinon.spy();
- let consentData = {
- gdprApplies: true,
- consentString: 'CO4VThZO4VTiuADABBENAzCgAP_AAEOAAAAAAwwAgAEABhAAgAgAAA.YAAAAAAAAAA',
- vendorData: {
- tcfPolicyVersion: 2
- }
- };
- let submoduleCallback = identityLinkSubmodule.getId(defaultConfigParams, consentData).callback;
+ let submoduleCallback = identityLinkSubmodule.getId(defaultConfigParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
- expect(request.url).to.be.eq('https://api.rlcdn.com/api/identity/envelope?pid=14&ct=4&cv=CO4VThZO4VTiuADABBENAzCgAP_AAEOAAAAAAwwAgAEABhAAgAgAAA.YAAAAAAAAAA');
+ expect(request.url).to.be.eq('https://api.rlcdn.com/api/identity/envelope?pid=14&gpp=DBABLA~BVVqAAAACqA.QA&gpp_sid=7');
+ request.respond(
+ 200,
+ responseHeader,
+ JSON.stringify({})
+ );
+ expect(callBackSpy.calledOnce).to.be.true;
+ gppConsentDataStub.restore();
+ });
+
+ it('should call the LiveRamp envelope endpoint without GPP consent string if consent string is not provided', function () {
+ gppConsentDataStub = sinon.stub(gppDataHandler, 'getConsentData');
+ gppConsentDataStub.returns({
+ ready: true,
+ gppString: '',
+ applicableSections: [7]
+ });
+ let callBackSpy = sinon.spy();
+ let submoduleCallback = identityLinkSubmodule.getId(defaultConfigParams).callback;
+ submoduleCallback(callBackSpy);
+ let request = server.requests[0];
+ expect(request.url).to.be.eq('https://api.rlcdn.com/api/identity/envelope?pid=14');
request.respond(
200,
responseHeader,
JSON.stringify({})
);
expect(callBackSpy.calledOnce).to.be.true;
+ gppConsentDataStub.restore();
});
it('should not throw Uncaught TypeError when envelope endpoint returns empty response', function () {
diff --git a/test/spec/modules/imdsBidAdapter_spec.js b/test/spec/modules/imdsBidAdapter_spec.js
index 7d808a2528f..b71a0bc51d9 100644
--- a/test/spec/modules/imdsBidAdapter_spec.js
+++ b/test/spec/modules/imdsBidAdapter_spec.js
@@ -1362,17 +1362,17 @@ describe('imdsBidAdapter ', function () {
expect(usersyncs[0].url).to.contain('https://ad-cdn.technoratimedia.com/html/usersync.html');
});
- it('should return a pixel usersync when pixels is enabled', function () {
+ it('should return an image usersync when pixels are enabled', function () {
let usersyncs = spec.getUserSyncs({
pixelEnabled: true
}, null);
expect(usersyncs).to.be.an('array').with.lengthOf(1);
- expect(usersyncs[0]).to.have.property('type', 'pixel');
+ expect(usersyncs[0]).to.have.property('type', 'image');
expect(usersyncs[0]).to.have.property('url');
expect(usersyncs[0].url).to.contain('https://sync.technoratimedia.com/services');
});
- it('should return an iframe usersync when both iframe and pixels is enabled', function () {
+ it('should return an iframe usersync when both iframe and pixel are enabled', function () {
let usersyncs = spec.getUserSyncs({
iframeEnabled: true,
pixelEnabled: true
diff --git a/test/spec/modules/impactifyBidAdapter_spec.js b/test/spec/modules/impactifyBidAdapter_spec.js
index 215972ff450..d9bf4becb22 100644
--- a/test/spec/modules/impactifyBidAdapter_spec.js
+++ b/test/spec/modules/impactifyBidAdapter_spec.js
@@ -1,6 +1,7 @@
import { expect } from 'chai';
-import { spec } from 'modules/impactifyBidAdapter.js';
+import { spec, STORAGE, STORAGE_KEY } from 'modules/impactifyBidAdapter.js';
import * as utils from 'src/utils.js';
+import sinon from 'sinon';
const BIDDER_CODE = 'impactify';
const BIDDER_ALIAS = ['imp'];
@@ -19,89 +20,202 @@ var gdprData = {
};
describe('ImpactifyAdapter', function () {
+ let getLocalStorageStub;
+ let localStorageIsEnabledStub;
+ let sandbox;
+
+ beforeEach(function () {
+ $$PREBID_GLOBAL$$.bidderSettings = {
+ impactify: {
+ storageAllowed: true
+ }
+ };
+ sinon.stub(document.body, 'appendChild');
+ sandbox = sinon.sandbox.create();
+ getLocalStorageStub = sandbox.stub(STORAGE, 'getDataFromLocalStorage');
+ localStorageIsEnabledStub = sandbox.stub(STORAGE, 'localStorageIsEnabled');
+ });
+
+ afterEach(function () {
+ $$PREBID_GLOBAL$$.bidderSettings = {};
+ document.body.appendChild.restore();
+ sandbox.restore();
+ });
+
describe('isBidRequestValid', function () {
- let validBid = {
- bidder: 'impactify',
- params: {
- appId: '1',
- format: 'screen',
- style: 'inline'
+ let validBids = [
+ {
+ bidder: 'impactify',
+ params: {
+ appId: 'example.com',
+ format: 'screen',
+ style: 'inline'
+ }
+ },
+ {
+ bidder: 'impactify',
+ params: {
+ appId: 'example.com',
+ format: 'display',
+ style: 'static'
+ }
+ }
+ ];
+
+ let videoBidRequests = [
+ {
+ bidder: 'impactify',
+ params: {
+ appId: '1',
+ format: 'screen',
+ style: 'inline'
+ },
+ mediaTypes: {
+ video: {
+ context: 'instream'
+ }
+ },
+ adUnitCode: 'adunit-code',
+ sizes: [[DEFAULT_VIDEO_WIDTH, DEFAULT_VIDEO_HEIGHT]],
+ bidId: '123456789',
+ bidderRequestId: '987654321',
+ auctionId: '19ab94a9-b0d7-4ed7-9f80-ad0c033cf1b1',
+ transactionId: 'f7b2c372-7a7b-11eb-9439-0242ac130002',
+ userId: {
+ pubcid: '87a0327b-851c-4bb3-a925-0c7be94548f5'
+ },
+ userIdAsEids: [
+ {
+ source: 'pubcid.org',
+ uids: [
+ {
+ id: '87a0327b-851c-4bb3-a925-0c7be94548f5',
+ atype: 1
+ }
+ ]
+ }
+ ]
+ }
+ ];
+ let videoBidderRequest = {
+ bidderRequestId: '98845765110',
+ auctionId: '165410516454',
+ bidderCode: 'impactify',
+ bids: [
+ {
+ ...videoBidRequests[0]
+ }
+ ],
+ refererInfo: {
+ referer: 'https://impactify.io'
}
};
it('should return true when required params found', function () {
- expect(spec.isBidRequestValid(validBid)).to.equal(true);
+ expect(spec.isBidRequestValid(validBids[0])).to.equal(true);
+ expect(spec.isBidRequestValid(validBids[1])).to.equal(true);
});
it('should return false when required params are not passed', function () {
- let bid = Object.assign({}, validBid);
+ let bid = Object.assign({}, validBids[0]);
delete bid.params;
bid.params = {};
expect(spec.isBidRequestValid(bid)).to.equal(false);
+
+ let bid2 = Object.assign({}, validBids[1]);
+ delete bid2.params;
+ bid2.params = {};
+ expect(spec.isBidRequestValid(bid2)).to.equal(false);
});
it('should return false when appId is missing', () => {
- const bid = utils.deepClone(validBid);
+ const bid = utils.deepClone(validBids[0]);
delete bid.params.appId;
-
expect(spec.isBidRequestValid(bid)).to.equal(false);
+
+ const bid2 = utils.deepClone(validBids[1]);
+ delete bid2.params.appId;
+ expect(spec.isBidRequestValid(bid2)).to.equal(false);
});
it('should return false when appId is not a string', () => {
- const bid = utils.deepClone(validBid);
+ const bid = utils.deepClone(validBids[0]);
+ const bid2 = utils.deepClone(validBids[1]);
bid.params.appId = 123;
+ bid2.params.appId = 123;
expect(spec.isBidRequestValid(bid)).to.equal(false);
+ expect(spec.isBidRequestValid(bid2)).to.equal(false);
bid.params.appId = false;
+ bid2.params.appId = false;
expect(spec.isBidRequestValid(bid)).to.equal(false);
+ expect(spec.isBidRequestValid(bid2)).to.equal(false);
bid.params.appId = void (0);
+ bid2.params.appId = void (0);
expect(spec.isBidRequestValid(bid)).to.equal(false);
+ expect(spec.isBidRequestValid(bid2)).to.equal(false);
bid.params.appId = {};
+ bid2.params.appId = {};
expect(spec.isBidRequestValid(bid)).to.equal(false);
+ expect(spec.isBidRequestValid(bid2)).to.equal(false);
});
it('should return false when format is missing', () => {
- const bid = utils.deepClone(validBid);
+ const bid = utils.deepClone(validBids[0]);
delete bid.params.format;
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
it('should return false when format is not a string', () => {
- const bid = utils.deepClone(validBid);
+ const bid = utils.deepClone(validBids[0]);
+ const bid2 = utils.deepClone(validBids[1]);
bid.params.format = 123;
+ bid2.params.format = 123;
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
expect(spec.isBidRequestValid(bid)).to.equal(false);
bid.params.format = false;
+ bid2.params.format = false;
expect(spec.isBidRequestValid(bid)).to.equal(false);
+ expect(spec.isBidRequestValid(bid2)).to.equal(false);
bid.params.format = void (0);
+ bid2.params.format = void (0);
expect(spec.isBidRequestValid(bid)).to.equal(false);
+ expect(spec.isBidRequestValid(bid2)).to.equal(false);
bid.params.format = {};
+ bid2.params.format = {};
expect(spec.isBidRequestValid(bid)).to.equal(false);
+ expect(spec.isBidRequestValid(bid2)).to.equal(false);
});
it('should return false when format is not equals to screen or display', () => {
- const bid = utils.deepClone(validBid);
+ const bid = utils.deepClone(validBids[0]);
if (bid.params.format != 'screen' && bid.params.format != 'display') {
expect(spec.isBidRequestValid(bid)).to.equal(false);
}
+
+ const bid2 = utils.deepClone(validBids[1]);
+ if (bid2.params.format != 'screen' && bid2.params.format != 'display') {
+ expect(spec.isBidRequestValid(bid2)).to.equal(false);
+ }
});
it('should return false when style is missing', () => {
- const bid = utils.deepClone(validBid);
+ const bid = utils.deepClone(validBids[0]);
delete bid.params.style;
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
it('should return false when style is not a string', () => {
- const bid = utils.deepClone(validBid);
+ const bid = utils.deepClone(validBids[0]);
bid.params.style = 123;
expect(spec.isBidRequestValid(bid)).to.equal(false);
@@ -167,22 +281,44 @@ describe('ImpactifyAdapter', function () {
};
it('should pass bidfloor', function () {
- videoBidRequests[0].getFloor = function() {
+ videoBidRequests[0].getFloor = function () {
return {
currency: 'USD',
floor: 1.23,
}
}
- const res = spec.buildRequests(videoBidRequests, videoBidderRequest)
+ const res = spec.buildRequests(videoBidRequests, videoBidderRequest);
const resData = JSON.parse(res.data)
expect(resData.imp[0].bidfloor).to.equal(1.23)
});
it('sends video bid request to ENDPOINT via POST', function () {
+ localStorageIsEnabledStub.returns(true);
+
+ getLocalStorageStub.returns('testValue');
+
const request = spec.buildRequests(videoBidRequests, videoBidderRequest);
+
expect(request.url).to.equal(ORIGIN + AUCTIONURI);
expect(request.method).to.equal('POST');
+ expect(request.options.customHeaders['x-impact']).to.equal('testValue');
+ });
+
+ it('should set header value from localstorage correctly', function () {
+ localStorageIsEnabledStub.returns(true);
+ getLocalStorageStub.returns('testValue');
+
+ const request = spec.buildRequests(videoBidRequests, videoBidderRequest);
+ expect(request.options.customHeaders).to.be.an('object');
+ expect(request.options.customHeaders['x-impact']).to.equal('testValue');
+ });
+
+ it('should set header value to empty if localstorage is not enabled', function () {
+ localStorageIsEnabledStub.returns(false);
+
+ const request = spec.buildRequests(videoBidRequests, videoBidderRequest);
+ expect(request.options.customHeaders).to.be.undefined;
});
});
describe('interpretResponse', function () {
@@ -205,7 +341,7 @@ describe('ImpactifyAdapter', function () {
h: 1,
hash: 'test',
expiry: 166192938,
- meta: {'advertiserDomains': ['testdomain.com']},
+ meta: { 'advertiserDomains': ['testdomain.com'] },
ext: {
prebid: {
'type': 'video'
@@ -281,7 +417,7 @@ describe('ImpactifyAdapter', function () {
height: 1,
hash: 'test',
expiry: 166192938,
- meta: {'advertiserDomains': ['testdomain.com']},
+ meta: { 'advertiserDomains': ['testdomain.com'] },
ttl: 300,
creativeId: '97517771'
}
@@ -343,7 +479,7 @@ describe('ImpactifyAdapter', function () {
h: 1,
hash: 'test',
expiry: 166192938,
- meta: {'advertiserDomains': ['testdomain.com']},
+ meta: { 'advertiserDomains': ['testdomain.com'] },
ext: {
prebid: {
'type': 'video'
@@ -399,8 +535,8 @@ describe('ImpactifyAdapter', function () {
const result = spec.getUserSyncs('bad', [], gdprData);
expect(result).to.be.empty;
});
- it('should append the various values if they exist', function() {
- const result = spec.getUserSyncs({iframeEnabled: true}, validResponse, gdprData);
+ it('should append the various values if they exist', function () {
+ const result = spec.getUserSyncs({ iframeEnabled: true }, validResponse, gdprData);
expect(result[0].url).to.include('gdpr=1');
expect(result[0].url).to.include('gdpr_consent=BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA');
});
diff --git a/test/spec/modules/improvedigitalBidAdapter_spec.js b/test/spec/modules/improvedigitalBidAdapter_spec.js
index f427f9e7624..a86b9be73e6 100644
--- a/test/spec/modules/improvedigitalBidAdapter_spec.js
+++ b/test/spec/modules/improvedigitalBidAdapter_spec.js
@@ -1181,6 +1181,16 @@ describe('Improve Digital Adapter Tests', function () {
expect(bids[0].dealId).to.equal(268515);
});
+ it('should set deal type targeting KV for PG', function () {
+ const request = makeRequest(bidderRequest);
+ const response = deepClone(serverResponse);
+ let bids;
+
+ response.body.seatbid[0].bid[0].ext.improvedigital.pg = 1;
+ bids = spec.interpretResponse(response, request);
+ expect(bids[0].adserverTargeting.hb_deal_type_improve).to.equal('pg');
+ });
+
it('should set currency', function () {
const response = deepClone(serverResponse);
response.body.cur = 'EUR';
diff --git a/test/spec/modules/innityBidAdapter_spec.js b/test/spec/modules/innityBidAdapter_spec.js
index 192ab4911ee..820f535ba72 100644
--- a/test/spec/modules/innityBidAdapter_spec.js
+++ b/test/spec/modules/innityBidAdapter_spec.js
@@ -120,5 +120,11 @@ describe('innityAdapterTest', () => {
expect(result[0].meta.advertiserDomains.length).to.equal(0);
expect(result[0].meta.advertiserDomains).to.deep.equal([]);
});
+
+ it('result with no bids', () => {
+ bidResponse.body = {};
+ const result = spec.interpretResponse(bidResponse, bidRequest);
+ expect(result).to.deep.equal([]);
+ });
});
});
diff --git a/test/spec/modules/insticatorBidAdapter_spec.js b/test/spec/modules/insticatorBidAdapter_spec.js
index e24bcb3b455..86f96834547 100644
--- a/test/spec/modules/insticatorBidAdapter_spec.js
+++ b/test/spec/modules/insticatorBidAdapter_spec.js
@@ -161,6 +161,19 @@ describe('InsticatorBidAdapter', function () {
})).to.be.false;
});
+ it('should return true if video object is absent/undefined', () => {
+ expect(spec.isBidRequestValid({
+ ...bidRequest,
+ ...{
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300, 600]],
+ },
+ }
+ }
+ })).to.be.true;
+ })
+
it('should return false if video placement is not a number', () => {
expect(spec.isBidRequestValid({
...bidRequest,
@@ -179,6 +192,143 @@ describe('InsticatorBidAdapter', function () {
}
})).to.be.false;
});
+
+ it('should return false if video plcmt is not a number', () => {
+ expect(spec.isBidRequestValid({
+ ...bidRequest,
+ ...{
+ mediaTypes: {
+ video: {
+ mimes: [
+ 'video/mp4',
+ 'video/mpeg',
+ ],
+ w: 250,
+ h: 300,
+ plcmt: 'NaN',
+ },
+ }
+ }
+ })).to.be.false;
+ });
+
+ it('should return true if playerSize is present instead of w and h', () => {
+ expect(spec.isBidRequestValid({
+ ...bidRequest,
+ ...{
+ mediaTypes: {
+ video: {
+ mimes: [
+ 'video/mp4',
+ 'video/mpeg',
+ ],
+ playerSize: [250, 300],
+ placement: 1,
+ },
+ }
+ }
+ })).to.be.true;
+ });
+
+ it('should return true if optional video fields are valid', () => {
+ expect(spec.isBidRequestValid({
+ ...bidRequest,
+ ...{
+ mediaTypes: {
+ video: {
+ mimes: [
+ 'video/mp4',
+ 'video/mpeg',
+ ],
+ playerSize: [250, 300],
+ placement: 1,
+ startdelay: 1,
+ skip: 1,
+ skipmin: 1,
+ skipafter: 1,
+ minduration: 1,
+ maxduration: 1,
+ api: [1, 2],
+ protocols: [2],
+ battr: [1, 2],
+ playbackmethod: [1, 2],
+ playbackend: 1,
+ delivery: [1, 2],
+ pos: 1,
+ },
+ }
+ }
+ })).to.be.true;
+ });
+
+ it('should return false if optional video fields are not valid', () => {
+ expect(spec.isBidRequestValid({
+ ...bidRequest,
+ ...{
+ mediaTypes: {
+ video: {
+ mimes: [
+ 'video/mp4',
+ 'video/mpeg',
+ ],
+ playerSize: [250, 300],
+ placement: 1,
+ startdelay: 'NaN',
+ },
+ }
+ }
+ })).to.be.false;
+ });
+
+ it('should return false if video min duration > max duration', () => {
+ expect(spec.isBidRequestValid({
+ ...bidRequest,
+ ...{
+ mediaTypes: {
+ video: {
+ mimes: [
+ 'video/mp4',
+ 'video/mpeg',
+ ],
+ playerSize: [250, 300],
+ placement: 1,
+ minduration: 5,
+ maxduration: 4,
+ },
+ }
+ }
+ })).to.be.false;
+ });
+
+ it('should return true when video bidder params override bidRequest video params', () => {
+ expect(spec.isBidRequestValid({
+ ...bidRequest,
+ ...{
+ mediaTypes: {
+ video: {
+ mimes: [
+ 'video/mp4',
+ 'video/mpeg',
+ ],
+ playerSize: [250, 300],
+ placement: 1,
+ },
+ }
+ },
+ params: {
+ ...bidRequest.params,
+ video: {
+ mimes: [
+ 'video/mp4',
+ 'video/mpeg',
+ 'video/x-flv',
+ 'video/webm',
+ ],
+ placement: 2,
+ },
+ }
+ })).to.be.true;
+ });
});
describe('buildRequests', function () {
@@ -355,6 +505,40 @@ describe('InsticatorBidAdapter', function () {
it('should return empty array if no valid requests are passed', function () {
expect(spec.buildRequests([], bidderRequest)).to.be.an('array').that.have.lengthOf(0);
});
+
+ it('should have bidder params override bidRequest mediatypes', function () {
+ const tempBiddRequest = {
+ ...bidRequest,
+ params: {
+ ...bidRequest.params,
+ video: {
+ mimes: [
+ 'video/mp4',
+ 'video/mpeg',
+ 'video/x-flv',
+ 'video/webm',
+ 'video/ogg',
+ ],
+ plcmt: 4,
+ w: 640,
+ h: 480,
+ }
+ }
+ }
+ const requests = spec.buildRequests([tempBiddRequest], bidderRequest);
+ const data = JSON.parse(requests[0].data);
+ expect(data.imp[0].video.mimes).to.deep.equal([
+ 'video/mp4',
+ 'video/mpeg',
+ 'video/x-flv',
+ 'video/webm',
+ 'video/ogg',
+ ])
+ expect(data.imp[0].video.placement).to.equal(2);
+ expect(data.imp[0].video.plcmt).to.equal(4);
+ expect(data.imp[0].video.w).to.equal(640);
+ expect(data.imp[0].video.h).to.equal(480);
+ });
});
describe('interpretResponse', function () {
@@ -570,4 +754,87 @@ describe('InsticatorBidAdapter', function () {
expect(spec.getUserSyncs({}, [response])).to.have.length(0);
})
});
+
+ describe('Response with video Instream', function () {
+ const bidRequestVid = {
+ method: 'POST',
+ url: 'https://ex.ingage.tech/v1/openrtb',
+ options: {
+ contentType: 'application/json',
+ withCredentials: true,
+ },
+ data: '',
+ bidderRequest: {
+ bidderRequestId: '22edbae2733bf6',
+ auctionId: '74f78609-a92d-4cf1-869f-1b244bbfb5d2',
+ timeout: 300,
+ bids: [
+ {
+ bidder: 'insticator',
+ params: {
+ adUnitId: '1a2b3c4d5e6f1a2b3c4d'
+ },
+ adUnitCode: 'adunit-code-1',
+ mediaTypes: {
+ video: {
+ mimes: [
+ 'video/mp4',
+ 'video/mpeg',
+ ],
+ playerSize: [[250, 300]],
+ placement: 2,
+ plcmt: 2,
+ }
+ },
+ bidId: 'bid1',
+ }
+ ]
+ }
+ };
+
+ const bidResponseVid = {
+ body: {
+ id: '22edbae2733bf6',
+ bidid: 'foo9876',
+ cur: 'USD',
+ seatbid: [
+ {
+ seat: 'some-dsp',
+ bid: [
+ {
+ ad: '
',
+ impid: 'bid1',
+ crid: 'crid1',
+ price: 0.5,
+ w: 300,
+ h: 250,
+ adm: '
',
+ exp: 60,
+ adomain: ['test1.com'],
+ ext: {
+ meta: {
+ test: 1
+ }
+ },
+ }
+ ],
+ },
+ ]
+ }
+ };
+ const bidRequestWithVideo = utils.deepClone(bidRequestVid);
+
+ it('should have related properties for video Instream', function() {
+ const serverResponseWithInstream = utils.deepClone(bidResponseVid);
+ serverResponseWithInstream.body.seatbid[0].bid[0].vastXml = '
';
+ serverResponseWithInstream.body.seatbid[0].bid[0].mediaType = 'video';
+ const bidResponse = spec.interpretResponse(serverResponseWithInstream, bidRequestWithVideo)[0];
+ expect(bidResponse).to.have.any.keys('mediaType', 'vastXml', 'vastUrl');
+ expect(bidResponse).to.have.property('mediaType', 'video');
+ expect(bidResponse.width).to.equal(300);
+ expect(bidResponse.height).to.equal(250);
+ expect(bidResponse).to.have.property('vastXml', '
');
+ expect(bidResponse.vastUrl).to.match(/^data:text\/xml;charset=utf-8;base64,[\w+/=]+$/)
+ });
+ })
});
diff --git a/test/spec/modules/invibesBidAdapter_spec.js b/test/spec/modules/invibesBidAdapter_spec.js
index 7ee6b464996..056255c7738 100644
--- a/test/spec/modules/invibesBidAdapter_spec.js
+++ b/test/spec/modules/invibesBidAdapter_spec.js
@@ -44,6 +44,78 @@ describe('invibesBidAdapter:', function () {
}
];
+ let bidRequestsWithDuplicatedplacementId = [
+ {
+ bidId: 'b1',
+ bidder: BIDDER_CODE,
+ bidderRequestId: 'r1',
+ params: {
+ placementId: PLACEMENT_ID,
+ disableUserSyncs: false
+
+ },
+ adUnitCode: 'test-div1',
+ auctionId: 'a1',
+ sizes: [
+ [300, 250],
+ [400, 300],
+ [125, 125]
+ ],
+ transactionId: 't1'
+ }, {
+ bidId: 'b2',
+ bidder: BIDDER_CODE,
+ bidderRequestId: 'r2',
+ params: {
+ placementId: PLACEMENT_ID,
+ disableUserSyncs: false
+ },
+ adUnitCode: 'test-div2',
+ auctionId: 'a2',
+ sizes: [
+ [300, 250],
+ [400, 300]
+ ],
+ transactionId: 't2'
+ }
+ ];
+
+ let bidRequestsWithUniquePlacementId = [
+ {
+ bidId: 'b1',
+ bidder: BIDDER_CODE,
+ bidderRequestId: 'r1',
+ params: {
+ placementId: 'PLACEMENT_ID_1',
+ disableUserSyncs: false
+
+ },
+ adUnitCode: 'test-div1',
+ auctionId: 'a1',
+ sizes: [
+ [300, 250],
+ [400, 300],
+ [125, 125]
+ ],
+ transactionId: 't1'
+ }, {
+ bidId: 'b2',
+ bidder: BIDDER_CODE,
+ bidderRequestId: 'r2',
+ params: {
+ placementId: 'PLACEMENT_ID_2',
+ disableUserSyncs: false
+ },
+ adUnitCode: 'test-div2',
+ auctionId: 'a2',
+ sizes: [
+ [300, 250],
+ [400, 300]
+ ],
+ transactionId: 't2'
+ }
+ ];
+
let bidRequestsWithUserId = [
{
bidId: 'b1',
@@ -185,17 +257,44 @@ describe('invibesBidAdapter:', function () {
expect(request.data.preventPageViewEvent).to.be.false;
});
+ it('sends isPlacementRefresh as false when the placement ids are used for the first time', function () {
+ let request = spec.buildRequests(bidRequestsWithUniquePlacementId, bidderRequestWithPageInfo);
+ expect(request.data.isPlacementRefresh).to.be.false;
+ });
+
it('sends preventPageViewEvent as true on 2nd call', function () {
let request = spec.buildRequests(bidRequests, bidderRequestWithPageInfo);
expect(request.data.preventPageViewEvent).to.be.true;
});
+ it('sends isPlacementRefresh as true on multi requests on the same placement id', function () {
+ let request = spec.buildRequests(bidRequestsWithDuplicatedplacementId, bidderRequestWithPageInfo);
+ expect(request.data.isPlacementRefresh).to.be.true;
+ });
+
+ it('sends isInfiniteScrollPage as false initially', function () {
+ let request = spec.buildRequests(bidRequests, bidderRequestWithPageInfo);
+ expect(request.data.isInfiniteScrollPage).to.be.false;
+ });
+
+ it('sends isPlacementRefresh as true on multi requests multiple calls with the same placement id from second call', function () {
+ let request = spec.buildRequests(bidRequests, bidderRequestWithPageInfo);
+ expect(request.data.isInfiniteScrollPage).to.be.false;
+ let duplicatedRequest = spec.buildRequests(bidRequests, bidderRequestWithPageInfo);
+ expect(duplicatedRequest.data.isPlacementRefresh).to.be.true;
+ });
+
it('sends bid request to ENDPOINT via GET', function () {
const request = spec.buildRequests(bidRequests, bidderRequestWithPageInfo);
expect(request.url).to.equal(ENDPOINT);
expect(request.method).to.equal('GET');
});
+ it('generates a visitId of length 32', function () {
+ spec.buildRequests(bidRequests, bidderRequestWithPageInfo);
+ expect(top.window.invibes.visitId.length).to.equal(32);
+ });
+
it('sends bid request to custom endpoint via GET', function () {
const request = spec.buildRequests([{
bidId: 'b1',
diff --git a/test/spec/modules/iqxBidAdapter_spec.js b/test/spec/modules/iqxBidAdapter_spec.js
new file mode 100644
index 00000000000..f5e680c8e0b
--- /dev/null
+++ b/test/spec/modules/iqxBidAdapter_spec.js
@@ -0,0 +1,455 @@
+import {expect} from 'chai';
+import {config} from 'src/config.js';
+import {spec, getBidFloor} from 'modules/iqxBidAdapter.js';
+import {deepClone} from 'src/utils';
+
+const ENDPOINT = 'https://pbjs.iqzonertb.live';
+
+const defaultRequest = {
+ adUnitCode: 'test',
+ bidId: '1',
+ requestId: 'qwerty',
+ ortb2: {
+ source: {
+ tid: 'auctionId'
+ }
+ },
+ ortb2Imp: {
+ ext: {
+ tid: 'tr1',
+ }
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [300, 250],
+ [300, 200]
+ ]
+ }
+ },
+ bidder: 'iqx',
+ params: {
+ env: 'iqx',
+ pid: '40',
+ ext: {}
+ },
+ bidRequestsCount: 1
+};
+
+const defaultRequestVideo = deepClone(defaultRequest);
+defaultRequestVideo.mediaTypes = {
+ video: {
+ playerSize: [640, 480],
+ context: 'instream',
+ skipppable: true
+ }
+};
+describe('iqxBidAdapter', () => {
+ describe('isBidRequestValid', function () {
+ it('should return false when request params is missing', function () {
+ const invalidRequest = deepClone(defaultRequest);
+ delete invalidRequest.params;
+ expect(spec.isBidRequestValid(invalidRequest)).to.equal(false);
+ });
+
+ it('should return false when required env param is missing', function () {
+ const invalidRequest = deepClone(defaultRequest);
+ delete invalidRequest.params.env;
+ expect(spec.isBidRequestValid(invalidRequest)).to.equal(false);
+ });
+
+ it('should return false when required pid param is missing', function () {
+ const invalidRequest = deepClone(defaultRequest);
+ delete invalidRequest.params.pid;
+ expect(spec.isBidRequestValid(invalidRequest)).to.equal(false);
+ });
+
+ it('should return false when video.playerSize is missing', function () {
+ const invalidRequest = deepClone(defaultRequestVideo);
+ delete invalidRequest.mediaTypes.video.playerSize;
+ expect(spec.isBidRequestValid(invalidRequest)).to.equal(false);
+ });
+
+ it('should return true when required params found', function () {
+ expect(spec.isBidRequestValid(defaultRequest)).to.equal(true);
+ });
+ });
+
+ describe('buildRequests', function () {
+ beforeEach(function () {
+ config.resetConfig();
+ });
+
+ it('should send request with correct structure', function () {
+ const request = spec.buildRequests([defaultRequest], {});
+ expect(request.method).to.equal('POST');
+ expect(request.url).to.equal(ENDPOINT + '/bid');
+ expect(request.options).to.have.property('contentType').and.to.equal('application/json');
+ expect(request).to.have.property('data');
+ });
+
+ it('should build basic request structure', function () {
+ const request = JSON.parse(spec.buildRequests([defaultRequest], {}).data)[0];
+ expect(request).to.have.property('bidId').and.to.equal(defaultRequest.bidId);
+ expect(request).to.have.property('auctionId').and.to.equal(defaultRequest.ortb2.source.tid);
+ expect(request).to.have.property('transactionId').and.to.equal(defaultRequest.ortb2Imp.ext.tid);
+ expect(request).to.have.property('tz').and.to.equal(new Date().getTimezoneOffset());
+ expect(request).to.have.property('bc').and.to.equal(1);
+ expect(request).to.have.property('floor').and.to.equal(null);
+ expect(request).to.have.property('banner').and.to.deep.equal({sizes: [[300, 250], [300, 200]]});
+ expect(request).to.have.property('gdprApplies').and.to.equal(0);
+ expect(request).to.have.property('consentString').and.to.equal('');
+ expect(request).to.have.property('userEids').and.to.deep.equal([]);
+ expect(request).to.have.property('usPrivacy').and.to.equal('');
+ expect(request).to.have.property('coppa').and.to.equal(0);
+ expect(request).to.have.property('sizes').and.to.deep.equal(['300x250', '300x200']);
+ expect(request).to.have.property('ext').and.to.deep.equal({});
+ expect(request).to.have.property('env').and.to.deep.equal({
+ env: 'iqx',
+ pid: '40'
+ });
+ expect(request).to.have.property('device').and.to.deep.equal({
+ ua: navigator.userAgent,
+ lang: navigator.language
+ });
+ });
+
+ it('should build request with schain', function () {
+ const schainRequest = deepClone(defaultRequest);
+ schainRequest.schain = {
+ validation: 'strict',
+ config: {
+ ver: '1.0'
+ }
+ };
+ const request = JSON.parse(spec.buildRequests([schainRequest], {}).data)[0];
+ expect(request).to.have.property('schain').and.to.deep.equal({
+ validation: 'strict',
+ config: {
+ ver: '1.0'
+ }
+ });
+ });
+
+ it('should build request with location', function () {
+ const bidderRequest = {
+ refererInfo: {
+ page: 'page',
+ location: 'location',
+ domain: 'domain',
+ ref: 'ref',
+ isAmp: false
+ }
+ };
+ const request = JSON.parse(spec.buildRequests([defaultRequest], bidderRequest).data)[0];
+ expect(request).to.have.property('location');
+ const location = request.location;
+ expect(location).to.have.property('page').and.to.equal('page');
+ expect(location).to.have.property('location').and.to.equal('location');
+ expect(location).to.have.property('domain').and.to.equal('domain');
+ expect(location).to.have.property('ref').and.to.equal('ref');
+ expect(location).to.have.property('isAmp').and.to.equal(false);
+ });
+
+ it('should build request with ortb2 info', function () {
+ const ortb2Request = deepClone(defaultRequest);
+ ortb2Request.ortb2 = {
+ site: {
+ name: 'name'
+ }
+ };
+ const request = JSON.parse(spec.buildRequests([ortb2Request], {}).data)[0];
+ expect(request).to.have.property('ortb2').and.to.deep.equal({
+ site: {
+ name: 'name'
+ }
+ });
+ });
+
+ it('should build request with ortb2Imp info', function () {
+ const ortb2ImpRequest = deepClone(defaultRequest);
+ ortb2ImpRequest.ortb2Imp = {
+ ext: {
+ data: {
+ pbadslot: 'home1',
+ adUnitSpecificAttribute: '1'
+ }
+ }
+ };
+ const request = JSON.parse(spec.buildRequests([ortb2ImpRequest], {}).data)[0];
+ expect(request).to.have.property('ortb2Imp').and.to.deep.equal({
+ ext: {
+ data: {
+ pbadslot: 'home1',
+ adUnitSpecificAttribute: '1'
+ }
+ }
+ });
+ });
+
+ it('should build request with valid bidfloor', function () {
+ const bfRequest = deepClone(defaultRequest);
+ bfRequest.getFloor = () => ({floor: 5, currency: 'USD'});
+ const request = JSON.parse(spec.buildRequests([bfRequest], {}).data)[0];
+ expect(request).to.have.property('floor').and.to.equal(5);
+ });
+
+ it('should build request with gdpr consent data if applies', function () {
+ const bidderRequest = {
+ gdprConsent: {
+ gdprApplies: true,
+ consentString: 'qwerty'
+ }
+ };
+ const request = JSON.parse(spec.buildRequests([defaultRequest], bidderRequest).data)[0];
+ expect(request).to.have.property('gdprApplies').and.equals(1);
+ expect(request).to.have.property('consentString').and.equals('qwerty');
+ });
+
+ it('should build request with usp consent data if applies', function () {
+ const bidderRequest = {
+ uspConsent: '1YA-'
+ };
+ const request = JSON.parse(spec.buildRequests([defaultRequest], bidderRequest).data)[0];
+ expect(request).to.have.property('usPrivacy').and.equals('1YA-');
+ });
+
+ it('should build request with coppa 1', function () {
+ config.setConfig({
+ coppa: true
+ });
+ const request = JSON.parse(spec.buildRequests([defaultRequest], {}).data)[0];
+ expect(request).to.have.property('coppa').and.equals(1);
+ });
+
+ it('should build request with extended ids', function () {
+ const idRequest = deepClone(defaultRequest);
+ idRequest.userIdAsEids = [
+ {source: 'adserver.org', uids: [{id: 'TTD_ID_FROM_USER_ID_MODULE', atype: 1, ext: {rtiPartner: 'TDID'}}]},
+ {source: 'pubcid.org', uids: [{id: 'pubCommonId_FROM_USER_ID_MODULE', atype: 1}]}
+ ];
+ const request = JSON.parse(spec.buildRequests([idRequest], {}).data)[0];
+ expect(request).to.have.property('userEids').and.deep.equal(idRequest.userIdAsEids);
+ });
+
+ it('should build request with video', function () {
+ const request = JSON.parse(spec.buildRequests([defaultRequestVideo], {}).data)[0];
+ expect(request).to.have.property('video').and.to.deep.equal({
+ playerSize: [640, 480],
+ context: 'instream',
+ skipppable: true
+ });
+ expect(request).to.have.property('sizes').and.to.deep.equal(['640x480']);
+ });
+ });
+
+ describe('interpretResponse', function () {
+ it('should return empty bids', function () {
+ const serverResponse = {
+ body: {
+ data: null
+ }
+ };
+
+ const invalidResponse = spec.interpretResponse(serverResponse, {});
+ expect(invalidResponse).to.be.an('array').that.is.empty;
+ });
+
+ it('should interpret valid response', function () {
+ const serverResponse = {
+ body: {
+ data: [{
+ requestId: 'qwerty',
+ cpm: 1,
+ currency: 'USD',
+ width: 300,
+ height: 250,
+ ttl: 600,
+ meta: {
+ advertiserDomains: ['iqx']
+ },
+ ext: {
+ pixels: [
+ ['iframe', 'surl1'],
+ ['image', 'surl2'],
+ ]
+ }
+ }]
+ }
+ };
+
+ const validResponse = spec.interpretResponse(serverResponse, {bidderRequest: defaultRequest});
+ const bid = validResponse[0];
+ expect(validResponse).to.be.an('array').that.is.not.empty;
+ expect(bid.requestId).to.equal('qwerty');
+ expect(bid.cpm).to.equal(1);
+ expect(bid.currency).to.equal('USD');
+ expect(bid.width).to.equal(300);
+ expect(bid.height).to.equal(250);
+ expect(bid.ttl).to.equal(600);
+ expect(bid.meta).to.deep.equal({advertiserDomains: ['iqx']});
+ });
+
+ it('should interpret valid banner response', function () {
+ const serverResponse = {
+ body: {
+ data: [{
+ requestId: 'qwerty',
+ cpm: 1,
+ currency: 'USD',
+ width: 300,
+ height: 250,
+ ttl: 600,
+ mediaType: 'banner',
+ creativeId: 'xe-demo-banner',
+ ad: 'ad',
+ meta: {}
+ }]
+ }
+ };
+
+ const validResponseBanner = spec.interpretResponse(serverResponse, {bidderRequest: defaultRequest});
+ const bid = validResponseBanner[0];
+ expect(validResponseBanner).to.be.an('array').that.is.not.empty;
+ expect(bid.mediaType).to.equal('banner');
+ expect(bid.creativeId).to.equal('xe-demo-banner');
+ expect(bid.ad).to.equal('ad');
+ });
+
+ it('should interpret valid video response', function () {
+ const serverResponse = {
+ body: {
+ data: [{
+ requestId: 'qwerty',
+ cpm: 1,
+ currency: 'USD',
+ width: 600,
+ height: 480,
+ ttl: 600,
+ mediaType: 'video',
+ creativeId: 'xe-demo-video',
+ ad: 'vast-xml',
+ meta: {}
+ }]
+ }
+ };
+
+ const validResponseBanner = spec.interpretResponse(serverResponse, {bidderRequest: defaultRequestVideo});
+ const bid = validResponseBanner[0];
+ expect(validResponseBanner).to.be.an('array').that.is.not.empty;
+ expect(bid.mediaType).to.equal('video');
+ expect(bid.creativeId).to.equal('xe-demo-video');
+ expect(bid.ad).to.equal('vast-xml');
+ });
+ });
+
+ describe('getUserSyncs', function () {
+ it('shoukd handle no params', function () {
+ const opts = spec.getUserSyncs({}, []);
+ expect(opts).to.be.an('array').that.is.empty;
+ });
+
+ it('should return empty if sync is not allowed', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: false});
+ expect(opts).to.be.an('array').that.is.empty;
+ });
+
+ it('should allow iframe sync', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: false}, [{
+ body: {
+ data: [{
+ requestId: 'qwerty',
+ ext: {
+ pixels: [
+ ['iframe', 'surl1?a=b'],
+ ['image', 'surl2?a=b'],
+ ]
+ }
+ }]
+ }
+ }]);
+ expect(opts.length).to.equal(1);
+ expect(opts[0].type).to.equal('iframe');
+ expect(opts[0].url).to.equal('surl1?a=b&us_privacy=&gdpr=0&gdpr_consent=');
+ });
+
+ it('should allow pixel sync', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, [{
+ body: {
+ data: [{
+ requestId: 'qwerty',
+ ext: {
+ pixels: [
+ ['iframe', 'surl1?a=b'],
+ ['image', 'surl2?a=b'],
+ ]
+ }
+ }]
+ }
+ }]);
+ expect(opts.length).to.equal(1);
+ expect(opts[0].type).to.equal('image');
+ expect(opts[0].url).to.equal('surl2?a=b&us_privacy=&gdpr=0&gdpr_consent=');
+ });
+
+ it('should allow pixel sync and parse consent params', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, [{
+ body: {
+ data: [{
+ requestId: 'qwerty',
+ ext: {
+ pixels: [
+ ['iframe', 'surl1?a=b'],
+ ['image', 'surl2?a=b'],
+ ]
+ }
+ }]
+ }
+ }], {
+ gdprApplies: 1,
+ consentString: '1YA-'
+ });
+ expect(opts.length).to.equal(1);
+ expect(opts[0].type).to.equal('image');
+ expect(opts[0].url).to.equal('surl2?a=b&us_privacy=&gdpr=1&gdpr_consent=1YA-');
+ });
+ });
+
+ describe('getBidFloor', function () {
+ it('should return null when getFloor is not a function', () => {
+ const bid = {getFloor: 2};
+ const result = getBidFloor(bid);
+ expect(result).to.be.null;
+ });
+
+ it('should return null when getFloor doesnt return an object', () => {
+ const bid = {getFloor: () => 2};
+ const result = getBidFloor(bid);
+ expect(result).to.be.null;
+ });
+
+ it('should return null when floor is not a number', () => {
+ const bid = {
+ getFloor: () => ({floor: 'string', currency: 'USD'})
+ };
+ const result = getBidFloor(bid);
+ expect(result).to.be.null;
+ });
+
+ it('should return null when currency is not USD', () => {
+ const bid = {
+ getFloor: () => ({floor: 5, currency: 'EUR'})
+ };
+ const result = getBidFloor(bid);
+ expect(result).to.be.null;
+ });
+
+ it('should return floor value when everything is correct', () => {
+ const bid = {
+ getFloor: () => ({floor: 5, currency: 'USD'})
+ };
+ const result = getBidFloor(bid);
+ expect(result).to.equal(5);
+ });
+ });
+})
diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js
index 853215d95ad..7655868ffc3 100644
--- a/test/spec/modules/ixBidAdapter_spec.js
+++ b/test/spec/modules/ixBidAdapter_spec.js
@@ -188,6 +188,35 @@ describe('IndexexchangeAdapter', function () {
}
];
+ const DEFAULT_BANNER_VALID_BID_WITH_FLEDGE_ENABLED = [
+ {
+ bidder: 'ix',
+ params: {
+ siteId: '123',
+ size: [300, 250]
+ },
+ sizes: [[300, 250], [300, 600]],
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250], [300, 600]],
+ pos: 0
+ }
+ },
+ ortb2Imp: {
+ ext: {
+ tid: '173f49a8-7549-4218-a23c-e7ba59b47229',
+ ae: 1 // Fledge enabled
+ },
+ },
+ adUnitCode: 'div-fledge-ad-1460505748561-0',
+ transactionId: '173f49a8-7549-4218-a23c-e7ba59b47229',
+ bidId: '1a2b3c4d',
+ bidderRequestId: '11a22b33c44d',
+ auctionId: '1aa2bb3cc4dd',
+ schain: SAMPLE_SCHAIN
+ }
+ ];
+
const DEFAULT_BANNER_VALID_BID_PARAM_NO_SIZE = [
{
bidder: 'ix',
@@ -596,6 +625,45 @@ describe('IndexexchangeAdapter', function () {
]
};
+ const DEFAULT_BANNER_BID_RESPONSE_WITH_DSA = {
+ cur: 'USD',
+ id: '11a22b33c44d',
+ seatbid: [
+ {
+ bid: [
+ {
+ crid: '12345',
+ adomain: ['www.abc.com'],
+ adid: '14851455',
+ impid: '1a2b3c4d',
+ cid: '3051266',
+ price: 100,
+ w: 300,
+ h: 250,
+ id: '1',
+ ext: {
+ dspid: 50,
+ pricelevel: '_100',
+ advbrandid: 303325,
+ advbrand: 'OECTA',
+ dsa: {
+ behalf: 'Advertiser',
+ paid: 'Advertiser',
+ transparency: [{
+ domain: 'dsp1domain.com',
+ dsaparams: [1, 2]
+ }],
+ 'adrender': 1
+ }
+ },
+ adm: '
'
+ }
+ ],
+ seat: '3970'
+ }
+ ]
+ };
+
const DEFAULT_BANNER_BID_RESPONSE_WITHOUT_ADOMAIN = {
cur: 'USD',
id: '11a22b33c44d',
@@ -735,6 +803,49 @@ describe('IndexexchangeAdapter', function () {
}
};
+ const DEFAULT_OPTION_FLEDGE_ENABLED_GLOBALLY = {
+ gdprConsent: {
+ gdprApplies: true,
+ consentString: '3huaa11=qu3198ae',
+ vendorData: {}
+ },
+ refererInfo: {
+ page: 'https://www.prebid.org',
+ canonicalUrl: 'https://www.prebid.org/the/link/to/the/page'
+ },
+ ortb2: {
+ site: {
+ page: 'https://www.prebid.org'
+ },
+ source: {
+ tid: 'mock-tid'
+ }
+ },
+ fledgeEnabled: true,
+ defaultForSlots: 1
+ };
+
+ const DEFAULT_OPTION_FLEDGE_ENABLED = {
+ gdprConsent: {
+ gdprApplies: true,
+ consentString: '3huaa11=qu3198ae',
+ vendorData: {}
+ },
+ refererInfo: {
+ page: 'https://www.prebid.org',
+ canonicalUrl: 'https://www.prebid.org/the/link/to/the/page'
+ },
+ ortb2: {
+ site: {
+ page: 'https://www.prebid.org'
+ },
+ source: {
+ tid: 'mock-tid'
+ }
+ },
+ fledgeEnabled: true
+ };
+
const DEFAULT_IDENTITY_RESPONSE = {
IdentityIp: {
responsePending: false,
@@ -760,6 +871,8 @@ describe('IndexexchangeAdapter', function () {
id5id: { uid: 'testid5id' }, // ID5
imuid: 'testimuid',
'33acrossId': { envelope: 'v1.5fs.1000.fjdiosmclds' },
+ 'criteoID': { envelope: 'testcriteoID' },
+ 'euidID': { envelope: 'testeuid' },
pairId: {envelope: 'testpairId'}
};
@@ -819,6 +932,16 @@ describe('IndexexchangeAdapter', function () {
uids: [{
id: DEFAULT_USERID_DATA['33acrossId'].envelope
}]
+ }, {
+ source: 'criteo.com',
+ uids: [{
+ id: DEFAULT_USERID_DATA['criteoID'].envelope
+ }]
+ }, {
+ source: 'euid.eu',
+ uids: [{
+ id: DEFAULT_USERID_DATA['euidID'].envelope
+ }]
}, {
source: 'google.com',
uids: [{
@@ -835,6 +958,23 @@ describe('IndexexchangeAdapter', function () {
const extractPayload = function (bidRequest) { return bidRequest.data }
+ const generateEid = function (numEid) {
+ const eids = [];
+
+ for (let i = 1; i <= numEid; i++) {
+ const newEid = {
+ source: `eid_source_${i}.com`,
+ uids: [{
+ id: `uid_id_${i}`,
+ }]
+ };
+
+ eids.push(newEid);
+ }
+
+ return eids;
+ }
+
describe('inherited functions', function () {
it('should exists and is a function', function () {
const adapter = newBidder(spec);
@@ -1230,7 +1370,7 @@ describe('IndexexchangeAdapter', function () {
const payload = extractPayload(request[0]);
expect(request).to.be.an('array');
expect(request).to.have.lengthOf.above(0); // should be 1 or more
- expect(payload.user.eids).to.have.lengthOf(9);
+ expect(payload.user.eids).to.have.lengthOf(11);
expect(payload.user.eids).to.deep.include(DEFAULT_USERID_PAYLOAD[0]);
});
});
@@ -1401,6 +1541,17 @@ describe('IndexexchangeAdapter', function () {
describe('buildRequestsUserId', function () {
let validIdentityResponse;
let validUserIdPayload;
+ const serverResponse = {
+ body: {
+ ext: {
+ pbjs_allow_all_eids: {
+ test: {
+ activated: false
+ }
+ }
+ }
+ }
+ };
beforeEach(function () {
window.headertag = {};
@@ -1411,6 +1562,12 @@ describe('IndexexchangeAdapter', function () {
afterEach(function () {
delete window.headertag;
+ serverResponse.body.ext.features = {
+ pbjs_allow_all_eids: {
+ activated: false
+ }
+ };
+ validIdentityResponse = {}
});
it('IX adapter reads supported user modules from Prebid and adds it to Video', function () {
@@ -1418,10 +1575,95 @@ describe('IndexexchangeAdapter', function () {
cloneValidBid[0].userIdAsEids = utils.deepClone(DEFAULT_USERIDASEIDS_DATA);
const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0];
const payload = extractPayload(request);
- expect(payload.user.eids).to.have.lengthOf(9);
+ expect(payload.user.eids).to.have.lengthOf(11);
expect(payload.user.eids).to.have.deep.members(DEFAULT_USERID_PAYLOAD);
});
+ it('IX adapter filters eids from prebid past the maximum eid limit', function () {
+ serverResponse.body.ext.features = {
+ pbjs_allow_all_eids: {
+ activated: true
+ }
+ };
+ FEATURE_TOGGLES.setFeatureToggles(serverResponse);
+ const cloneValidBid = utils.deepClone(DEFAULT_VIDEO_VALID_BID);
+ let eid_sent_from_prebid = generateEid(55);
+ cloneValidBid[0].userIdAsEids = utils.deepClone(eid_sent_from_prebid);
+ const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0];
+ const payload = extractPayload(request);
+ expect(payload.user.eids).to.have.lengthOf(50);
+ let eid_accepted = eid_sent_from_prebid.slice(0, 50);
+ expect(payload.user.eids).to.have.deep.members(eid_accepted);
+ expect(payload.ext.ixdiag.eidLength).to.equal(55);
+ });
+
+ it('IX adapter filters eids from IXL past the maximum eid limit', function () {
+ validIdentityResponse = {
+ MerkleIp: {
+ responsePending: false,
+ data: {
+ source: 'merkle.com',
+ uids: [{
+ id: '1234-5678-9012-3456',
+ ext: {
+ keyID: '1234-5678',
+ enc: 1
+ }
+ }]
+ }
+ },
+ LiveIntentIp: {
+ responsePending: false,
+ data: {
+ source: 'liveintent.com',
+ uids: [{
+ id: '1234-5678-9012-3456',
+ ext: {
+ keyID: '1234-5678',
+ rtiPartner: 'LDID',
+ enc: 1
+ }
+ }]
+ }
+ }
+ };
+ serverResponse.body.ext.features = {
+ pbjs_allow_all_eids: {
+ activated: true
+ }
+ };
+ FEATURE_TOGGLES.setFeatureToggles(serverResponse);
+ const cloneValidBid = utils.deepClone(DEFAULT_VIDEO_VALID_BID);
+ let eid_sent_from_prebid = generateEid(49);
+ cloneValidBid[0].userIdAsEids = utils.deepClone(eid_sent_from_prebid);
+ const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0];
+ const payload = extractPayload(request);
+ expect(payload.user.eids).to.have.lengthOf(50);
+ eid_sent_from_prebid.push({
+ source: 'merkle.com',
+ uids: [{
+ id: '1234-5678-9012-3456',
+ ext: {
+ keyID: '1234-5678',
+ enc: 1
+ }
+ }]
+ })
+ expect(payload.user.eids).to.have.deep.members(eid_sent_from_prebid);
+ expect(payload.ext.ixdiag.eidLength).to.equal(49);
+ });
+
+ it('All incoming eids are from unsupported source with feature toggle off', function () {
+ FEATURE_TOGGLES.setFeatureToggles(serverResponse);
+ const cloneValidBid = utils.deepClone(DEFAULT_VIDEO_VALID_BID);
+ let eid_sent_from_prebid = generateEid(20);
+ cloneValidBid[0].userIdAsEids = utils.deepClone(eid_sent_from_prebid);
+ const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0];
+ const payload = extractPayload(request);
+ expect(payload.user.eids).to.be.undefined
+ expect(payload.ext.ixdiag.eidLength).to.equal(20);
+ });
+
it('We continue to send in IXL identity info and Prebid takes precedence over IXL', function () {
validIdentityResponse = {
AdserverOrgIp: {
@@ -1551,7 +1793,7 @@ describe('IndexexchangeAdapter', function () {
})
expect(payload.user).to.exist;
- expect(payload.user.eids).to.have.lengthOf(11);
+ expect(payload.user.eids).to.have.lengthOf(13);
expect(payload.user.eids).to.have.deep.members(validUserIdPayload);
});
@@ -1593,7 +1835,7 @@ describe('IndexexchangeAdapter', function () {
});
const payload = extractPayload(request);
- expect(payload.user.eids).to.have.lengthOf(10);
+ expect(payload.user.eids).to.have.lengthOf(12);
expect(payload.user.eids).to.have.deep.members(validUserIdPayload);
});
});
@@ -1700,6 +1942,72 @@ describe('IndexexchangeAdapter', function () {
expect(r.user.testProperty).to.be.undefined;
});
+ it('should set dsa field when defined', function () {
+ const dsa = {
+ dsarequired: 3,
+ pubrender: 0,
+ datatopub: 2,
+ transparency: [{
+ domain: 'domain.com',
+ dsaparams: [1]
+ }]
+ }
+ const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2: {regs: {
+ ext: {
+ dsa: deepClone(dsa)
+ }
+ }
+ }})[0];
+ const r = extractPayload(request);
+
+ expect(r.regs.ext.dsa.dsarequired).to.equal(dsa.dsarequired);
+ expect(r.regs.ext.dsa.pubrender).to.equal(dsa.pubrender);
+ expect(r.regs.ext.dsa.datatopub).to.equal(dsa.datatopub);
+ expect(r.regs.ext.dsa.transparency).to.be.an('array');
+ expect(r.regs.ext.dsa.transparency).to.have.deep.members(dsa.transparency);
+ });
+ it('should not set dsa fields when fields arent appropriately defined', function () {
+ const dsa = {
+ dsarequired: '3',
+ pubrender: '0',
+ datatopub: '2',
+ transparency: 20
+ }
+ const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2: {regs: {
+ ext: {
+ dsa: deepClone(dsa)
+ }
+ }
+ }})[0];
+ const r = extractPayload(request);
+
+ expect(r.regs).to.be.undefined;
+ });
+ it('should not set dsa transparency when fields arent appropriately defined', function () {
+ const dsa = {
+ transparency: [{
+ domain: 3,
+ dsaparams: [1]
+ },
+ {
+ domain: 'domain.com',
+ dsaparams: 'params'
+ },
+ {
+ domain: 'domain.com',
+ dsaparams: ['1']
+ }]
+ }
+ const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2: {regs: {
+ ext: {
+ dsa: deepClone(dsa)
+ }
+ }
+ }})[0];
+ const r = extractPayload(request);
+
+ expect(r.regs).to.be.undefined;
+ });
it('should set gpp and gpp_sid field when defined', function () {
const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2: {regs: {gpp: 'gpp', gpp_sid: [1]}} })[0];
const r = extractPayload(request);
@@ -1708,7 +2016,7 @@ describe('IndexexchangeAdapter', function () {
expect(r.regs.gpp_sid).to.be.an('array');
expect(r.regs.gpp_sid).to.include(1);
});
- it('should not set gpp and gpp_sid field when not defined', function () {
+ it('should not set gpp, gpp_sid and dsa field when not defined', function () {
const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, { ortb2: {regs: {}} })[0];
const r = extractPayload(request);
@@ -3146,6 +3454,149 @@ describe('IndexexchangeAdapter', function () {
});
});
+ describe('buildRequestFledge', function () {
+ it('impression should have ae=1 in ext when fledge module is enabled and ae is set in ad unit', function () {
+ const bidderRequest = deepClone(DEFAULT_OPTION_FLEDGE_ENABLED);
+ const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID_WITH_FLEDGE_ENABLED[0]);
+ const requestBidFloor = spec.buildRequests([bid], bidderRequest)[0];
+ const impression = extractPayload(requestBidFloor).imp[0];
+
+ expect(impression.ext.ae).to.equal(1);
+ });
+
+ it('impression should have ae=1 in ext when fledge module is enabled globally and default is set through setConfig', function () {
+ const bidderRequest = deepClone(DEFAULT_OPTION_FLEDGE_ENABLED_GLOBALLY);
+ const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]);
+ const requestBidFloor = spec.buildRequests([bid], bidderRequest)[0];
+ const impression = extractPayload(requestBidFloor).imp[0];
+
+ expect(impression.ext.ae).to.equal(1);
+ });
+
+ it('impression should have ae=1 in ext when fledge module is enabled globally but no default set through setConfig but set at ad unit level', function () {
+ const bidderRequest = deepClone(DEFAULT_OPTION_FLEDGE_ENABLED);
+ const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID_WITH_FLEDGE_ENABLED[0]);
+ const requestBidFloor = spec.buildRequests([bid], bidderRequest)[0];
+ const impression = extractPayload(requestBidFloor).imp[0];
+
+ expect(impression.ext.ae).to.equal(1);
+ });
+
+ it('impression should not have ae=1 in ext when fledge module is enabled globally through setConfig but overidden at ad unit level', function () {
+ const bidderRequest = deepClone(DEFAULT_OPTION_FLEDGE_ENABLED);
+ const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]);
+ const requestBidFloor = spec.buildRequests([bid], bidderRequest)[0];
+ const impression = extractPayload(requestBidFloor).imp[0];
+
+ expect(impression.ext.ae).to.be.undefined;
+ });
+
+ it('impression should not have ae=1 in ext when fledge module is disabled', function () {
+ const bidderRequest = deepClone(DEFAULT_OPTION);
+ const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]);
+ const requestBidFloor = spec.buildRequests([bid], bidderRequest)[0];
+ const impression = extractPayload(requestBidFloor).imp[0];
+
+ expect(impression.ext.ae).to.be.undefined;
+ });
+
+ it('should contain correct IXdiag ae property for Fledge', function () {
+ const bid = DEFAULT_BANNER_VALID_BID_WITH_FLEDGE_ENABLED[0];
+ const bidderRequestWithFledgeEnabled = deepClone(DEFAULT_OPTION_FLEDGE_ENABLED);
+ const request = spec.buildRequests([bid], bidderRequestWithFledgeEnabled);
+ const diagObj = extractPayload(request[0]).ext.ixdiag;
+ expect(diagObj.ae).to.equal(true);
+ });
+
+ it('should log warning for non integer auction environment in ad unit for fledge', () => {
+ const logWarnSpy = sinon.spy(utils, 'logWarn');
+ const bid = DEFAULT_BANNER_VALID_BID_WITH_FLEDGE_ENABLED[0];
+ bid.ortb2Imp.ext.ae = 'malformed'
+ const bidderRequestWithFledgeEnabled = deepClone(DEFAULT_OPTION_FLEDGE_ENABLED);
+ spec.buildRequests([bid], bidderRequestWithFledgeEnabled);
+ expect(logWarnSpy.calledWith('error setting auction environment flag - must be an integer')).to.be.true;
+ logWarnSpy.restore();
+ });
+ });
+
+ describe('integration through exchangeId and externalId', function () {
+ const expectedExchangeId = 123456;
+ // create banner bids with externalId but no siteId as bidder param
+ const bannerBids = utils.deepClone(DEFAULT_BANNER_VALID_BID);
+ delete bannerBids[0].params.siteId;
+ bannerBids[0].params.externalId = 'exteranl_id_1';
+
+ beforeEach(() => {
+ config.setConfig({ exchangeId: expectedExchangeId });
+ spec.resetSiteID();
+ });
+
+ afterEach(() => {
+ config.resetConfig();
+ });
+
+ it('when exchangeId and externalId set but no siteId, isBidRequestValid should return true', function () {
+ const bid = utils.deepClone(bannerBids[0]);
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+
+ it('when neither exchangeId nor siteId set, isBidRequestValid should return false', function () {
+ config.resetConfig();
+ const bid = utils.deepClone(bannerBids[0]);
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+
+ it('when exchangeId and externalId set with banner impression but no siteId, bidrequest sent to endpoint with p param and externalID inside imp.ext', function () {
+ const requests = spec.buildRequests(bannerBids, DEFAULT_OPTION);
+ const payload = extractPayload(requests[0]);
+
+ const expectedURL = IX_SECURE_ENDPOINT + '?p=' + expectedExchangeId;
+ expect(requests[0].url).to.equal(expectedURL);
+ expect(payload.imp[0].ext.externalID).to.equal(bannerBids[0].params.externalId);
+ expect(payload.imp[0].banner.format[0].ext).to.be.undefined;
+ expect(payload.imp[0].ext.siteID).to.be.undefined;
+ });
+
+ it('when exchangeId and externalId set with video impression, bidrequest sent to endpoint with p param and externalID inside imp.ext', function () {
+ const validBids = utils.deepClone(DEFAULT_VIDEO_VALID_BID);
+ delete validBids[0].params.siteId;
+ validBids[0].params.externalId = 'exteranl_id_1';
+
+ const requests = spec.buildRequests(validBids, DEFAULT_OPTION);
+ const payload = extractPayload(requests[0]);
+
+ const expectedURL = IX_SECURE_ENDPOINT + '?p=' + expectedExchangeId;
+ expect(requests[0].url).to.equal(expectedURL);
+ expect(payload.imp[0].ext.externalID).to.equal(validBids[0].params.externalId);
+ expect(payload.imp[0].ext.siteID).to.be.undefined;
+ });
+
+ it('when exchangeId and externalId set beside siteId, bidrequest sent to endpoint with both p param and s param and externalID inside imp.ext and siteID inside imp.banner.format.ext', function () {
+ bannerBids[0].params.siteId = '1234';
+ const requests = spec.buildRequests(bannerBids, DEFAULT_OPTION);
+ const payload = extractPayload(requests[0]);
+
+ const expectedURL = IX_SECURE_ENDPOINT + '?s=' + bannerBids[0].params.siteId + '&p=' + expectedExchangeId;
+ expect(requests[0].url).to.equal(expectedURL);
+ expect(payload.imp[0].ext.externalID).to.equal(bannerBids[0].params.externalId);
+ expect(payload.imp[0].banner.format[0].ext.externalID).to.be.undefined;
+ expect(payload.imp[0].ext.siteID).to.be.undefined;
+ expect(payload.imp[0].banner.format[0].ext.siteID).to.equal(bannerBids[0].params.siteId);
+ });
+
+ it('when exchangeId and siteId set, but no externalId, bidrequest sent to exchange', function () {
+ bannerBids[0].params.siteId = '1234';
+ delete bannerBids[0].params.externalId;
+ const requests = spec.buildRequests(bannerBids, DEFAULT_OPTION);
+ const payload = extractPayload(requests[0]);
+
+ const expectedURL = IX_SECURE_ENDPOINT + '?s=' + bannerBids[0].params.siteId + '&p=' + expectedExchangeId;
+ expect(requests[0].url).to.equal(expectedURL);
+ expect(payload.imp[0].ext.externalID).to.be.undefined;
+ expect(payload.imp[0].banner.format[0].ext.siteID).to.equal(bannerBids[0].params.siteId);
+ });
+ });
+
describe('interpretResponse', function () {
// generate bidderRequest with real buildRequest logic for intepretResponse testing
let bannerBidderRequest
@@ -3183,6 +3634,40 @@ describe('IndexexchangeAdapter', function () {
expect(result[0]).to.deep.equal(expectedParse[0]);
});
+ it('should get correct bid response for banner ad with dsa signals', function () {
+ const expectedParse = [
+ {
+ requestId: '1a2b3c4d',
+ cpm: 1,
+ creativeId: '12345',
+ width: 300,
+ height: 250,
+ mediaType: 'banner',
+ ad: '
',
+ currency: 'USD',
+ ttl: 300,
+ netRevenue: true,
+ meta: {
+ networkId: 50,
+ brandId: 303325,
+ brandName: 'OECTA',
+ advertiserDomains: ['www.abc.com'],
+ dsa: {
+ behalf: 'Advertiser',
+ paid: 'Advertiser',
+ transparency: [{
+ domain: 'dsp1domain.com',
+ dsaparams: [1, 2]
+ }],
+ 'adrender': 1
+ }
+ }
+ }
+ ];
+ const result = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE_WITH_DSA }, bannerBidderRequest);
+ expect(result[0]).to.deep.equal(expectedParse[0]);
+ });
+
it('should get correct bid response for banner ad with missing adomain', function () {
const expectedParse = [
{
@@ -3669,6 +4154,140 @@ describe('IndexexchangeAdapter', function () {
const result = spec.interpretResponse({ body: DEFAULT_NATIVE_BID_RESPONSE }, nativeBidderRequest);
expect(result[0]).to.deep.equal(expectedParse[0]);
});
+
+ describe('Auction config response', function () {
+ let bidderRequestWithFledgeEnabled;
+ let serverResponseWithoutFledgeConfigs;
+ let serverResponseWithFledgeConfigs;
+ let serverResponseWithMalformedAuctionConfig;
+ let serverResponseWithMalformedAuctionConfigs;
+
+ beforeEach(() => {
+ bidderRequestWithFledgeEnabled = spec.buildRequests(DEFAULT_BANNER_VALID_BID_WITH_FLEDGE_ENABLED, {})[0];
+ bidderRequestWithFledgeEnabled.fledgeEnabled = true;
+
+ serverResponseWithoutFledgeConfigs = {
+ body: {
+ ...DEFAULT_BANNER_BID_RESPONSE
+ }
+ };
+
+ serverResponseWithFledgeConfigs = {
+ body: {
+ ...DEFAULT_BANNER_BID_RESPONSE,
+ ext: {
+ protectedAudienceAuctionConfigs: [
+ {
+ bidId: '59f219e54dc2fc',
+ config: {
+ seller: 'https://seller.test.indexexchange.com',
+ decisionLogicUrl: 'https://seller.test.indexexchange.com/decision-logic.js',
+ interestGroupBuyers: ['https://buyer.test.indexexchange.com'],
+ sellerSignals: {
+ callbackURL: 'https://test.com/ig/v1/ck74j8bcvc9c73a8eg6g'
+ },
+ perBuyerSignals: {
+ 'https://buyer.test.indexexchange.com': {}
+ }
+ }
+ }
+ ]
+ }
+ }
+ };
+
+ serverResponseWithMalformedAuctionConfig = {
+ body: {
+ ...DEFAULT_BANNER_BID_RESPONSE,
+ ext: {
+ protectedAudienceAuctionConfigs: ['malformed']
+ }
+ }
+ };
+
+ serverResponseWithMalformedAuctionConfigs = {
+ body: {
+ ...DEFAULT_BANNER_BID_RESPONSE,
+ ext: {
+ protectedAudienceAuctionConfigs: 'malformed'
+ }
+ }
+ };
+ });
+
+ it('should correctly interpret response with auction configs', () => {
+ const result = spec.interpretResponse(serverResponseWithFledgeConfigs, bidderRequestWithFledgeEnabled);
+ const expectedOutput = [
+ {
+ bidId: '59f219e54dc2fc',
+ config: {
+ ...serverResponseWithFledgeConfigs.body.ext.protectedAudienceAuctionConfigs[0].config,
+ perBuyerSignals: {
+ 'https://buyer.test.indexexchange.com': {}
+ }
+ }
+ }
+ ];
+ expect(result.fledgeAuctionConfigs).to.deep.equal(expectedOutput);
+ });
+
+ it('should correctly interpret response without auction configs', () => {
+ const result = spec.interpretResponse(serverResponseWithoutFledgeConfigs, bidderRequestWithFledgeEnabled);
+ expect(result.fledgeAuctionConfigs).to.be.undefined;
+ });
+
+ it('should handle malformed auction configs gracefully', () => {
+ const result = spec.interpretResponse(serverResponseWithMalformedAuctionConfig, bidderRequestWithFledgeEnabled);
+ expect(result.fledgeAuctionConfigs).to.be.empty;
+ });
+
+ it('should log warning for malformed auction configs', () => {
+ const logWarnSpy = sinon.spy(utils, 'logWarn');
+ spec.interpretResponse(serverResponseWithMalformedAuctionConfig, bidderRequestWithFledgeEnabled);
+ expect(logWarnSpy.calledWith('Malformed auction config detected:', 'malformed')).to.be.true;
+ logWarnSpy.restore();
+ });
+
+ it('should return bids when protected audience auction conigs is malformed', () => {
+ const result = spec.interpretResponse(serverResponseWithMalformedAuctionConfigs, bidderRequestWithFledgeEnabled);
+ expect(result.fledgeAuctionConfigs).to.be.undefined;
+ expect(result.length).to.be.greaterThan(0);
+ });
+ });
+
+ describe('interpretResponse when server response is empty', function() {
+ let serverResponseWithoutBody;
+ let serverResponseWithoutSeatbid;
+ let bidderRequestWithFledgeEnabled;
+ let bidderRequestWithoutFledgeEnabled;
+
+ beforeEach(() => {
+ serverResponseWithoutBody = {};
+
+ serverResponseWithoutSeatbid = {
+ body: {}
+ };
+
+ bidderRequestWithFledgeEnabled = spec.buildRequests(DEFAULT_BANNER_VALID_BID_WITH_FLEDGE_ENABLED, {})[0];
+ bidderRequestWithFledgeEnabled.fledgeEnabled = true;
+
+ bidderRequestWithoutFledgeEnabled = spec.buildRequests(DEFAULT_BANNER_VALID_BID, {})[0];
+ });
+
+ it('should return empty bids when response does not have body', function () {
+ let result = spec.interpretResponse(serverResponseWithoutBody, bidderRequestWithFledgeEnabled);
+ expect(result).to.deep.equal([]);
+ result = spec.interpretResponse(serverResponseWithoutBody, bidderRequestWithoutFledgeEnabled);
+ expect(result).to.deep.equal([]);
+ });
+
+ it('should return empty bids when response body does not have seatbid', function () {
+ let result = spec.interpretResponse(serverResponseWithoutSeatbid, bidderRequestWithFledgeEnabled);
+ expect(result).to.deep.equal([]);
+ result = spec.interpretResponse(serverResponseWithoutSeatbid, bidderRequestWithoutFledgeEnabled);
+ expect(result).to.deep.equal([]);
+ });
+ });
});
describe('bidrequest consent', function () {
diff --git a/test/spec/modules/jixieBidAdapter_spec.js b/test/spec/modules/jixieBidAdapter_spec.js
index fd0d7e8a033..5428fd0db0f 100644
--- a/test/spec/modules/jixieBidAdapter_spec.js
+++ b/test/spec/modules/jixieBidAdapter_spec.js
@@ -76,8 +76,11 @@ describe('jixie Adapter', function () {
const jxifoTest1_ = 'fffffbbbbbcccccaaaaae890606aaaaa';
const jxtdidTest1_ = '222223d1-1111-2222-3333-b9f129299999';
const jxcompTest1_ = 'AAAAABBBBBCCCCCDDDDDEEEEEUkkZPQfifpkPnnlJhtsa4o+gf4nfqgN5qHiTVX73ymTSbLT9jz1nf+Q7QdxNh9nTad9UaN5pzfHMt/rs1woQw72c1ip+8heZXPfKGZtZP7ldJesYhlo3/0FVcL/wl9ZlAo1jYOEfHo7Y9zFzNXABbbbbb==';
-
+ const ckname1Val_ = 'ckckname1';
+ const ckname2Val_ = 'ckckname2';
const refJxEids_ = {
+ 'pubid1': ckname1Val_,
+ 'pubid2': ckname2Val_,
'_jxtoko': jxtokoTest1_,
'_jxifo': jxifoTest1_,
'_jxtdid': jxtdidTest1_,
@@ -206,6 +209,17 @@ describe('jixie Adapter', function () {
}
];
+ const testJixieCfg_ = {
+ genids: [
+ { id: 'pubid1', ck: 'ckname1' },
+ { id: 'pubid2', ck: 'ckname2' },
+ { id: '_jxtoko' },
+ { id: '_jxifo' },
+ { id: '_jxtdid' },
+ { id: '_jxcomp' }
+ ]
+ };
+
it('should attach valid params to the adserver endpoint (1)', function () {
// this one we do not intercept the cookie stuff so really don't know
// what will be in there. so we do not check here (using expect)
@@ -216,7 +230,6 @@ describe('jixie Adapter', function () {
})
expect(request.data).to.be.an('string');
const payload = JSON.parse(request.data);
- expect(payload).to.have.property('auctionid', auctionId_);
expect(payload).to.have.property('timeout', timeout_);
expect(payload).to.have.property('currency', currency_);
expect(payload).to.have.property('bids').that.deep.equals(refBids_);
@@ -226,8 +239,25 @@ describe('jixie Adapter', function () {
// similar to above test case but here we force some clientid sessionid values
// and domain, pageurl
// get the interceptors ready:
+ let getConfigStub = sinon.stub(config, 'getConfig');
+ getConfigStub.callsFake(function fakeFn(prop) {
+ if (prop == 'jixie') {
+ return testJixieCfg_;
+ }
+ return null;
+ });
+
let getCookieStub = sinon.stub(storage, 'getCookie');
let getLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage');
+ getCookieStub
+ .withArgs('ckname1')
+ .returns(ckname1Val_);
+ getCookieStub
+ .withArgs('ckname2')
+ .returns(ckname2Val_);
+ getCookieStub
+ .withArgs('_jxtoko')
+ .returns(jxtokoTest1_);
getCookieStub
.withArgs('_jxtoko')
.returns(jxtokoTest1_);
@@ -265,7 +295,6 @@ describe('jixie Adapter', function () {
expect(request.data).to.be.an('string');
const payload = JSON.parse(request.data);
- expect(payload).to.have.property('auctionid', auctionId_);
expect(payload).to.have.property('client_id_c', clientIdTest1_);
expect(payload).to.have.property('client_id_ls', clientIdTest1_);
expect(payload).to.have.property('session_id_c', sessionIdTest1_);
@@ -282,6 +311,7 @@ describe('jixie Adapter', function () {
// unwire interceptors
getCookieStub.restore();
getLocalStorageStub.restore();
+ getConfigStub.restore();
miscDimsStub.restore();
});// it
@@ -362,6 +392,27 @@ describe('jixie Adapter', function () {
expect(payload.bids[0].bidFloor).to.exist.and.to.equal(2.1);
});
+ it('it should populate the aid field when available', function () {
+ let oneSpecialBidReq = deepClone(bidRequests_[0]);
+ // 1 aid is not set in the jixie config
+ let request = spec.buildRequests([oneSpecialBidReq], bidderRequest_);
+ let payload = JSON.parse(request.data);
+ expect(payload.aid).to.eql('');
+
+ // 2 aid is set in the jixie config
+ let getConfigStub = sinon.stub(config, 'getConfig');
+ getConfigStub.callsFake(function fakeFn(prop) {
+ if (prop == 'jixie') {
+ return { aid: '11223344556677889900' };
+ }
+ return null;
+ });
+ request = spec.buildRequests([oneSpecialBidReq], bidderRequest_);
+ payload = JSON.parse(request.data);
+ expect(payload.aid).to.exist.and.to.equal('11223344556677889900');
+ getConfigStub.restore();
+ });
+
it('should populate eids when supported userIds are available', function () {
const oneSpecialBidReq = Object.assign({}, bidRequests_[0], {
userIdAsEids: [
@@ -425,7 +476,6 @@ describe('jixie Adapter', function () {
'bids': [
// video (vast tag url) returned here
{
- 'trackingUrlBase': 'https://traid.jixie.io/sync/ad?',
'jxBidId': '62847e4c696edcb-028d5dee-2c83-44e3-bed1-b75002475cdf',
'requestId': '62847e4c696edcb',
'cpm': 2.19,
@@ -458,7 +508,6 @@ describe('jixie Adapter', function () {
// display ad returned here: This one there is advertiserDomains
// in the response . Will be checked in the unit tests below
{
- 'trackingUrlBase': 'https://traid.jixie.io/sync/ad?',
'jxBidId': '600c9ae6fda1acb-028d5dee-2c83-44e3-bed1-b75002475cdf',
'requestId': '600c9ae6fda1acb',
'cpm': 1.999,
@@ -495,7 +544,6 @@ describe('jixie Adapter', function () {
},
// outstream, jx non-default renderer specified:
{
- 'trackingUrlBase': 'https://traid.jixie.io/sync/ad?',
'jxBidId': '99bc539c81b00ce-028d5dee-2c83-44e3-bed1-b75002475cdf',
'requestId': '99bc539c81b00ce',
'cpm': 2.99,
@@ -514,7 +562,6 @@ describe('jixie Adapter', function () {
},
// outstream, jx default renderer:
{
- 'trackingUrlBase': 'https://traid.jixie.io/sync/ad?',
'jxBidId': '61bc539c81b00ce-028d5dee-2c83-44e3-bed1-b75002475cdf',
'requestId': '61bc539c81b00ce',
'cpm': 1.99,
@@ -585,7 +632,6 @@ describe('jixie Adapter', function () {
expect(result[0].netRevenue).to.equal(true)
expect(result[0].ttl).to.equal(300)
expect(result[0].vastUrl).to.include('https://ad.jixie.io/v1/video?creativeid=')
- expect(result[0].trackingUrlBase).to.include('sync')
// We will always make sure the meta->advertiserDomains property is there
// If no info it is an empty array.
expect(result[0].meta.advertiserDomains.length).to.equal(0)
@@ -601,7 +647,6 @@ describe('jixie Adapter', function () {
expect(result[1].ttl).to.equal(300)
expect(result[1].ad).to.include('jxoutstream')
expect(result[1].meta.advertiserDomains.length).to.equal(3)
- expect(result[1].trackingUrlBase).to.include('sync')
// should pick up about using alternative outstream renderer
expect(result[2].requestId).to.equal('99bc539c81b00ce')
@@ -613,7 +658,6 @@ describe('jixie Adapter', function () {
expect(result[2].netRevenue).to.equal(true)
expect(result[2].ttl).to.equal(300)
expect(result[2].vastXml).to.include('')
- expect(result[2].trackingUrlBase).to.include('sync');
expect(result[2].renderer.id).to.equal('demoslot4-div')
expect(result[2].meta.advertiserDomains.length).to.equal(0)
expect(result[2].renderer.url).to.equal(JX_OTHER_OUTSTREAM_RENDERER_URL);
@@ -628,7 +672,6 @@ describe('jixie Adapter', function () {
expect(result[3].netRevenue).to.equal(true)
expect(result[3].ttl).to.equal(300)
expect(result[3].vastXml).to.include('')
- expect(result[3].trackingUrlBase).to.include('sync');
expect(result[3].renderer.id).to.equal('demoslot2-div')
expect(result[3].meta.advertiserDomains.length).to.equal(0)
expect(result[3].renderer.url).to.equal(JX_OUTSTREAM_RENDERER_URL)
@@ -663,116 +706,68 @@ describe('jixie Adapter', function () {
spec.onBidWon({ trackingUrl: TRACKINGURL_ })
expect(jixieaux.ajax.calledWith(TRACKINGURL_)).to.equal(true);
})
-
- it('Should not fire if the adserver response indicates no firing', function() {
- let called = false;
- ajaxStub.callsFake(function fakeFn() {
- called = true;
- });
- spec.onBidWon({ notrack: 1 })
- expect(called).to.equal(false);
- });
-
- // A reference to check again:
- const QPARAMS_ = {
- action: 'hbbidwon',
- device: device_,
- pageurl: encodeURIComponent(pageurl_),
- domain: encodeURIComponent(domain_),
- cid: 121,
- cpid: 99,
- jxbidid: '62847e4c696edcb-028d5dee-2c83-44e3-bed1-b75002475cdf',
- auctionid: '028d5dee-2c83-44e3-bed1-b75002475cdf',
- cpm: 1.11,
- requestid: '62847e4c696edcb'
- };
-
- it('check it is sending the correct ajax url and qparameters', function() {
- spec.onBidWon({
- trackingUrlBase: 'https://mytracker.com/sync?',
- cid: 121,
- cpid: 99,
- jxBidId: '62847e4c696edcb-028d5dee-2c83-44e3-bed1-b75002475cdf',
- auctionId: '028d5dee-2c83-44e3-bed1-b75002475cdf',
- cpm: 1.11,
- requestId: '62847e4c696edcb'
- })
- expect(jixieaux.ajax.calledWith('https://mytracker.com/sync?', null, QPARAMS_)).to.equal(true);
- });
}); // describe
- /**
- * onTimeout
- */
- describe('onTimeout', function() {
- let ajaxStub;
- let miscDimsStub;
- beforeEach(function() {
- ajaxStub = sinon.stub(jixieaux, 'ajax');
- miscDimsStub = sinon.stub(jixieaux, 'getMiscDims');
- miscDimsStub
- .returns({ device: device_, pageurl: pageurl_, domain: domain_, mkeywords: keywords_ });
- })
-
- afterEach(function() {
- miscDimsStub.restore();
- ajaxStub.restore();
- })
-
- // reference to check against:
- const QPARAMS_ = {
- action: 'hbtimeout',
- device: device_,
- pageurl: encodeURIComponent(pageurl_),
- domain: encodeURIComponent(domain_),
- auctionid: '028d5dee-2c83-44e3-bed1-b75002475cdf',
- timeout: 1000,
- count: 2
- };
-
- it('check it is sending the correct ajax url and qparameters', function() {
- spec.onTimeout([
- {auctionId: '028d5dee-2c83-44e3-bed1-b75002475cdf', timeout: 1000},
- {auctionId: '028d5dee-2c83-44e3-bed1-b75002475cdf', timeout: 1000}
- ])
- expect(jixieaux.ajax.calledWith(spec.EVENTS_URL, null, QPARAMS_)).to.equal(true);
+ describe('getUserSyncs', function () {
+ it('it should favour iframe over pixel if publisher allows iframe usersync', function () {
+ const syncOptions = {
+ 'iframeEnabled': true,
+ 'pixelEnabled': true,
+ }
+ const response = {
+ 'userSyncs': [
+ {
+ 'uf': 'https://syncstuff.jixie.io/',
+ 'up': 'https://syncstuff.jixie.io/image.gif'
+ },
+ {
+ 'up': 'https://syncstuff.jixie.io/image1.gif'
+ }
+ ]
+ }
+ let result = spec.getUserSyncs(syncOptions, [{ body: response }]);
+ expect(result[0].type).to.equal('iframe')
+ expect(result[1].type).to.equal('image')
})
- it('if turned off via config then dont do onTimeout sending of event', function() {
- let getConfigStub = sinon.stub(config, 'getConfig');
- getConfigStub.callsFake(function fakeFn(prop) {
- if (prop == 'jixie') {
- return { onTimeout: 'off' };
- }
- return null;
- });
- let called = false;
- ajaxStub.callsFake(function fakeFn() {
- called = true;
- });
- spec.onTimeout([
- {auctionId: '028d5dee-2c83-44e3-bed1-b75002475cdf', timeout: 1000},
- {auctionId: '028d5dee-2c83-44e3-bed1-b75002475cdf', timeout: 1000}
- ])
- expect(called).to.equal(false);
- getConfigStub.restore();
+ it('it should pick pixel if publisher not allow iframe', function () {
+ const syncOptions = {
+ 'iframeEnabled': false,
+ 'pixelEnabled': true,
+ }
+ const response = {
+ 'userSyncs': [
+ {
+ 'uf': 'https://syncstuff.jixie.io/',
+ 'up': 'https://syncstuff.jixie.io/image.gif'
+ },
+ {
+ 'up': 'https://syncstuff.jixie.io/image1.gif'
+ }
+ ]
+ }
+ let result = spec.getUserSyncs(syncOptions, [{ body: response }]);
+ expect(result[0].type).to.equal('image')
+ expect(result[1].type).to.equal('image')
})
- const otherUrl_ = 'https://other.azurewebsites.net/sync/evt?';
- it('if config specifies a different endpoint then should send there instead', function() {
- let getConfigStub = sinon.stub(config, 'getConfig');
- getConfigStub.callsFake(function fakeFn(prop) {
- if (prop == 'jixie') {
- return { onTimeoutUrl: otherUrl_ };
- }
- return null;
- });
- spec.onTimeout([
- {auctionId: '028d5dee-2c83-44e3-bed1-b75002475cdf', timeout: 1000},
- {auctionId: '028d5dee-2c83-44e3-bed1-b75002475cdf', timeout: 1000}
- ])
- expect(jixieaux.ajax.calledWith(otherUrl_, null, QPARAMS_)).to.equal(true);
- getConfigStub.restore();
+ it('it should return nothing if pub only allow pixel but all usersyncs are iframe only', function () {
+ const syncOptions = {
+ 'iframeEnabled': false,
+ 'pixelEnabled': true,
+ }
+ const response = {
+ 'userSyncs': [
+ {
+ 'uf': 'https://syncstuff.jixie.io/',
+ },
+ {
+ 'uf': 'https://syncstuff2.jixie.io/',
+ }
+ ]
+ }
+ let result = spec.getUserSyncs(syncOptions, [{ body: response }]);
+ expect(result.length).to.equal(0)
})
- });// describe
+ })
});
diff --git a/test/spec/modules/jwplayerRtdProvider_spec.js b/test/spec/modules/jwplayerRtdProvider_spec.js
index 4638595e0d6..12fe9a7e800 100644
--- a/test/spec/modules/jwplayerRtdProvider_spec.js
+++ b/test/spec/modules/jwplayerRtdProvider_spec.js
@@ -237,6 +237,41 @@ describe('jwplayerRtdProvider', function() {
fetchTargetingForMediaId(mediaIdWithSegment);
+ const bid = {};
+ const adUnit = {
+ ortb2Imp: {
+ ext: {
+ data: {
+ jwTargeting: {
+ mediaID: mediaIdWithSegment,
+ playerDivId: validPlayerID
+ }
+ }
+ }
+ },
+ bids: [
+ bid
+ ]
+ };
+ const expectedContentId = 'jw_' + mediaIdWithSegment;
+ const expectedTargeting = {
+ segments: validSegments,
+ content: {
+ id: expectedContentId
+ }
+ };
+ jwplayerSubmodule.getBidRequestData({ adUnits: [adUnit] }, bidRequestSpy);
+ expect(bidRequestSpy.calledOnce).to.be.true;
+ expect(bid.rtd.jwplayer).to.have.deep.property('targeting', expectedTargeting);
+ server.respond();
+ expect(bidRequestSpy.calledOnce).to.be.true;
+ });
+
+ it('includes backwards support for playerID when playerDivId is not set', function () {
+ const bidRequestSpy = sinon.spy();
+
+ fetchTargetingForMediaId(mediaIdWithSegment);
+
const bid = {};
const adUnit = {
ortb2Imp: {
@@ -605,23 +640,23 @@ describe('jwplayerRtdProvider', function() {
it('should prioritize adUnit properties ', function () {
const expectedMediaID = 'test_media_id';
const expectedPlayerID = 'test_player_id';
- const config = { playerID: 'bad_id', mediaID: 'bad_id' };
+ const config = { playerDivId: 'bad_id', mediaID: 'bad_id' };
- const adUnit = { ortb2Imp: { ext: { data: { jwTargeting: { mediaID: expectedMediaID, playerID: expectedPlayerID } } } } };
+ const adUnit = { ortb2Imp: { ext: { data: { jwTargeting: { mediaID: expectedMediaID, playerDivId: expectedPlayerID } } } } };
const targeting = extractPublisherParams(adUnit, config);
expect(targeting).to.have.property('mediaID', expectedMediaID);
- expect(targeting).to.have.property('playerID', expectedPlayerID);
+ expect(targeting).to.have.property('playerDivId', expectedPlayerID);
});
it('should use config properties as fallbacks', function () {
const expectedMediaID = 'test_media_id';
const expectedPlayerID = 'test_player_id';
- const config = { playerID: expectedPlayerID, mediaID: 'bad_id' };
+ const config = { playerDivId: expectedPlayerID, mediaID: 'bad_id' };
const adUnit = { ortb2Imp: { ext: { data: { jwTargeting: { mediaID: expectedMediaID } } } } };
const targeting = extractPublisherParams(adUnit, config);
expect(targeting).to.have.property('mediaID', expectedMediaID);
- expect(targeting).to.have.property('playerID', expectedPlayerID);
+ expect(targeting).to.have.property('playerDivId', expectedPlayerID);
});
it('should return undefined when Publisher Params are absent', function () {
diff --git a/test/spec/modules/kargoBidAdapter_spec.js b/test/spec/modules/kargoBidAdapter_spec.js
index 9f7a4854063..eb8f310201d 100644
--- a/test/spec/modules/kargoBidAdapter_spec.js
+++ b/test/spec/modules/kargoBidAdapter_spec.js
@@ -112,6 +112,24 @@ describe('kargo adapter tests', function () {
}
}
]
+ },
+ {
+ 'source': 'adquery.io',
+ 'uids': [
+ {
+ 'id': 'adqueryId-123',
+ 'atype': 1
+ }
+ ]
+ },
+ {
+ 'source': 'criteo.com',
+ 'uids': [
+ {
+ 'id': 'criteoId-456',
+ 'atype': 1
+ }
+ ]
}
],
floorData: {
@@ -142,6 +160,27 @@ describe('kargo adapter tests', function () {
model: 'model',
source: 1,
}
+ },
+ site: {
+ id: '1234',
+ name: 'SiteName',
+ cat: ['IAB1', 'IAB2', 'IAB3']
+ },
+ user: {
+ data: [
+ {
+ name: 'prebid.org',
+ ext: {
+ segtax: 600,
+ segclass: 'v1',
+ },
+ segment: [
+ {
+ id: '133'
+ },
+ ]
+ },
+ ]
}
},
ortb2Imp: {
@@ -150,9 +189,9 @@ describe('kargo adapter tests', function () {
data: {
adServer: {
name: 'gam',
- adSlot: '/22558409563,18834096/dfy_mobile_adhesion'
+ adslot: '/22558409563,18834096/dfy_mobile_adhesion'
},
- pbAdSlot: '/22558409563,18834096/dfy_mobile_adhesion'
+ pbadslot: '/22558409563,18834096/dfy_mobile_adhesion'
},
gpid: '/22558409563,18834096/dfy_mobile_adhesion'
}
@@ -179,9 +218,9 @@ describe('kargo adapter tests', function () {
data: {
adServer: {
name: 'gam',
- adSlot: '/22558409563,18834096/dfy_mobile_adhesion'
+ adslot: '/22558409563,18834096/dfy_mobile_adhesion'
},
- pbAdSlot: '/22558409563,18834096/dfy_mobile_adhesion'
+ pbadslot: '/22558409563,18834096/dfy_mobile_adhesion'
}
}
}
@@ -204,9 +243,10 @@ describe('kargo adapter tests', function () {
data: {
adServer: {
name: 'gam',
- adSlot: '/22558409563,18834096/dfy_mobile_adhesion'
+ adslot: '/22558409563,18834096/dfy_mobile_adhesion'
}
- }
+ },
+ gpid: '/22558409563,18834096/dfy_mobile_adhesion'
}
}
}
@@ -439,6 +479,9 @@ describe('kargo adapter tests', function () {
source: 1
},
},
+ site: {
+ cat: ['IAB1', 'IAB2', 'IAB3']
+ },
imp: [
{
code: '101',
@@ -454,6 +497,21 @@ describe('kargo adapter tests', function () {
floor: 1,
fpd: {
gpid: '/22558409563,18834096/dfy_mobile_adhesion'
+ },
+ ext: {
+ ortb2Imp: {
+ ext: {
+ tid: '10101',
+ data: {
+ adServer: {
+ name: 'gam',
+ adslot: '/22558409563,18834096/dfy_mobile_adhesion'
+ },
+ pbadslot: '/22558409563,18834096/dfy_mobile_adhesion'
+ },
+ gpid: '/22558409563,18834096/dfy_mobile_adhesion'
+ }
+ }
}
},
{
@@ -466,6 +524,21 @@ describe('kargo adapter tests', function () {
},
fpd: {
gpid: '/22558409563,18834096/dfy_mobile_adhesion'
+ },
+ floor: 2,
+ ext: {
+ ortb2Imp: {
+ ext: {
+ tid: '20202',
+ data: {
+ adServer: {
+ name: 'gam',
+ adslot: '/22558409563,18834096/dfy_mobile_adhesion'
+ },
+ pbadslot: '/22558409563,18834096/dfy_mobile_adhesion'
+ }
+ }
+ }
}
},
{
@@ -478,6 +551,21 @@ describe('kargo adapter tests', function () {
},
fpd: {
gpid: '/22558409563,18834096/dfy_mobile_adhesion'
+ },
+ floor: 3,
+ ext: {
+ ortb2Imp: {
+ ext: {
+ tid: '30303',
+ data: {
+ adServer: {
+ name: 'gam',
+ adslot: '/22558409563,18834096/dfy_mobile_adhesion'
+ }
+ },
+ gpid: '/22558409563,18834096/dfy_mobile_adhesion'
+ }
+ }
}
}
],
@@ -512,8 +600,90 @@ describe('kargo adapter tests', function () {
}
}
]
+ },
+ {
+ source: 'adquery.io',
+ uids: [
+ {
+ id: 'adqueryId-123',
+ atype: 1
+ }
+ ]
+ },
+ {
+ source: 'criteo.com',
+ uids: [
+ {
+ id: 'criteoId-456',
+ atype: 1
+ }
+ ]
+ }
+ ],
+ data: [
+ {
+ name: 'prebid.org',
+ ext: {
+ segtax: 600,
+ segclass: 'v1',
+ },
+ segment: [
+ {
+ id: '133'
+ }
+ ]
}
]
+ },
+ ext: {
+ ortb2: {
+ device: {
+ sua: {
+ platform: {
+ brand: 'macOS',
+ version: ['12', '6', '0']
+ },
+ browsers: [
+ {
+ brand: 'Chromium',
+ version: ['106', '0', '5249', '119']
+ },
+ {
+ brand: 'Google Chrome',
+ version: ['106', '0', '5249', '119']
+ },
+ {
+ brand: 'Not;A=Brand',
+ version: ['99', '0', '0', '0']
+ }
+ ],
+ mobile: 1,
+ model: 'model',
+ source: 1,
+ }
+ },
+ site: {
+ id: '1234',
+ name: 'SiteName',
+ cat: ['IAB1', 'IAB2', 'IAB3']
+ },
+ user: {
+ data: [
+ {
+ name: 'prebid.org',
+ ext: {
+ segtax: 600,
+ segclass: 'v1',
+ },
+ segment: [
+ {
+ id: '133'
+ },
+ ]
+ },
+ ]
+ }
+ }
}
};
@@ -566,6 +736,16 @@ describe('kargo adapter tests', function () {
payload['gdprConsent'] = gdpr
}
+ clonedBids.forEach(bid => {
+ if (bid.mediaTypes.banner) {
+ bid.getFloor = () => ({ currency: 'USD', floor: 1 });
+ } else if (bid.mediaTypes.video) {
+ bid.getFloor = () => ({ currency: 'USD', floor: 2 });
+ } else if (bid.mediaTypes.native) {
+ bid.getFloor = () => ({ currency: 'USD', floor: 3 });
+ }
+ });
+
var request = spec.buildRequests(clonedBids, payload);
var krakenParams = request.data;
@@ -686,7 +866,8 @@ describe('kargo adapter tests', function () {
adm: '
',
width: 320,
height: 50,
- metadata: {}
+ metadata: {},
+ creativeID: 'bar'
},
2: {
id: 'bar',
@@ -697,14 +878,16 @@ describe('kargo adapter tests', function () {
targetingCustom: 'dmpmptest1234',
metadata: {
landingPageDomain: ['https://foobar.com']
- }
+ },
+ creativeID: 'foo'
},
3: {
id: 'bar',
cpm: 2.5,
adm: '
',
width: 300,
- height: 250
+ height: 250,
+ creativeID: 'foo'
},
4: {
id: 'bar',
@@ -714,6 +897,7 @@ describe('kargo adapter tests', function () {
height: 250,
mediaType: 'banner',
metadata: {},
+ creativeID: 'foo',
currency: 'EUR'
},
5: {
@@ -724,6 +908,7 @@ describe('kargo adapter tests', function () {
height: 250,
mediaType: 'video',
metadata: {},
+ creativeID: 'foo',
currency: 'EUR'
},
6: {
@@ -735,6 +920,7 @@ describe('kargo adapter tests', function () {
height: 250,
mediaType: 'video',
metadata: {},
+ creativeID: 'foo',
currency: 'EUR'
}
}
@@ -779,7 +965,7 @@ describe('kargo adapter tests', function () {
width: 320,
height: 50,
ttl: 300,
- creativeId: 'foo',
+ creativeId: 'bar',
dealId: undefined,
netRevenue: true,
currency: 'USD',
@@ -794,7 +980,7 @@ describe('kargo adapter tests', function () {
width: 300,
height: 250,
ttl: 300,
- creativeId: 'bar',
+ creativeId: 'foo',
dealId: 'dmpmptest1234',
netRevenue: true,
currency: 'USD',
@@ -811,7 +997,7 @@ describe('kargo adapter tests', function () {
width: 300,
height: 250,
ttl: 300,
- creativeId: 'bar',
+ creativeId: 'foo',
dealId: undefined,
netRevenue: true,
currency: 'USD',
@@ -826,7 +1012,7 @@ describe('kargo adapter tests', function () {
width: 300,
height: 250,
ttl: 300,
- creativeId: 'bar',
+ creativeId: 'foo',
dealId: undefined,
netRevenue: true,
currency: 'EUR',
@@ -841,7 +1027,7 @@ describe('kargo adapter tests', function () {
height: 250,
vastXml: '
',
ttl: 300,
- creativeId: 'bar',
+ creativeId: 'foo',
dealId: undefined,
netRevenue: true,
currency: 'EUR',
@@ -856,7 +1042,7 @@ describe('kargo adapter tests', function () {
height: 250,
vastUrl: 'https://foobar.com/vast_adm',
ttl: 300,
- creativeId: 'bar',
+ creativeId: 'foo',
dealId: undefined,
netRevenue: true,
currency: 'EUR',
diff --git a/test/spec/modules/kimberliteBidAdapter_spec.js b/test/spec/modules/kimberliteBidAdapter_spec.js
new file mode 100644
index 00000000000..1480f1cc768
--- /dev/null
+++ b/test/spec/modules/kimberliteBidAdapter_spec.js
@@ -0,0 +1,171 @@
+import { spec } from 'modules/kimberliteBidAdapter.js';
+import { assert } from 'chai';
+import { BANNER } from '../../../src/mediaTypes.js';
+
+const BIDDER_CODE = 'kimberlite';
+
+describe('kimberliteBidAdapter', function () {
+ const sizes = [[640, 480]];
+
+ describe('isBidRequestValid', function () {
+ let bidRequest;
+
+ beforeEach(function () {
+ bidRequest = {
+ mediaTypes: {
+ [BANNER]: {
+ sizes: [[320, 240]]
+ }
+ },
+ params: {
+ placementId: 'test-placement'
+ }
+ };
+ });
+
+ it('pass on valid bidRequest', function () {
+ assert.isTrue(spec.isBidRequestValid(bidRequest));
+ });
+
+ it('fails on missed placementId', function () {
+ delete bidRequest.params.placementId;
+ assert.isFalse(spec.isBidRequestValid(bidRequest));
+ });
+
+ it('fails on empty banner', function () {
+ delete bidRequest.mediaTypes.banner;
+ assert.isFalse(spec.isBidRequestValid(bidRequest));
+ });
+
+ it('fails on empty banner.sizes', function () {
+ delete bidRequest.mediaTypes.banner.sizes;
+ assert.isFalse(spec.isBidRequestValid(bidRequest));
+ });
+
+ it('fails on empty request', function () {
+ assert.isFalse(spec.isBidRequestValid());
+ });
+ });
+
+ describe('buildRequests', function () {
+ let bidRequests, bidderRequest;
+
+ beforeEach(function () {
+ bidRequests = [{
+ mediaTypes: {
+ [BANNER]: {sizes: sizes}
+ },
+ params: {
+ placementId: 'test-placement'
+ }
+ }];
+
+ bidderRequest = {
+ refererInfo: {
+ domain: 'example.com',
+ page: 'https://www.example.com/test.html',
+ },
+ bids: [{
+ mediaTypes: {
+ [BANNER]: {sizes: sizes}
+ }
+ }]
+ };
+ });
+
+ it('valid bid request', function () {
+ const bidRequest = spec.buildRequests(bidRequests, bidderRequest);
+ assert.equal(bidRequest.method, 'POST');
+ assert.ok(bidRequest.data);
+
+ const requestData = bidRequest.data;
+ expect(requestData.site.page).to.equal(bidderRequest.refererInfo.page);
+ expect(requestData.site.publisher.domain).to.equal(bidderRequest.refererInfo.domain);
+
+ expect(requestData.imp).to.be.an('array').and.is.not.empty;
+
+ expect(requestData.ext).to.be.an('Object').and.have.all.keys('prebid');
+ expect(requestData.ext.prebid).to.be.an('Object').and.have.all.keys('ver', 'adapterVer');
+
+ const impData = requestData.imp[0];
+ expect(impData.banner).is.to.be.an('Object').and.have.all.keys(['format', 'topframe']);
+
+ const bannerData = impData.banner;
+ expect(bannerData.format).to.be.an('array').and.is.not.empty;
+
+ const formatData = bannerData.format[0];
+ expect(formatData).to.be.an('Object').and.have.all.keys('w', 'h');
+
+ assert.equal(formatData.w, sizes[0][0]);
+ assert.equal(formatData.h, sizes[0][1]);
+ });
+ });
+
+ describe('interpretResponse', function () {
+ let bidderResponse, bidderRequest, bidRequest, expectedBid;
+
+ const requestId = '07fba8b0-8812-4dc6-b91e-4a525d81729c';
+ const bidId = '222209853178';
+ const impId = 'imp-id';
+ const crId = 'creative-id';
+ const adm = '
landing ';
+
+ beforeEach(function () {
+ bidderResponse = {
+ body: {
+ id: requestId,
+ seatbid: [{
+ bid: [{
+ crid: crId,
+ id: bidId,
+ impid: impId,
+ price: 1,
+ adm: adm
+ }]
+ }]
+ }
+ };
+
+ bidderRequest = {
+ refererInfo: {
+ domain: 'example.com',
+ page: 'https://www.example.com/test.html',
+ },
+ bids: [{
+ bidId: impId,
+ mediaTypes: {
+ [BANNER]: {sizes: sizes}
+ },
+ params: {
+ placementId: 'test-placement'
+ }
+ }]
+ };
+
+ expectedBid = {
+ mediaType: 'banner',
+ requestId: 'imp-id',
+ seatBidId: '222209853178',
+ cpm: 1,
+ creative_id: 'creative-id',
+ creativeId: 'creative-id',
+ ttl: 300,
+ netRevenue: true,
+ ad: adm,
+ meta: {}
+ };
+
+ bidRequest = spec.buildRequests(bidderRequest.bids, bidderRequest);
+ });
+
+ it('pass on valid request', function () {
+ const bids = spec.interpretResponse(bidderResponse, bidRequest);
+ assert.deepEqual(bids[0], expectedBid);
+ });
+
+ it('fails on empty response', function () {
+ const bids = spec.interpretResponse({body: ''}, bidRequest);
+ assert.empty(bids);
+ });
+ });
+});
diff --git a/test/spec/modules/lassoBidAdapter_spec.js b/test/spec/modules/lassoBidAdapter_spec.js
index 3695889aca0..ad4040c0452 100644
--- a/test/spec/modules/lassoBidAdapter_spec.js
+++ b/test/spec/modules/lassoBidAdapter_spec.js
@@ -126,6 +126,7 @@ describe('lassoBidAdapter', function () {
it('should get the correct bid response', function () {
let expectedResponse = {
requestId: '123456789',
+ bidId: '123456789',
cpm: 1,
currency: 'USD',
width: 728,
diff --git a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js
index fa4c5cd8cad..d00bfbc7bb5 100644
--- a/test/spec/modules/liveIntentAnalyticsAdapter_spec.js
+++ b/test/spec/modules/liveIntentAnalyticsAdapter_spec.js
@@ -16,7 +16,7 @@ let events = require('src/events');
let constants = require('src/constants.json');
let auctionId = '99abbc81-c1f1-41cd-8f25-f7149244c897'
-const config = {
+const configWithSamplingAll = {
provider: 'liveintent',
options: {
bidWonTimeout: 2000,
@@ -24,6 +24,14 @@ const config = {
}
}
+const configWithSamplingNone = {
+ provider: 'liveintent',
+ options: {
+ bidWonTimeout: 2000,
+ sampling: 0
+ }
+}
+
let args = {
auctionId: auctionId,
timestamp: 1660915379703,
@@ -273,8 +281,8 @@ describe('LiveIntent Analytics Adapter ', () => {
clock.restore();
});
- it('request is computed and sent correctly', () => {
- liAnalytics.enableAnalytics(config);
+ it('request is computed and sent correctly when sampling is 1', () => {
+ liAnalytics.enableAnalytics(configWithSamplingAll);
sandbox.stub(utils, 'generateUUID').returns(instanceId);
sandbox.stub(refererDetection, 'getRefererInfo').returns({page: url});
sandbox.stub(auctionManager.index, 'getAuction').withArgs(auctionId).returns({ getWinningBids: () => winningBids });
@@ -288,7 +296,23 @@ describe('LiveIntent Analytics Adapter ', () => {
it('track is called', () => {
sandbox.stub(liAnalytics, 'track');
- liAnalytics.enableAnalytics(config);
+ liAnalytics.enableAnalytics(configWithSamplingAll);
expectEvents().to.beTrackedBy(liAnalytics.track);
})
+
+ it('no request is computed when sampling is 0', () => {
+ liAnalytics.enableAnalytics(configWithSamplingNone);
+ sandbox.stub(utils, 'generateUUID').returns(instanceId);
+ sandbox.stub(refererDetection, 'getRefererInfo').returns({page: url});
+ sandbox.stub(auctionManager.index, 'getAuction').withArgs(auctionId).returns({ getWinningBids: () => winningBids });
+ events.emit(constants.EVENTS.AUCTION_END, args);
+ clock.tick(2000);
+ expect(server.requests.length).to.equal(0);
+ });
+
+ it('track is not called', () => {
+ sandbox.stub(liAnalytics, 'track');
+ liAnalytics.enableAnalytics(configWithSamplingNone);
+ sinon.assert.callCount(liAnalytics.track, 0);
+ })
});
diff --git a/test/spec/modules/liveIntentIdMinimalSystem_spec.js b/test/spec/modules/liveIntentIdMinimalSystem_spec.js
index 0929a022937..e280d9108a0 100644
--- a/test/spec/modules/liveIntentIdMinimalSystem_spec.js
+++ b/test/spec/modules/liveIntentIdMinimalSystem_spec.js
@@ -2,6 +2,7 @@ import * as utils from 'src/utils.js';
import { gdprDataHandler, uspDataHandler } from '../../../src/adapterManager.js';
import { server } from 'test/mocks/xhr.js';
import { liveIntentIdSubmodule, reset as resetLiveIntentIdSubmodule, storage } from 'modules/liveIntentIdSystem.js';
+import * as refererDetection from '../../../src/refererDetection.js';
const PUBLISHER_ID = '89899';
const defaultConfigParams = { params: {publisherId: PUBLISHER_ID} };
@@ -14,6 +15,7 @@ describe('LiveIntentMinimalId', function() {
let getCookieStub;
let getDataFromLocalStorageStub;
let imgStub;
+ let refererInfoStub;
beforeEach(function() {
liveIntentIdSubmodule.setModuleMode('minimal');
@@ -23,6 +25,7 @@ describe('LiveIntentMinimalId', function() {
logErrorStub = sinon.stub(utils, 'logError');
uspConsentDataStub = sinon.stub(uspDataHandler, 'getConsentData');
gdprConsentDataStub = sinon.stub(gdprDataHandler, 'getConsentData');
+ refererInfoStub = sinon.stub(refererDetection, 'getRefererInfo');
});
afterEach(function() {
@@ -32,6 +35,7 @@ describe('LiveIntentMinimalId', function() {
logErrorStub.restore();
uspConsentDataStub.restore();
gdprConsentDataStub.restore();
+ refererInfoStub.restore();
liveIntentIdSubmodule.setModuleMode('minimal');
resetLiveIntentIdSubmodule();
});
@@ -73,7 +77,7 @@ describe('LiveIntentMinimalId', function() {
expect(callBackSpy.calledOnce).to.be.true;
});
- it('should call the Identity Exchange endpoint with the privided distributorId', function() {
+ it('should call the Identity Exchange endpoint with the provided distributorId', function() {
getCookieStub.returns(null);
let callBackSpy = sinon.spy();
let submoduleCallback = liveIntentIdSubmodule.getId({ params: { fireEventDelay: 1, distributorId: 'did-1111' } }).callback;
@@ -87,7 +91,7 @@ describe('LiveIntentMinimalId', function() {
expect(callBackSpy.calledOnceWith({})).to.be.true;
});
- it('should call the Identity Exchange endpoint without the privided distributorId when appId is provided', function() {
+ it('should call the Identity Exchange endpoint without the provided distributorId when appId is provided', function() {
getCookieStub.returns(null);
let callBackSpy = sinon.spy();
let submoduleCallback = liveIntentIdSubmodule.getId({ params: { fireEventDelay: 1, distributorId: 'did-1111', liCollectConfig: { appId: 'a-0001' } } }).callback;
@@ -241,7 +245,7 @@ describe('LiveIntentMinimalId', function() {
expect(callBackSpy.calledOnce).to.be.true;
});
- it('should decode a uid2 to a seperate object when present', function() {
+ it('should decode a uid2 to a separate object when present', function() {
const result = liveIntentIdSubmodule.decode({ nonId: 'foo', uid2: 'bar' });
expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'uid2': 'bar'}, 'uid2': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
});
@@ -251,26 +255,48 @@ describe('LiveIntentMinimalId', function() {
expect(result).to.eql({'uid2': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
});
- it('should decode a bidswitch id to a seperate object when present', function() {
+ it('should decode a bidswitch id to a separate object when present', function() {
const result = liveIntentIdSubmodule.decode({ nonId: 'foo', bidswitch: 'bar' });
expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'bidswitch': 'bar'}, 'bidswitch': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
});
- it('should decode a medianet id to a seperate object when present', function() {
+ it('should decode a medianet id to a separate object when present', function() {
const result = liveIntentIdSubmodule.decode({ nonId: 'foo', medianet: 'bar' });
expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'medianet': 'bar'}, 'medianet': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
});
- it('should decode a magnite id to a seperate object when present', function() {
+ it('should decode a sovrn id to a separate object when present', function() {
+ const result = liveIntentIdSubmodule.decode({ nonId: 'foo', sovrn: 'bar' });
+ expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'sovrn': 'bar'}, 'sovrn': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
+ });
+
+ it('should decode a magnite id to a separate object when present', function() {
const result = liveIntentIdSubmodule.decode({ nonId: 'foo', magnite: 'bar' });
expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'magnite': 'bar'}, 'magnite': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
});
- it('should decode an index id to a seperate object when present', function() {
+ it('should decode an index id to a separate object when present', function() {
const result = liveIntentIdSubmodule.decode({ nonId: 'foo', index: 'bar' });
expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'index': 'bar'}, 'index': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
});
+ it('should decode an openx id to a separate object when present', function () {
+ const result = liveIntentIdSubmodule.decode({ nonId: 'foo', openx: 'bar' });
+ expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'openx': 'bar'}, 'openx': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
+ });
+
+ it('should decode an pubmatic id to a separate object when present', function() {
+ const result = liveIntentIdSubmodule.decode({ nonId: 'foo', pubmatic: 'bar' });
+ expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'pubmatic': 'bar'}, 'pubmatic': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
+ });
+
+ it('should decode a thetradedesk id to a separate object when present', function() {
+ const provider = 'liveintent.com'
+ refererInfoStub.returns({domain: provider})
+ const result = liveIntentIdSubmodule.decode({ nonId: 'foo', thetradedesk: 'bar' });
+ expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'tdid': 'bar'}, 'tdid': {'id': 'bar', 'ext': {'rtiPartner': 'TDID', 'provider': provider}}});
+ });
+
it('should allow disabling nonId resolution', function() {
let callBackSpy = sinon.spy();
let submoduleCallback = liveIntentIdSubmodule.getId({ params: {
diff --git a/test/spec/modules/liveIntentIdSystem_spec.js b/test/spec/modules/liveIntentIdSystem_spec.js
index 4f11af57711..c6108b49715 100644
--- a/test/spec/modules/liveIntentIdSystem_spec.js
+++ b/test/spec/modules/liveIntentIdSystem_spec.js
@@ -1,7 +1,9 @@
import { liveIntentIdSubmodule, reset as resetLiveIntentIdSubmodule, storage } from 'modules/liveIntentIdSystem.js';
import * as utils from 'src/utils.js';
-import { gdprDataHandler, uspDataHandler } from '../../../src/adapterManager.js';
+import { gdprDataHandler, uspDataHandler, gppDataHandler } from '../../../src/adapterManager.js';
import { server } from 'test/mocks/xhr.js';
+import * as refererDetection from '../../../src/refererDetection.js';
+
resetLiveIntentIdSubmodule();
liveIntentIdSubmodule.setModuleMode('standard')
const PUBLISHER_ID = '89899';
@@ -12,9 +14,11 @@ describe('LiveIntentId', function() {
let logErrorStub;
let uspConsentDataStub;
let gdprConsentDataStub;
+ let gppConsentDataStub;
let getCookieStub;
let getDataFromLocalStorageStub;
let imgStub;
+ let refererInfoStub;
beforeEach(function() {
liveIntentIdSubmodule.setModuleMode('standard');
@@ -24,6 +28,8 @@ describe('LiveIntentId', function() {
logErrorStub = sinon.stub(utils, 'logError');
uspConsentDataStub = sinon.stub(uspDataHandler, 'getConsentData');
gdprConsentDataStub = sinon.stub(gdprDataHandler, 'getConsentData');
+ gppConsentDataStub = sinon.stub(gppDataHandler, 'getConsentData');
+ refererInfoStub = sinon.stub(refererDetection, 'getRefererInfo');
});
afterEach(function() {
@@ -33,6 +39,8 @@ describe('LiveIntentId', function() {
logErrorStub.restore();
uspConsentDataStub.restore();
gdprConsentDataStub.restore();
+ gppConsentDataStub.restore();
+ refererInfoStub.restore();
resetLiveIntentIdSubmodule();
});
@@ -42,11 +50,15 @@ describe('LiveIntentId', function() {
gdprApplies: true,
consentString: 'consentDataString'
})
+ gppConsentDataStub.returns({
+ gppString: 'gppConsentDataString',
+ applicableSections: [1, 2]
+ })
let callBackSpy = sinon.spy();
let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
- expect(request.url).to.match(/.*us_privacy=1YNY.*&gdpr=1&n3pc=1&gdpr_consent=consentDataString.*/);
+ expect(request.url).to.match(/.*us_privacy=1YNY.*&gdpr=1&n3pc=1&gdpr_consent=consentDataString.*&gpp_s=gppConsentDataString&gpp_as=1%2C2.*/);
const response = {
unifiedId: 'a_unified_id',
segments: [123, 234]
@@ -65,9 +77,13 @@ describe('LiveIntentId', function() {
gdprApplies: true,
consentString: 'consentDataString'
})
+ gppConsentDataStub.returns({
+ gppString: 'gppConsentDataString',
+ applicableSections: [1]
+ })
liveIntentIdSubmodule.getId(defaultConfigParams);
setTimeout(() => {
- expect(server.requests[0].url).to.match(/https:\/\/rp.liadm.com\/j\?.*&us_privacy=1YNY.*&wpn=prebid.*&gdpr=1&n3pc=1&n3pct=1&nb=1&gdpr_consent=consentDataString.*/);
+ expect(server.requests[0].url).to.match(/https:\/\/rp.liadm.com\/j\?.*&us_privacy=1YNY.*&wpn=prebid.*&gdpr=1&n3pc=1&n3pct=1&nb=1&gdpr_consent=consentDataString&gpp_s=gppConsentDataString&gpp_as=1.*/);
done();
}, 200);
});
@@ -83,6 +99,16 @@ describe('LiveIntentId', function() {
}, 200);
});
+ it('should initialize LiveConnect and forward the prebid version when decode and emit an event', function(done) {
+ liveIntentIdSubmodule.decode({}, { params: {
+ ...defaultConfigParams
+ }});
+ setTimeout(() => {
+ expect(server.requests[0].url).to.contain('tv=$prebid.version$')
+ done();
+ }, 200);
+ });
+
it('should initialize LiveConnect with the config params when decode and emit an event', function (done) {
liveIntentIdSubmodule.decode({}, { params: {
...defaultConfigParams.params,
@@ -123,9 +149,13 @@ describe('LiveIntentId', function() {
gdprApplies: false,
consentString: 'consentDataString'
})
+ gppConsentDataStub.returns({
+ gppString: 'gppConsentDataString',
+ applicableSections: [1]
+ })
liveIntentIdSubmodule.decode({}, defaultConfigParams);
setTimeout(() => {
- expect(server.requests[0].url).to.match(/.*us_privacy=1YNY.*&gdpr=0&gdpr_consent=consentDataString.*/);
+ expect(server.requests[0].url).to.match(/.*us_privacy=1YNY.*&gdpr=0&gdpr_consent=consentDataString.*&gpp_s=gppConsentDataString&gpp_as=1.*/);
done();
}, 200);
});
@@ -171,7 +201,7 @@ describe('LiveIntentId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId({ params: {...defaultConfigParams.params, ...{'url': 'https://dummy.liveintent.com/idex'}} }).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
- expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/prebid/89899?resolve=nonId');
+ expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/prebid/89899?cd=.localhost&resolve=nonId');
request.respond(
204,
responseHeader
@@ -179,13 +209,13 @@ describe('LiveIntentId', function() {
expect(callBackSpy.calledOnceWith({})).to.be.true;
});
- it('should call the Identity Exchange endpoint with the privided distributorId', function() {
+ it('should call the Identity Exchange endpoint with the provided distributorId', function() {
getCookieStub.returns(null);
let callBackSpy = sinon.spy();
let submoduleCallback = liveIntentIdSubmodule.getId({ params: { fireEventDelay: 1, distributorId: 'did-1111' } }).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
- expect(request.url).to.be.eq('https://idx.liadm.com/idex/did-1111/any?did=did-1111&resolve=nonId');
+ expect(request.url).to.be.eq('https://idx.liadm.com/idex/did-1111/any?did=did-1111&cd=.localhost&resolve=nonId');
request.respond(
204,
responseHeader
@@ -193,13 +223,13 @@ describe('LiveIntentId', function() {
expect(callBackSpy.calledOnceWith({})).to.be.true;
});
- it('should call the Identity Exchange endpoint without the privided distributorId when appId is provided', function() {
+ it('should call the Identity Exchange endpoint without the provided distributorId when appId is provided', function() {
getCookieStub.returns(null);
let callBackSpy = sinon.spy();
let submoduleCallback = liveIntentIdSubmodule.getId({ params: { fireEventDelay: 1, distributorId: 'did-1111', liCollectConfig: { appId: 'a-0001' } } }).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
- expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/any?resolve=nonId');
+ expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/any?cd=.localhost&resolve=nonId');
request.respond(
204,
responseHeader
@@ -219,7 +249,7 @@ describe('LiveIntentId', function() {
} }).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
- expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/rubicon/89899?resolve=nonId');
+ expect(request.url).to.be.eq('https://dummy.liveintent.com/idex/rubicon/89899?cd=.localhost&resolve=nonId');
request.respond(
200,
responseHeader,
@@ -234,7 +264,7 @@ describe('LiveIntentId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
- expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?resolve=nonId');
+ expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?cd=.localhost&resolve=nonId');
request.respond(
200,
responseHeader,
@@ -249,7 +279,7 @@ describe('LiveIntentId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
- expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?resolve=nonId');
+ expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?cd=.localhost&resolve=nonId');
request.respond(
503,
responseHeader,
@@ -266,7 +296,7 @@ describe('LiveIntentId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(defaultConfigParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
- expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?duid=${oldCookie}&resolve=nonId`);
+ expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?duid=${oldCookie}&cd=.localhost&resolve=nonId`);
request.respond(
200,
responseHeader,
@@ -289,7 +319,7 @@ describe('LiveIntentId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(configParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
- expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?duid=${oldCookie}&_thirdPC=third-pc&resolve=nonId`);
+ expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?duid=${oldCookie}&cd=.localhost&_thirdPC=third-pc&resolve=nonId`);
request.respond(
200,
responseHeader,
@@ -311,7 +341,7 @@ describe('LiveIntentId', function() {
let submoduleCallback = liveIntentIdSubmodule.getId(configParams).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
- expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?_thirdPC=%7B%22key%22%3A%22value%22%7D&resolve=nonId');
+ expect(request.url).to.be.eq('https://idx.liadm.com/idex/prebid/89899?cd=.localhost&_thirdPC=%7B%22key%22%3A%22value%22%7D&resolve=nonId');
request.respond(
200,
responseHeader,
@@ -344,7 +374,7 @@ describe('LiveIntentId', function() {
} }).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
- expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?resolve=nonId&resolve=foo`);
+ expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?cd=.localhost&resolve=nonId&resolve=foo`);
request.respond(
200,
responseHeader,
@@ -353,7 +383,7 @@ describe('LiveIntentId', function() {
expect(callBackSpy.calledOnce).to.be.true;
});
- it('should decode a uid2 to a seperate object when present', function() {
+ it('should decode a uid2 to a separate object when present', function() {
const result = liveIntentIdSubmodule.decode({ nonId: 'foo', uid2: 'bar' });
expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'uid2': 'bar'}, 'uid2': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
});
@@ -363,26 +393,48 @@ describe('LiveIntentId', function() {
expect(result).to.eql({'uid2': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
});
- it('should decode a bidswitch id to a seperate object when present', function() {
+ it('should decode a bidswitch id to a separate object when present', function() {
const result = liveIntentIdSubmodule.decode({ nonId: 'foo', bidswitch: 'bar' });
expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'bidswitch': 'bar'}, 'bidswitch': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
});
- it('should decode a medianet id to a seperate object when present', function() {
+ it('should decode a medianet id to a separate object when present', function() {
const result = liveIntentIdSubmodule.decode({ nonId: 'foo', medianet: 'bar' });
expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'medianet': 'bar'}, 'medianet': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
});
- it('should decode a magnite id to a seperate object when present', function() {
+ it('should decode a sovrn id to a separate object when present', function() {
+ const result = liveIntentIdSubmodule.decode({ nonId: 'foo', sovrn: 'bar' });
+ expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'sovrn': 'bar'}, 'sovrn': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
+ });
+
+ it('should decode a magnite id to a separate object when present', function() {
const result = liveIntentIdSubmodule.decode({ nonId: 'foo', magnite: 'bar' });
expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'magnite': 'bar'}, 'magnite': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
});
- it('should decode an index id to a seperate object when present', function() {
+ it('should decode an index id to a separate object when present', function() {
const result = liveIntentIdSubmodule.decode({ nonId: 'foo', index: 'bar' });
expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'index': 'bar'}, 'index': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
});
+ it('should decode an openx id to a separate object when present', function () {
+ const result = liveIntentIdSubmodule.decode({ nonId: 'foo', openx: 'bar' });
+ expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'openx': 'bar'}, 'openx': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
+ });
+
+ it('should decode an pubmatic id to a separate object when present', function() {
+ const result = liveIntentIdSubmodule.decode({ nonId: 'foo', pubmatic: 'bar' });
+ expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'pubmatic': 'bar'}, 'pubmatic': {'id': 'bar', 'ext': {'provider': 'liveintent.com'}}});
+ });
+
+ it('should decode a thetradedesk id to a separate object when present', function() {
+ const provider = 'liveintent.com'
+ refererInfoStub.returns({domain: provider})
+ const result = liveIntentIdSubmodule.decode({ nonId: 'foo', thetradedesk: 'bar' });
+ expect(result).to.eql({'lipb': {'lipbid': 'foo', 'nonId': 'foo', 'tdid': 'bar'}, 'tdid': {'id': 'bar', 'ext': {'rtiPartner': 'TDID', 'provider': provider}}});
+ });
+
it('should allow disabling nonId resolution', function() {
let callBackSpy = sinon.spy();
let submoduleCallback = liveIntentIdSubmodule.getId({ params: {
@@ -391,7 +443,7 @@ describe('LiveIntentId', function() {
} }).callback;
submoduleCallback(callBackSpy);
let request = server.requests[0];
- expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?resolve=uid2`);
+ expect(request.url).to.be.eq(`https://idx.liadm.com/idex/prebid/89899?cd=.localhost&resolve=uid2`);
request.respond(
200,
responseHeader,
diff --git a/test/spec/modules/livewrappedBidAdapter_spec.js b/test/spec/modules/livewrappedBidAdapter_spec.js
index 52eaf8d7d76..5ab00859d81 100644
--- a/test/spec/modules/livewrappedBidAdapter_spec.js
+++ b/test/spec/modules/livewrappedBidAdapter_spec.js
@@ -38,10 +38,9 @@ describe('Livewrapped adapter tests', function () {
auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C',
ortb2Imp: {
ext: {
- tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
}
},
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
}
],
start: 1472239426002,
@@ -120,8 +119,49 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
- formats: [{width: 980, height: 240}, {width: 980, height: 120}]
+ formats: [{width: 980, height: 240}, {width: 980, height: 120}],
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ }
+ }]
+ };
+
+ expect(data).to.deep.equal(expectedQuery);
+ });
+
+ it('should send ortb2Imp', function() {
+ sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false);
+ sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true);
+ let ortb2ImpRequest = clone(bidderRequest);
+ ortb2ImpRequest.bids[0].ortb2Imp.ext.data = {key: 'value'};
+ let result = spec.buildRequests(ortb2ImpRequest.bids, ortb2ImpRequest);
+ let data = JSON.parse(result.data);
+
+ expect(result.url).to.equal('https://lwadm.com/ad');
+
+ let expectedQuery = {
+ auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C',
+ publisherId: '26947112-2289-405D-88C1-A7340C57E63E',
+ userId: 'user id',
+ url: 'https://www.domain.com',
+ seats: {'dsp': ['seat 1']},
+ version: '1.4',
+ width: 100,
+ height: 100,
+ cookieSupport: true,
+ adRequests: [{
+ adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
+ callerAdUnitId: 'panorama_d_1',
+ bidId: '2ffb201a808da7',
+ formats: [{width: 980, height: 240}, {width: 980, height: 120}],
+ rtbData: {
+ ext: {
+ data: {key: 'value'},
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ }
}]
};
@@ -157,12 +197,20 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}, {
callerAdUnitId: 'box_d_1',
bidId: '3ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 300, height: 250}]
}]
};
@@ -194,7 +242,11 @@ describe('Livewrapped adapter tests', function () {
adRequests: [{
callerAdUnitId: 'caller id 1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -225,7 +277,11 @@ describe('Livewrapped adapter tests', function () {
adRequests: [{
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -256,7 +312,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -289,7 +349,11 @@ describe('Livewrapped adapter tests', function () {
adRequests: [{
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -322,7 +386,11 @@ describe('Livewrapped adapter tests', function () {
adRequests: [{
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -352,7 +420,11 @@ describe('Livewrapped adapter tests', function () {
adRequests: [{
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}],
options: {keyvalues: [{key: 'key', value: 'value'}]}
}]
@@ -384,7 +456,11 @@ describe('Livewrapped adapter tests', function () {
adRequests: [{
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -414,7 +490,11 @@ describe('Livewrapped adapter tests', function () {
adRequests: [{
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}],
native: {'nativedata': 'content parsed serverside only'}
}]
@@ -445,7 +525,11 @@ describe('Livewrapped adapter tests', function () {
adRequests: [{
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}],
native: {'nativedata': 'content parsed serverside only'},
banner: true
@@ -477,7 +561,11 @@ describe('Livewrapped adapter tests', function () {
adRequests: [{
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}],
video: {'videodata': 'content parsed serverside only'}
}]
@@ -525,7 +613,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -555,7 +647,11 @@ describe('Livewrapped adapter tests', function () {
adRequests: [{
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 728, height: 90}]
}]
};
@@ -592,7 +688,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -627,7 +727,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -660,7 +764,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -700,7 +808,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -730,7 +842,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -760,7 +876,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -810,7 +930,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -842,7 +966,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -876,7 +1004,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -910,7 +1042,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -946,7 +1082,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -982,7 +1122,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -1018,7 +1162,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}]
}]
};
@@ -1063,7 +1211,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}],
flr: 10
}]
@@ -1101,7 +1253,11 @@ describe('Livewrapped adapter tests', function () {
adUnitId: '9E153CED-61BC-479E-98DF-24DC0D01BA37',
callerAdUnitId: 'panorama_d_1',
bidId: '2ffb201a808da7',
- transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D',
+ rtbData: {
+ ext: {
+ tid: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D'
+ },
+ },
formats: [{width: 980, height: 240}, {width: 980, height: 120}],
flr: 10
}]
diff --git a/test/spec/modules/lm_kiviadsBidAdapter_spec.js b/test/spec/modules/lm_kiviadsBidAdapter_spec.js
new file mode 100644
index 00000000000..68ac73289cd
--- /dev/null
+++ b/test/spec/modules/lm_kiviadsBidAdapter_spec.js
@@ -0,0 +1,455 @@
+import {expect} from 'chai';
+import {config} from 'src/config.js';
+import {spec, getBidFloor} from 'modules/lm_kiviadsBidAdapter.js';
+import {deepClone} from 'src/utils';
+
+const ENDPOINT = 'https://pbjs.kiviads.live';
+
+const defaultRequest = {
+ adUnitCode: 'test',
+ bidId: '1',
+ requestId: 'qwerty',
+ ortb2: {
+ source: {
+ tid: 'auctionId'
+ }
+ },
+ ortb2Imp: {
+ ext: {
+ tid: 'tr1',
+ }
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [300, 250],
+ [300, 200]
+ ]
+ }
+ },
+ bidder: 'lm_kiviads',
+ params: {
+ env: 'lm_kiviads',
+ pid: '40',
+ ext: {}
+ },
+ bidRequestsCount: 1
+};
+
+const defaultRequestVideo = deepClone(defaultRequest);
+defaultRequestVideo.mediaTypes = {
+ video: {
+ playerSize: [640, 480],
+ context: 'instream',
+ skipppable: true
+ }
+};
+describe('lm_kiviadsBidAdapter', () => {
+ describe('isBidRequestValid', function () {
+ it('should return false when request params is missing', function () {
+ const invalidRequest = deepClone(defaultRequest);
+ delete invalidRequest.params;
+ expect(spec.isBidRequestValid(invalidRequest)).to.equal(false);
+ });
+
+ it('should return false when required env param is missing', function () {
+ const invalidRequest = deepClone(defaultRequest);
+ delete invalidRequest.params.env;
+ expect(spec.isBidRequestValid(invalidRequest)).to.equal(false);
+ });
+
+ it('should return false when required pid param is missing', function () {
+ const invalidRequest = deepClone(defaultRequest);
+ delete invalidRequest.params.pid;
+ expect(spec.isBidRequestValid(invalidRequest)).to.equal(false);
+ });
+
+ it('should return false when video.playerSize is missing', function () {
+ const invalidRequest = deepClone(defaultRequestVideo);
+ delete invalidRequest.mediaTypes.video.playerSize;
+ expect(spec.isBidRequestValid(invalidRequest)).to.equal(false);
+ });
+
+ it('should return true when required params found', function () {
+ expect(spec.isBidRequestValid(defaultRequest)).to.equal(true);
+ });
+ });
+
+ describe('buildRequests', function () {
+ beforeEach(function () {
+ config.resetConfig();
+ });
+
+ it('should send request with correct structure', function () {
+ const request = spec.buildRequests([defaultRequest], {});
+ expect(request.method).to.equal('POST');
+ expect(request.url).to.equal(ENDPOINT + '/bid');
+ expect(request.options).to.have.property('contentType').and.to.equal('application/json');
+ expect(request).to.have.property('data');
+ });
+
+ it('should build basic request structure', function () {
+ const request = JSON.parse(spec.buildRequests([defaultRequest], {}).data)[0];
+ expect(request).to.have.property('bidId').and.to.equal(defaultRequest.bidId);
+ expect(request).to.have.property('auctionId').and.to.equal(defaultRequest.ortb2.source.tid);
+ expect(request).to.have.property('transactionId').and.to.equal(defaultRequest.ortb2Imp.ext.tid);
+ expect(request).to.have.property('tz').and.to.equal(new Date().getTimezoneOffset());
+ expect(request).to.have.property('bc').and.to.equal(1);
+ expect(request).to.have.property('floor').and.to.equal(null);
+ expect(request).to.have.property('banner').and.to.deep.equal({sizes: [[300, 250], [300, 200]]});
+ expect(request).to.have.property('gdprApplies').and.to.equal(0);
+ expect(request).to.have.property('consentString').and.to.equal('');
+ expect(request).to.have.property('userEids').and.to.deep.equal([]);
+ expect(request).to.have.property('usPrivacy').and.to.equal('');
+ expect(request).to.have.property('coppa').and.to.equal(0);
+ expect(request).to.have.property('sizes').and.to.deep.equal(['300x250', '300x200']);
+ expect(request).to.have.property('ext').and.to.deep.equal({});
+ expect(request).to.have.property('env').and.to.deep.equal({
+ env: 'lm_kiviads',
+ pid: '40'
+ });
+ expect(request).to.have.property('device').and.to.deep.equal({
+ ua: navigator.userAgent,
+ lang: navigator.language
+ });
+ });
+
+ it('should build request with schain', function () {
+ const schainRequest = deepClone(defaultRequest);
+ schainRequest.schain = {
+ validation: 'strict',
+ config: {
+ ver: '1.0'
+ }
+ };
+ const request = JSON.parse(spec.buildRequests([schainRequest], {}).data)[0];
+ expect(request).to.have.property('schain').and.to.deep.equal({
+ validation: 'strict',
+ config: {
+ ver: '1.0'
+ }
+ });
+ });
+
+ it('should build request with location', function () {
+ const bidderRequest = {
+ refererInfo: {
+ page: 'page',
+ location: 'location',
+ domain: 'domain',
+ ref: 'ref',
+ isAmp: false
+ }
+ };
+ const request = JSON.parse(spec.buildRequests([defaultRequest], bidderRequest).data)[0];
+ expect(request).to.have.property('location');
+ const location = request.location;
+ expect(location).to.have.property('page').and.to.equal('page');
+ expect(location).to.have.property('location').and.to.equal('location');
+ expect(location).to.have.property('domain').and.to.equal('domain');
+ expect(location).to.have.property('ref').and.to.equal('ref');
+ expect(location).to.have.property('isAmp').and.to.equal(false);
+ });
+
+ it('should build request with ortb2 info', function () {
+ const ortb2Request = deepClone(defaultRequest);
+ ortb2Request.ortb2 = {
+ site: {
+ name: 'name'
+ }
+ };
+ const request = JSON.parse(spec.buildRequests([ortb2Request], {}).data)[0];
+ expect(request).to.have.property('ortb2').and.to.deep.equal({
+ site: {
+ name: 'name'
+ }
+ });
+ });
+
+ it('should build request with ortb2Imp info', function () {
+ const ortb2ImpRequest = deepClone(defaultRequest);
+ ortb2ImpRequest.ortb2Imp = {
+ ext: {
+ data: {
+ pbadslot: 'home1',
+ adUnitSpecificAttribute: '1'
+ }
+ }
+ };
+ const request = JSON.parse(spec.buildRequests([ortb2ImpRequest], {}).data)[0];
+ expect(request).to.have.property('ortb2Imp').and.to.deep.equal({
+ ext: {
+ data: {
+ pbadslot: 'home1',
+ adUnitSpecificAttribute: '1'
+ }
+ }
+ });
+ });
+
+ it('should build request with valid bidfloor', function () {
+ const bfRequest = deepClone(defaultRequest);
+ bfRequest.getFloor = () => ({floor: 5, currency: 'USD'});
+ const request = JSON.parse(spec.buildRequests([bfRequest], {}).data)[0];
+ expect(request).to.have.property('floor').and.to.equal(5);
+ });
+
+ it('should build request with gdpr consent data if applies', function () {
+ const bidderRequest = {
+ gdprConsent: {
+ gdprApplies: true,
+ consentString: 'qwerty'
+ }
+ };
+ const request = JSON.parse(spec.buildRequests([defaultRequest], bidderRequest).data)[0];
+ expect(request).to.have.property('gdprApplies').and.equals(1);
+ expect(request).to.have.property('consentString').and.equals('qwerty');
+ });
+
+ it('should build request with usp consent data if applies', function () {
+ const bidderRequest = {
+ uspConsent: '1YA-'
+ };
+ const request = JSON.parse(spec.buildRequests([defaultRequest], bidderRequest).data)[0];
+ expect(request).to.have.property('usPrivacy').and.equals('1YA-');
+ });
+
+ it('should build request with coppa 1', function () {
+ config.setConfig({
+ coppa: true
+ });
+ const request = JSON.parse(spec.buildRequests([defaultRequest], {}).data)[0];
+ expect(request).to.have.property('coppa').and.equals(1);
+ });
+
+ it('should build request with extended ids', function () {
+ const idRequest = deepClone(defaultRequest);
+ idRequest.userIdAsEids = [
+ {source: 'adserver.org', uids: [{id: 'TTD_ID_FROM_USER_ID_MODULE', atype: 1, ext: {rtiPartner: 'TDID'}}]},
+ {source: 'pubcid.org', uids: [{id: 'pubCommonId_FROM_USER_ID_MODULE', atype: 1}]}
+ ];
+ const request = JSON.parse(spec.buildRequests([idRequest], {}).data)[0];
+ expect(request).to.have.property('userEids').and.deep.equal(idRequest.userIdAsEids);
+ });
+
+ it('should build request with video', function () {
+ const request = JSON.parse(spec.buildRequests([defaultRequestVideo], {}).data)[0];
+ expect(request).to.have.property('video').and.to.deep.equal({
+ playerSize: [640, 480],
+ context: 'instream',
+ skipppable: true
+ });
+ expect(request).to.have.property('sizes').and.to.deep.equal(['640x480']);
+ });
+ });
+
+ describe('interpretResponse', function () {
+ it('should return empty bids', function () {
+ const serverResponse = {
+ body: {
+ data: null
+ }
+ };
+
+ const invalidResponse = spec.interpretResponse(serverResponse, {});
+ expect(invalidResponse).to.be.an('array').that.is.empty;
+ });
+
+ it('should interpret valid response', function () {
+ const serverResponse = {
+ body: {
+ data: [{
+ requestId: 'qwerty',
+ cpm: 1,
+ currency: 'USD',
+ width: 300,
+ height: 250,
+ ttl: 600,
+ meta: {
+ advertiserDomains: ['lm_kiviads']
+ },
+ ext: {
+ pixels: [
+ ['iframe', 'surl1'],
+ ['image', 'surl2'],
+ ]
+ }
+ }]
+ }
+ };
+
+ const validResponse = spec.interpretResponse(serverResponse, {bidderRequest: defaultRequest});
+ const bid = validResponse[0];
+ expect(validResponse).to.be.an('array').that.is.not.empty;
+ expect(bid.requestId).to.equal('qwerty');
+ expect(bid.cpm).to.equal(1);
+ expect(bid.currency).to.equal('USD');
+ expect(bid.width).to.equal(300);
+ expect(bid.height).to.equal(250);
+ expect(bid.ttl).to.equal(600);
+ expect(bid.meta).to.deep.equal({advertiserDomains: ['lm_kiviads']});
+ });
+
+ it('should interpret valid banner response', function () {
+ const serverResponse = {
+ body: {
+ data: [{
+ requestId: 'qwerty',
+ cpm: 1,
+ currency: 'USD',
+ width: 300,
+ height: 250,
+ ttl: 600,
+ mediaType: 'banner',
+ creativeId: 'xe-demo-banner',
+ ad: 'ad',
+ meta: {}
+ }]
+ }
+ };
+
+ const validResponseBanner = spec.interpretResponse(serverResponse, {bidderRequest: defaultRequest});
+ const bid = validResponseBanner[0];
+ expect(validResponseBanner).to.be.an('array').that.is.not.empty;
+ expect(bid.mediaType).to.equal('banner');
+ expect(bid.creativeId).to.equal('xe-demo-banner');
+ expect(bid.ad).to.equal('ad');
+ });
+
+ it('should interpret valid video response', function () {
+ const serverResponse = {
+ body: {
+ data: [{
+ requestId: 'qwerty',
+ cpm: 1,
+ currency: 'USD',
+ width: 600,
+ height: 480,
+ ttl: 600,
+ mediaType: 'video',
+ creativeId: 'xe-demo-video',
+ ad: 'vast-xml',
+ meta: {}
+ }]
+ }
+ };
+
+ const validResponseBanner = spec.interpretResponse(serverResponse, {bidderRequest: defaultRequestVideo});
+ const bid = validResponseBanner[0];
+ expect(validResponseBanner).to.be.an('array').that.is.not.empty;
+ expect(bid.mediaType).to.equal('video');
+ expect(bid.creativeId).to.equal('xe-demo-video');
+ expect(bid.ad).to.equal('vast-xml');
+ });
+ });
+
+ describe('getUserSyncs', function () {
+ it('shoukd handle no params', function () {
+ const opts = spec.getUserSyncs({}, []);
+ expect(opts).to.be.an('array').that.is.empty;
+ });
+
+ it('should return empty if sync is not allowed', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: false});
+ expect(opts).to.be.an('array').that.is.empty;
+ });
+
+ it('should allow iframe sync', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: false}, [{
+ body: {
+ data: [{
+ requestId: 'qwerty',
+ ext: {
+ pixels: [
+ ['iframe', 'surl1?a=b'],
+ ['image', 'surl2?a=b'],
+ ]
+ }
+ }]
+ }
+ }]);
+ expect(opts.length).to.equal(1);
+ expect(opts[0].type).to.equal('iframe');
+ expect(opts[0].url).to.equal('surl1?a=b&us_privacy=&gdpr=0&gdpr_consent=');
+ });
+
+ it('should allow pixel sync', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, [{
+ body: {
+ data: [{
+ requestId: 'qwerty',
+ ext: {
+ pixels: [
+ ['iframe', 'surl1?a=b'],
+ ['image', 'surl2?a=b'],
+ ]
+ }
+ }]
+ }
+ }]);
+ expect(opts.length).to.equal(1);
+ expect(opts[0].type).to.equal('image');
+ expect(opts[0].url).to.equal('surl2?a=b&us_privacy=&gdpr=0&gdpr_consent=');
+ });
+
+ it('should allow pixel sync and parse consent params', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, [{
+ body: {
+ data: [{
+ requestId: 'qwerty',
+ ext: {
+ pixels: [
+ ['iframe', 'surl1?a=b'],
+ ['image', 'surl2?a=b'],
+ ]
+ }
+ }]
+ }
+ }], {
+ gdprApplies: 1,
+ consentString: '1YA-'
+ });
+ expect(opts.length).to.equal(1);
+ expect(opts[0].type).to.equal('image');
+ expect(opts[0].url).to.equal('surl2?a=b&us_privacy=&gdpr=1&gdpr_consent=1YA-');
+ });
+ });
+
+ describe('getBidFloor', function () {
+ it('should return null when getFloor is not a function', () => {
+ const bid = {getFloor: 2};
+ const result = getBidFloor(bid);
+ expect(result).to.be.null;
+ });
+
+ it('should return null when getFloor doesnt return an object', () => {
+ const bid = {getFloor: () => 2};
+ const result = getBidFloor(bid);
+ expect(result).to.be.null;
+ });
+
+ it('should return null when floor is not a number', () => {
+ const bid = {
+ getFloor: () => ({floor: 'string', currency: 'USD'})
+ };
+ const result = getBidFloor(bid);
+ expect(result).to.be.null;
+ });
+
+ it('should return null when currency is not USD', () => {
+ const bid = {
+ getFloor: () => ({floor: 5, currency: 'EUR'})
+ };
+ const result = getBidFloor(bid);
+ expect(result).to.be.null;
+ });
+
+ it('should return floor value when everything is correct', () => {
+ const bid = {
+ getFloor: () => ({floor: 5, currency: 'USD'})
+ };
+ const result = getBidFloor(bid);
+ expect(result).to.equal(5);
+ });
+ });
+})
diff --git a/test/spec/modules/logicadBidAdapter_spec.js b/test/spec/modules/logicadBidAdapter_spec.js
index 3c1383781b9..12e8ca31cbb 100644
--- a/test/spec/modules/logicadBidAdapter_spec.js
+++ b/test/spec/modules/logicadBidAdapter_spec.js
@@ -36,6 +36,11 @@ describe('LogicadAdapter', function () {
}
}]
}],
+ ortb2Imp: {
+ ext: {
+ ae: 1
+ }
+ },
ortb2: {
device: {
sua: {
@@ -176,7 +181,8 @@ describe('LogicadAdapter', function () {
numIframes: 1,
stack: []
},
- auctionStart: 1563337198010
+ auctionStart: 1563337198010,
+ fledgeEnabled: true
};
const serverResponse = {
body: {
@@ -203,6 +209,49 @@ describe('LogicadAdapter', function () {
}
}
};
+
+ const paapiServerResponse = {
+ body: {
+ seatbid:
+ [{
+ bid: {
+ requestId: '51ef8751f9aead',
+ cpm: 101.0234,
+ width: 300,
+ height: 250,
+ creativeId: '2019',
+ currency: 'JPY',
+ netRevenue: true,
+ ttl: 60,
+ ad: '
TEST
',
+ meta: {
+ advertiserDomains: ['logicad.com']
+ }
+ }
+ }],
+ ext: {
+ fledgeAuctionConfigs: [{
+ bidId: '51ef8751f9aead',
+ config: {
+ seller: 'https://fledge.ladsp.com',
+ decisionLogicUrl: 'https://fledge.ladsp.com/decision_logic.js',
+ interestGroupBuyers: ['https://fledge.ladsp.com'],
+ requestedSize: {width: '300', height: '250'},
+ allSlotsRequestedSizes: [{width: '300', height: '250'}],
+ sellerSignals: {signal: 'signal'},
+ sellerTimeout: '500',
+ perBuyerSignals: {'https://fledge.ladsp.com': {signal: 'signal'}},
+ perBuyerCurrencies: {'https://fledge.ladsp.com': 'USD'}
+ }
+ }]
+ },
+ userSync: {
+ type: 'image',
+ url: 'https://cr-p31.ladsp.jp/cookiesender/31'
+ }
+ }
+ };
+
const nativeServerResponse = {
body: {
seatbid:
@@ -272,6 +321,11 @@ describe('LogicadAdapter', function () {
const data = JSON.parse(request.data);
expect(data.auctionId).to.equal('18fd8b8b0bd757');
+
+ // Protected Audience API flag
+ expect(data.bids[0]).to.have.property('ae');
+ expect(data.bids[0].ae).to.equal(1);
+
expect(data.eids[0].source).to.equal('sharedid.org');
expect(data.eids[0].uids[0].id).to.equal('fakesharedid');
@@ -330,6 +384,13 @@ describe('LogicadAdapter', function () {
expect(interpretedResponse[0].ttl).to.equal(serverResponse.body.seatbid[0].bid.ttl);
expect(interpretedResponse[0].meta.advertiserDomains).to.equal(serverResponse.body.seatbid[0].bid.meta.advertiserDomains);
+ // Protected Audience API
+ const paapiRequest = spec.buildRequests(bidRequests, bidderRequest)[0];
+ const paapiInterpretedResponse = spec.interpretResponse(paapiServerResponse, paapiRequest);
+ expect(paapiInterpretedResponse).to.have.property('bids');
+ expect(paapiInterpretedResponse).to.have.property('fledgeAuctionConfigs');
+ expect(paapiInterpretedResponse.fledgeAuctionConfigs[0]).to.deep.equal(paapiServerResponse.body.ext.fledgeAuctionConfigs[0]);
+
// native
const nativeRequest = spec.buildRequests(nativeBidRequests, bidderRequest)[0];
const interpretedResponseForNative = spec.interpretResponse(nativeServerResponse, nativeRequest);
diff --git a/test/spec/modules/luceadBidAdapter_spec.js b/test/spec/modules/luceadBidAdapter_spec.js
new file mode 100644
index 00000000000..72bc7cc2d6e
--- /dev/null
+++ b/test/spec/modules/luceadBidAdapter_spec.js
@@ -0,0 +1,171 @@
+/* eslint-disable prebid/validate-imports,no-undef */
+import { expect } from 'chai';
+import { spec } from 'modules/luceadBidAdapter.js';
+import sinon from 'sinon';
+import { newBidder } from 'src/adapters/bidderFactory.js';
+import {deepClone} from 'src/utils.js';
+import * as ajax from 'src/ajax.js';
+
+describe('Lucead Adapter', () => {
+ describe('inherited functions', function () {
+ it('exists and is a function', function () {
+ // noinspection JSCheckFunctionSignatures
+ const adapter = newBidder(spec);
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
+ });
+ });
+
+ describe('utils functions', function () {
+ it('returns false', function () {
+ expect(spec.isDevEnv()).to.be.false;
+ });
+ });
+
+ describe('isBidRequestValid', function () {
+ let bid;
+ beforeEach(function () {
+ bid = {
+ bidder: 'lucead',
+ params: {
+ placementId: '1',
+ },
+ };
+ });
+
+ it('should return true when required params found', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+ });
+
+ describe('onBidWon', function () {
+ let sandbox;
+ const bid = { foo: 'bar', creativeId: 'ssp:improve' };
+
+ beforeEach(function () {
+ sandbox = sinon.sandbox.create();
+ });
+
+ it('should trigger impression pixel', function () {
+ sandbox.spy(ajax, 'fetch');
+ spec.onBidWon(bid);
+ expect(ajax.fetch.args[0][0]).to.match(/report\/impression$/);
+ });
+
+ afterEach(function () {
+ sandbox.restore();
+ });
+ });
+
+ describe('buildRequests', function () {
+ const bidRequests = [
+ {
+ bidder: 'lucead',
+ adUnitCode: 'lucead_code',
+ bidId: 'abc1234',
+ sizes: [[1800, 1000], [640, 300]],
+ requestId: 'xyz654',
+ params: {
+ placementId: '123',
+ }
+ }
+ ];
+
+ const bidderRequest = {
+ bidderRequestId: '13aaa3df18bfe4',
+ bids: {}
+ };
+
+ it('should have a post method', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request[0].method).to.equal('POST');
+ });
+
+ it('should contains a request id equals to the bid id', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(JSON.parse(request[0].data).bid_id).to.equal(bidRequests[0].bidId);
+ });
+
+ it('should have an url that contains sub keyword', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request[0].url).to.match(/sub/);
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const serverResponse = {
+ body: {
+ 'bid_id': '2daf899fbe4c52',
+ 'request_id': '13aaa3df18bfe4',
+ 'ad': 'Ad',
+ 'ad_id': '3890677904',
+ 'cpm': 3.02,
+ 'currency': 'USD',
+ 'time': 1707257712095,
+ 'size': {'width': 300, 'height': 250},
+ }
+ };
+
+ const bidRequest = {data: JSON.stringify({
+ 'request_id': '13aaa3df18bfe4',
+ 'domain': '7cdb-2a02-8429-e4a0-1701-bc69-d51c-86e-b279.ngrok-free.app',
+ 'bid_id': '2daf899fbe4c52',
+ 'sizes': [[300, 250]],
+ 'media_types': {'banner': {'sizes': [[300, 250]]}},
+ 'fledge_enabled': true,
+ 'enable_contextual': true,
+ 'enable_pa': true,
+ 'params': {'placementId': '1'},
+ })};
+
+ it('should get correct bid response', function () {
+ const result = spec.interpretResponse(serverResponse, bidRequest);
+
+ expect(Object.keys(result.bids[0])).to.have.members([
+ 'requestId',
+ 'cpm',
+ 'width',
+ 'height',
+ 'currency',
+ 'ttl',
+ 'creativeId',
+ 'netRevenue',
+ 'ad',
+ 'meta',
+ ]);
+ });
+
+ it('should return bid empty response', function () {
+ const serverResponse = {body: {cpm: 0}};
+ const bidRequest = {data: '{}'};
+ const result = spec.interpretResponse(serverResponse, bidRequest);
+ expect(result.bids[0].ad).to.be.equal('');
+ expect(result.bids[0].cpm).to.be.equal(0);
+ });
+
+ it('should add advertiserDomains', function () {
+ const bidRequest = {data: JSON.stringify({
+ bidder: 'lucead',
+ params: {
+ placementId: '1',
+ }
+ })};
+
+ const result = spec.interpretResponse(serverResponse, bidRequest);
+ expect(Object.keys(result.bids[0].meta)).to.include.members(['advertiserDomains']);
+ });
+
+ it('should support disabled contextual bids', function () {
+ const serverResponseWithDisabledContectual = deepClone(serverResponse);
+ serverResponseWithDisabledContectual.body.enable_contextual = false;
+ const result = spec.interpretResponse(serverResponseWithDisabledContectual, bidRequest);
+ expect(result.bids).to.be.null;
+ });
+
+ it('should support disabled Protected Audience', function () {
+ const serverResponseWithEnablePaFalse = deepClone(serverResponse);
+ serverResponseWithEnablePaFalse.body.enable_pa = false;
+ const result = spec.interpretResponse(serverResponseWithEnablePaFalse, bidRequest);
+ expect(result.fledgeAuctionConfigs).to.be.undefined;
+ });
+ });
+});
diff --git a/test/spec/modules/magniteAnalyticsAdapter_spec.js b/test/spec/modules/magniteAnalyticsAdapter_spec.js
index 0864a976d7d..397ee4a8577 100644
--- a/test/spec/modules/magniteAnalyticsAdapter_spec.js
+++ b/test/spec/modules/magniteAnalyticsAdapter_spec.js
@@ -3,7 +3,8 @@ import magniteAdapter, {
getHostNameFromReferer,
storage,
rubiConf,
- detectBrowserFromUa
+ detectBrowserFromUa,
+ callPrebidCacheHook
} from '../../../modules/magniteAnalyticsAdapter.js';
import CONSTANTS from 'src/constants.json';
import { config } from 'src/config.js';
@@ -1137,6 +1138,39 @@ describe('magnite analytics adapter', function () {
});
});
+ it('should not use pbsBidId if the bid was client side cached', function () {
+ // bid response
+ let seatBidResponse = utils.deepClone(MOCK.BID_RESPONSE);
+ seatBidResponse.pbsBidId = 'do-not-use-me';
+
+ // Run auction
+ events.emit(AUCTION_INIT, MOCK.AUCTION_INIT);
+ events.emit(BID_REQUESTED, MOCK.BID_REQUESTED);
+
+ // mock client side cache call
+ callPrebidCacheHook(() => {}, {}, seatBidResponse);
+
+ events.emit(BID_RESPONSE, seatBidResponse);
+ events.emit(BIDDER_DONE, MOCK.BIDDER_DONE);
+ events.emit(AUCTION_END, MOCK.AUCTION_END);
+
+ // emmit gpt events and bidWon
+ mockGpt.emitEvent(gptSlotRenderEnded0.eventName, gptSlotRenderEnded0.params);
+
+ events.emit(BID_WON, MOCK.BID_WON);
+
+ // tick the event delay time plus processing delay
+ clock.tick(rubiConf.analyticsEventDelay + rubiConf.analyticsProcessDelay);
+
+ expect(server.requests.length).to.equal(1);
+ let request = server.requests[0];
+ let message = JSON.parse(request.requestBody);
+
+ // Expect the ids sent to server to use the original bidId not the pbsBidId thing
+ expect(message.auctions[0].adUnits[0].bids[0].bidId).to.equal(MOCK.BID_RESPONSE.requestId);
+ expect(message.bidsWon[0].bidId).to.equal(MOCK.BID_RESPONSE.requestId);
+ });
+
[0, '0'].forEach(pbsParam => {
it(`should generate new bidId if incoming pbsBidId is ${pbsParam}`, function () {
// bid response
@@ -1707,6 +1741,79 @@ describe('magnite analytics adapter', function () {
expect(message1.bidsWon).to.deep.equal([expectedMessage1]);
});
});
+ describe('cookieless', () => {
+ beforeEach(() => {
+ magniteAdapter.enableAnalytics({
+ options: {
+ cookieles: undefined
+ }
+ });
+ })
+ afterEach(() => {
+ magniteAdapter.disableAnalytics();
+ })
+ it('should add sufix _cookieless to the wrapper.rule if ortb2.device.ext.cdep start with "treatment" or "control_2"', () => {
+ // Set the confs
+ config.setConfig({
+ rubicon: {
+ wrapperName: '1001_general',
+ wrapperFamily: 'general',
+ rule_name: 'desktop-magnite.com',
+ }
+ });
+ const auctionId = MOCK.AUCTION_INIT.auctionId;
+
+ let auctionInit = utils.deepClone(MOCK.AUCTION_INIT);
+ auctionInit.bidderRequests[0].ortb2.device.ext = { cdep: 'treatment' };
+ // Run auction
+ events.emit(AUCTION_INIT, auctionInit);
+ events.emit(BID_REQUESTED, MOCK.BID_REQUESTED);
+ events.emit(BID_RESPONSE, MOCK.BID_RESPONSE);
+ events.emit(BIDDER_DONE, MOCK.BIDDER_DONE);
+ events.emit(AUCTION_END, MOCK.AUCTION_END);
+ [gptSlotRenderEnded0].forEach(gptEvent => mockGpt.emitEvent(gptEvent.eventName, gptEvent.params));
+ events.emit(BID_WON, { ...MOCK.BID_WON, auctionId });
+ clock.tick(rubiConf.analyticsEventDelay);
+ expect(server.requests.length).to.equal(1);
+ let request = server.requests[0];
+ let message = JSON.parse(request.requestBody);
+ expect(message.wrapper).to.deep.equal({
+ name: '1001_general',
+ family: 'general',
+ rule: 'desktop-magnite.com_cookieless',
+ });
+ })
+ it('should add cookieless to the wrapper.rule if ortb2.device.ext.cdep start with "treatment" or "control_2"', () => {
+ // Set the confs
+ config.setConfig({
+ rubicon: {
+ wrapperName: '1001_general',
+ wrapperFamily: 'general',
+ }
+ });
+ const auctionId = MOCK.AUCTION_INIT.auctionId;
+
+ let auctionInit = utils.deepClone(MOCK.AUCTION_INIT);
+ auctionInit.bidderRequests[0].ortb2.device.ext = { cdep: 'control_2' };
+ // Run auction
+ events.emit(AUCTION_INIT, auctionInit);
+ events.emit(BID_REQUESTED, MOCK.BID_REQUESTED);
+ events.emit(BID_RESPONSE, MOCK.BID_RESPONSE);
+ events.emit(BIDDER_DONE, MOCK.BIDDER_DONE);
+ events.emit(AUCTION_END, MOCK.AUCTION_END);
+ [gptSlotRenderEnded0].forEach(gptEvent => mockGpt.emitEvent(gptEvent.eventName, gptEvent.params));
+ events.emit(BID_WON, { ...MOCK.BID_WON, auctionId });
+ clock.tick(rubiConf.analyticsEventDelay);
+ expect(server.requests.length).to.equal(1);
+ let request = server.requests[0];
+ let message = JSON.parse(request.requestBody);
+ expect(message.wrapper).to.deep.equal({
+ family: 'general',
+ name: '1001_general',
+ rule: 'cookieless',
+ });
+ });
+ });
});
describe('billing events integration', () => {
diff --git a/test/spec/modules/mediabramaBidAdapter_spec.js b/test/spec/modules/mediabramaBidAdapter_spec.js
new file mode 100644
index 00000000000..d7341e02f17
--- /dev/null
+++ b/test/spec/modules/mediabramaBidAdapter_spec.js
@@ -0,0 +1,256 @@
+import {expect} from 'chai';
+import {spec} from '../../../modules/mediabramaBidAdapter.js';
+import { BANNER } from '../../../src/mediaTypes.js';
+import * as utils from '../../../src/utils.js';
+
+describe('MediaBramaBidAdapter', function () {
+ const bid = {
+ bidId: '23dc19818e5293',
+ bidder: 'mediabrama',
+ mediaTypes: {
+ [BANNER]: {
+ sizes: [[300, 250]]
+ }
+ },
+ params: {
+ placementId: 24428,
+ }
+ };
+
+ const bidderRequest = {
+ refererInfo: {
+ referer: 'test.com'
+ }
+ };
+
+ describe('isBidRequestValid', function () {
+ it('Should return true if there are bidId, params and key parameters present', function () {
+ expect(spec.isBidRequestValid(bid)).to.be.true;
+ });
+ it('Should return false if at least one of parameters is not present', function () {
+ delete bid.params.placementId;
+ expect(spec.isBidRequestValid(bid)).to.be.false;
+ });
+ });
+
+ describe('buildRequests', function () {
+ let serverRequest = spec.buildRequests([bid], bidderRequest);
+ it('Creates a ServerRequest object with method, URL and data', function () {
+ expect(serverRequest).to.exist;
+ expect(serverRequest.method).to.exist;
+ expect(serverRequest.url).to.exist;
+ expect(serverRequest.data).to.exist;
+ });
+ it('Returns POST method', function () {
+ expect(serverRequest.method).to.equal('POST');
+ });
+ it('Returns valid URL', function () {
+ expect(serverRequest.url).to.equal('https://prebid.mediabrama.com/pbjs');
+ });
+ it('Returns valid data if array of bids is valid', function () {
+ let data = serverRequest.data;
+ expect(data).to.be.an('object');
+ expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'host', 'page', 'placements');
+ expect(data.deviceWidth).to.be.a('number');
+ expect(data.deviceHeight).to.be.a('number');
+ expect(data.language).to.be.a('string');
+ expect(data.host).to.be.a('string');
+ expect(data.page).to.be.a('string');
+ expect(data.gdpr).to.not.exist;
+ expect(data.ccpa).to.not.exist;
+ let placement = data['placements'][0];
+ expect(placement).to.have.keys('placementId', 'bidId', 'adFormat', 'sizes', 'schain', 'bidfloor');
+ expect(placement.placementId).to.equal(24428);
+ expect(placement.bidId).to.equal('23dc19818e5293');
+ expect(placement.adFormat).to.equal(BANNER);
+ expect(placement.schain).to.be.an('object');
+ expect(placement.sizes).to.be.an('array');
+ expect(placement.bidfloor).to.exist.and.to.equal(0);
+ });
+
+ it('Returns data with gdprConsent and without uspConsent', function () {
+ bidderRequest.gdprConsent = 'test';
+ serverRequest = spec.buildRequests([bid], bidderRequest);
+ let data = serverRequest.data;
+ expect(data.gdpr).to.exist;
+ expect(data.gdpr).to.be.a('string');
+ expect(data.gdpr).to.equal(bidderRequest.gdprConsent);
+ expect(data.ccpa).to.not.exist;
+ delete bidderRequest.gdprConsent;
+ });
+
+ it('Returns data with uspConsent and without gdprConsent', function () {
+ bidderRequest.uspConsent = 'test';
+ serverRequest = spec.buildRequests([bid], bidderRequest);
+ let data = serverRequest.data;
+ expect(data.ccpa).to.exist;
+ expect(data.ccpa).to.be.a('string');
+ expect(data.ccpa).to.equal(bidderRequest.uspConsent);
+ expect(data.gdpr).to.not.exist;
+ });
+
+ it('Returns empty data if no valid requests are passed', function () {
+ serverRequest = spec.buildRequests([]);
+ let data = serverRequest.data;
+ expect(data.placements).to.be.an('array').that.is.empty;
+ });
+ });
+ describe('interpretResponse', function () {
+ it('Should interpret banner response', function () {
+ const banner = {
+ body: [{
+ mediaType: 'banner',
+ width: 300,
+ height: 250,
+ cpm: 0.4,
+ ad: 'Test',
+ requestId: '23dc19818e5293',
+ ttl: 120,
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ dealId: '1',
+ meta: {}
+ }]
+ };
+ let bannerResponses = spec.interpretResponse(banner);
+ expect(bannerResponses).to.be.an('array').that.is.not.empty;
+ let dataItem = bannerResponses[0];
+ expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId',
+ 'netRevenue', 'currency', 'dealId', 'mediaType', 'meta');
+ expect(dataItem.requestId).to.equal('23dc19818e5293');
+ expect(dataItem.cpm).to.equal(0.4);
+ expect(dataItem.width).to.equal(300);
+ expect(dataItem.height).to.equal(250);
+ expect(dataItem.ad).to.equal('Test');
+ expect(dataItem.ttl).to.equal(120);
+ expect(dataItem.creativeId).to.equal('2');
+ expect(dataItem.netRevenue).to.be.true;
+ expect(dataItem.currency).to.equal('USD');
+ expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains');
+ });
+ it('Should return an empty array if invalid banner response is passed', function () {
+ const invBanner = {
+ body: [{
+ width: 300,
+ cpm: 0.4,
+ ad: 'Test',
+ requestId: '23dc19818e5293',
+ ttl: 120,
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ dealId: '1'
+ }]
+ };
+
+ let serverResponses = spec.interpretResponse(invBanner);
+ expect(serverResponses).to.be.an('array').that.is.empty;
+ });
+ it('Should return an empty array if invalid response is passed', function () {
+ const invalid = {
+ body: [{
+ ttl: 120,
+ creativeId: '2',
+ netRevenue: true,
+ currency: 'USD',
+ dealId: '1'
+ }]
+ };
+ let serverResponses = spec.interpretResponse(invalid);
+ expect(serverResponses).to.be.an('array').that.is.empty;
+ });
+ });
+
+ describe('getUserSyncs', function () {
+ it('should do nothing on getUserSyncs', function () {
+ const syncData = spec.getUserSyncs({}, {}, {
+ consentString: 'ALL',
+ gdprApplies: true
+ }, {});
+ expect(syncData).to.be.an('array').which.is.not.empty;
+ expect(syncData[0]).to.be.an('object')
+ expect(syncData[0].type).to.be.a('string')
+ expect(syncData[0].type).to.equal('image')
+ expect(syncData[0].url).to.be.a('string')
+ expect(syncData[0].url).to.equal('https://prebid.mediabrama.com/sync/image?pbjs=1&gdpr=1&gdpr_consent=ALL&coppa=0')
+ });
+ });
+
+ describe('on bidWon', function () {
+ beforeEach(function() {
+ sinon.stub(utils, 'triggerPixel');
+ });
+ afterEach(function() {
+ utils.triggerPixel.restore();
+ });
+ it('should replace nurl for banner', function () {
+ const nurl = 'nurl/?ap=${' + 'AUCTION_PRICE}';
+ const bid = {
+ 'bidderCode': 'mediabrama',
+ 'width': 300,
+ 'height': 250,
+ 'statusMessage': 'Bid available',
+ 'adId': '5691dd18ba6ab6',
+ 'requestId': '23dc19818e5293',
+ 'transactionId': '948c716b-bf64-4303-bcf4-395c2f6a9770',
+ 'auctionId': 'a6b7c61f-15a9-481b-8f64-e859787e9c07',
+ 'mediaType': 'banner',
+ 'source': 'client',
+ 'ad': "
\n",
+ 'cpm': 0.61,
+ 'nurl': nurl,
+ 'creativeId': 'test',
+ 'currency': 'USD',
+ 'dealId': '',
+ 'meta': {
+ 'advertiserDomains': [],
+ 'dchain': {
+ 'ver': '1.0',
+ 'complete': 0,
+ 'nodes': [
+ {
+ 'name': 'mediabrama'
+ }
+ ]
+ }
+ },
+ 'netRevenue': true,
+ 'ttl': 185,
+ 'metrics': {},
+ 'adapterCode': 'mediabrama',
+ 'originalCpm': 0.61,
+ 'originalCurrency': 'USD',
+ 'responseTimestamp': 1668162732297,
+ 'requestTimestamp': 1668162732292,
+ 'bidder': 'mediabrama',
+ 'adUnitCode': 'div-prebid',
+ 'timeToRespond': 5,
+ 'pbLg': '0.50',
+ 'pbMg': '0.60',
+ 'pbHg': '0.61',
+ 'pbAg': '0.61',
+ 'pbDg': '0.61',
+ 'pbCg': '',
+ 'size': '300x250',
+ 'adserverTargeting': {
+ 'hb_bidder': 'mediabrama',
+ 'hb_adid': '5691dd18ba6ab6',
+ 'hb_pb': '0.61',
+ 'hb_size': '300x250',
+ 'hb_source': 'client',
+ 'hb_format': 'banner',
+ 'hb_adomain': ''
+ },
+ 'status': 'rendered',
+ 'params': [
+ {
+ 'placementId': 24428
+ }
+ ]
+ };
+ spec.onBidWon(bid);
+ expect(bid.nurl).to.deep.equal('nurl/?ap=0.61');
+ });
+ });
+});
diff --git a/test/spec/modules/mediafilterRtdProvider_spec.js b/test/spec/modules/mediafilterRtdProvider_spec.js
new file mode 100644
index 00000000000..3395c7be691
--- /dev/null
+++ b/test/spec/modules/mediafilterRtdProvider_spec.js
@@ -0,0 +1,147 @@
+import * as utils from '../../../src/utils.js';
+import * as hook from '../../../src/hook.js'
+import * as events from '../../../src/events.js';
+import CONSTANTS from '../../../src/constants.json';
+
+import {
+ MediaFilter,
+ MEDIAFILTER_EVENT_TYPE,
+ MEDIAFILTER_BASE_URL
+} from '../../../modules/mediafilterRtdProvider.js';
+
+describe('The Media Filter RTD module', function () {
+ describe('register()', function() {
+ let submoduleSpy, generateInitHandlerSpy;
+
+ beforeEach(function () {
+ submoduleSpy = sinon.spy(hook, 'submodule');
+ generateInitHandlerSpy = sinon.spy(MediaFilter, 'generateInitHandler');
+ });
+
+ afterEach(function () {
+ submoduleSpy.restore();
+ generateInitHandlerSpy.restore();
+ });
+
+ it('should register and call the submodule function(s)', function () {
+ MediaFilter.register();
+
+ expect(submoduleSpy.calledOnceWithExactly('realTimeData', sinon.match.object)).to.be.true;
+ expect(submoduleSpy.called).to.be.true;
+ expect(generateInitHandlerSpy.called).to.be.true;
+ });
+ });
+
+ describe('setup()', function() {
+ let setupEventListenerSpy, setupScriptSpy;
+
+ beforeEach(function() {
+ setupEventListenerSpy = sinon.spy(MediaFilter, 'setupEventListener');
+ setupScriptSpy = sinon.spy(MediaFilter, 'setupScript');
+ });
+
+ afterEach(function() {
+ setupEventListenerSpy.restore();
+ setupScriptSpy.restore();
+ });
+
+ it('should call setupEventListener and setupScript function(s)', function() {
+ MediaFilter.setup({ configurationHash: 'abc123' });
+
+ expect(setupEventListenerSpy.called).to.be.true;
+ expect(setupScriptSpy.called).to.be.true;
+ });
+ });
+
+ describe('setupEventListener()', function() {
+ let setupEventListenerSpy, addEventListenerSpy;
+
+ beforeEach(function() {
+ setupEventListenerSpy = sinon.spy(MediaFilter, 'setupEventListener');
+ addEventListenerSpy = sinon.spy(window, 'addEventListener');
+ });
+
+ afterEach(function() {
+ setupEventListenerSpy.restore();
+ addEventListenerSpy.restore();
+ });
+
+ it('should call addEventListener function(s)', function() {
+ MediaFilter.setupEventListener();
+ expect(addEventListenerSpy.called).to.be.true;
+ expect(addEventListenerSpy.calledWith('message', sinon.match.func)).to.be.true;
+ });
+ });
+
+ describe('generateInitHandler()', function() {
+ let generateInitHandlerSpy, setupMock, logErrorSpy;
+
+ beforeEach(function() {
+ generateInitHandlerSpy = sinon.spy(MediaFilter, 'generateInitHandler');
+ setupMock = sinon.stub(MediaFilter, 'setup').throws(new Error('Mocked error!'));
+ logErrorSpy = sinon.spy(utils, 'logError');
+ });
+
+ afterEach(function() {
+ generateInitHandlerSpy.restore();
+ setupMock.restore();
+ logErrorSpy.restore();
+ });
+
+ it('should handle errors in the catch block when setup throws an error', function() {
+ const initHandler = MediaFilter.generateInitHandler();
+ initHandler({});
+
+ expect(logErrorSpy.calledWith('Error in initialization: Mocked error!')).to.be.true;
+ });
+ });
+
+ describe('generateEventHandler()', function() {
+ let generateEventHandlerSpy, eventsEmitSpy;
+
+ beforeEach(function() {
+ generateEventHandlerSpy = sinon.spy(MediaFilter, 'generateEventHandler');
+ eventsEmitSpy = sinon.spy(events, 'emit');
+ });
+
+ afterEach(function() {
+ generateEventHandlerSpy.restore();
+ eventsEmitSpy.restore();
+ });
+
+ it('should emit a billable event when the event type matches', function() {
+ const configurationHash = 'abc123';
+ const eventHandler = MediaFilter.generateEventHandler(configurationHash);
+
+ const mockEvent = {
+ data: {
+ type: MEDIAFILTER_EVENT_TYPE.concat('.', configurationHash)
+ }
+ };
+
+ eventHandler(mockEvent);
+
+ expect(eventsEmitSpy.calledWith(CONSTANTS.EVENTS.BILLABLE_EVENT, {
+ 'billingId': sinon.match.string,
+ 'configurationHash': configurationHash,
+ 'type': 'impression',
+ 'vendor': 'mediafilter',
+ })).to.be.true;
+ });
+
+ it('should not emit a billable event when the event type does not match', function() {
+ const configurationHash = 'abc123';
+ const eventHandler = MediaFilter.generateEventHandler(configurationHash);
+
+ const mockEvent = {
+ data: {
+ type: 'differentEventType'
+ }
+ };
+
+ eventHandler(mockEvent);
+
+ expect(eventsEmitSpy.called).to.be.false;
+ });
+ });
+});
diff --git a/test/spec/modules/mediagoBidAdapter_spec.js b/test/spec/modules/mediagoBidAdapter_spec.js
index e77af544429..6e58217b3d3 100644
--- a/test/spec/modules/mediagoBidAdapter_spec.js
+++ b/test/spec/modules/mediagoBidAdapter_spec.js
@@ -1,5 +1,17 @@
import { expect } from 'chai';
-import { spec } from 'modules/mediagoBidAdapter.js';
+import {
+ spec,
+ getPmgUID,
+ storage,
+ getPageTitle,
+ getPageDescription,
+ getPageKeywords,
+ getConnectionDownLink,
+ THIRD_PARTY_COOKIE_ORIGIN,
+ COOKIE_KEY_MGUID,
+ getCurrentTimeToUTCString
+} from 'modules/mediagoBidAdapter.js';
+import * as utils from 'src/utils.js';
describe('mediago:BidAdapterTests', function () {
let bidRequestData = {
@@ -11,12 +23,49 @@ describe('mediago:BidAdapterTests', function () {
bidder: 'mediago',
params: {
token: '85a6b01e41ac36d49744fad726e3655d',
+ siteId: 'siteId_01',
+ zoneId: 'zoneId_01',
+ publisher: '52',
+ position: 'left',
+ referrer: 'https://trace.mediago.io',
bidfloor: 0.01,
+ ortb2Imp: {
+ ext: {
+ gpid: 'adslot_gpid',
+ tid: 'tid_01',
+ data: {
+ browsi: {
+ browsiViewability: 'NA'
+ },
+ adserver: {
+ name: 'adserver_name',
+ adslot: 'adslot_name'
+ },
+ pbadslot: '/12345/my-gpt-tag-0'
+ }
+ }
+ }
},
mediaTypes: {
banner: {
sizes: [[300, 250]],
+ pos: 'left'
+ }
+ },
+ ortb2: {
+ site: {
+ cat: ['IAB2'],
+ keywords: 'power tools, drills, tools=industrial',
+ content: {
+ keywords: 'video, source=streaming'
+ },
+
},
+ user: {
+ ext: {
+ data: {}
+ }
+ }
},
adUnitCode: 'regular_iframe',
transactionId: '7b26fdae-96e6-4c35-a18b-218dda11397d',
@@ -27,9 +76,83 @@ describe('mediago:BidAdapterTests', function () {
src: 'client',
bidRequestsCount: 1,
bidderRequestsCount: 1,
- bidderWinsCount: 0,
- },
+ bidderWinsCount: 0
+ }
],
+ gdprConsent: {
+ consentString: 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A==',
+ gdprApplies: true,
+ apiVersion: 2,
+ vendorData: {
+ purpose: {
+ consents: {
+ 1: false
+ }
+ }
+ }
+ },
+ userId: {
+ tdid: 'sample-userid',
+ uid2: { id: 'sample-uid2-value' },
+ criteoId: 'sample-criteo-userid',
+ netId: 'sample-netId-userid',
+ idl_env: 'sample-idl-userid',
+ pubProvidedId: [
+ {
+ source: 'puburl.com',
+ uids: [
+ {
+ id: 'pubid2',
+ atype: 1,
+ ext: {
+ stype: 'ppuid'
+ }
+ }
+ ]
+ },
+ {
+ source: 'puburl2.com',
+ uids: [
+ {
+ id: 'pubid2'
+ },
+ {
+ id: 'pubid2-123'
+ }
+ ]
+ }
+ ]
+ },
+ userIdAsEids: [
+ {
+ source: 'adserver.org',
+ uids: [{ id: 'sample-userid' }]
+ },
+ {
+ source: 'criteo.com',
+ uids: [{ id: 'sample-criteo-userid' }]
+ },
+ {
+ source: 'netid.de',
+ uids: [{ id: 'sample-netId-userid' }]
+ },
+ {
+ source: 'liveramp.com',
+ uids: [{ id: 'sample-idl-userid' }]
+ },
+ {
+ source: 'uidapi.com',
+ uids: [{ id: 'sample-uid2-value' }]
+ },
+ {
+ source: 'puburl.com',
+ uids: [{ id: 'pubid1' }]
+ },
+ {
+ source: 'puburl2.com',
+ uids: [{ id: 'pubid2' }, { id: 'pubid2-123' }]
+ }
+ ]
};
let request = [];
@@ -38,8 +161,8 @@ describe('mediago:BidAdapterTests', function () {
spec.isBidRequestValid({
bidder: 'mediago',
params: {
- token: ['85a6b01e41ac36d49744fad726e3655d'],
- },
+ token: ['85a6b01e41ac36d49744fad726e3655d']
+ }
})
).to.equal(true);
});
@@ -50,11 +173,54 @@ describe('mediago:BidAdapterTests', function () {
expect(req_data.imp).to.have.lengthOf(1);
});
+ describe('mediago: buildRequests', function() {
+ describe('getPmgUID function', function() {
+ let sandbox;
+
+ beforeEach(() => {
+ sandbox = sinon.sandbox.create();
+ sandbox.stub(storage, 'getCookie');
+ sandbox.stub(storage, 'setCookie');
+ sandbox.stub(utils, 'generateUUID').returns('new-uuid');
+ sandbox.stub(storage, 'cookiesAreEnabled');
+ })
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should generate new UUID and set cookie if not exists', () => {
+ storage.cookiesAreEnabled.callsFake(() => true);
+ storage.getCookie.callsFake(() => null);
+ const uid = getPmgUID();
+ expect(uid).to.equal('new-uuid');
+ expect(storage.setCookie.calledOnce).to.be.true;
+ });
+
+ it('should return existing UUID from cookie', () => {
+ storage.cookiesAreEnabled.callsFake(() => true);
+ storage.getCookie.callsFake(() => 'existing-uuid');
+ const uid = getPmgUID();
+ expect(uid).to.equal('existing-uuid');
+ expect(storage.setCookie.called).to.be.false;
+ });
+
+ it('should not set new UUID when cookies are not enabled', () => {
+ storage.cookiesAreEnabled.callsFake(() => false);
+ storage.getCookie.callsFake(() => null);
+ getPmgUID();
+ expect(storage.setCookie.calledOnce).to.be.false;
+ });
+ })
+ });
+
it('mediago:validate_response_params', function () {
- let adm = "
";
+ let adm =
+ '
';
let temp = '%3Cscr';
temp += 'ipt%3E';
- temp += '!function()%7B%22use%20strict%22%3Bfunction%20f(t)%7Breturn(f%3D%22function%22%3D%3Dtypeof%20Symbol%26%26%22symbol%22%3D%3Dtypeof%20Symbol.iterator%3Ffunction(t)%7Breturn%20typeof%20t%7D%3Afunction(t)%7Breturn%20t%26%26%22function%22%3D%3Dtypeof%20Symbol%26%26t.constructor%3D%3D%3DSymbol%26%26t!%3D%3DSymbol.prototype%3F%22symbol%22%3Atypeof%20t%7D)(t)%7Dfunction%20l(t)%7Bvar%20e%3D0%3Carguments.length%26%26void%200!%3D%3Dt%3Ft%3A%7B%7D%3Btry%7Be.random_t%3D(new%20Date).getTime()%2Cg(function(t)%7Bvar%20e%3D1%3Carguments.length%26%26void%200!%3D%3Darguments%5B1%5D%3Farguments%5B1%5D%3A%22%22%3Bif(%22object%22!%3D%3Df(t))return%20e%3Bvar%20n%3Dfunction(t)%7Bfor(var%20e%2Cn%3D%5B%5D%2Co%3D0%2Ci%3DObject.keys(t)%3Bo%3Ci.length%3Bo%2B%2B)e%3Di%5Bo%5D%2Cn.push(%22%22.concat(e%2C%22%3D%22).concat(t%5Be%5D))%3Breturn%20n%7D(t).join(%22%26%22)%2Co%3De.indexOf(%22%23%22)%2Ci%3De%2Ct%3D%22%22%3Breturn-1!%3D%3Do%26%26(i%3De.slice(0%2Co)%2Ct%3De.slice(o))%2Cn%26%26(i%26%26-1!%3D%3Di.indexOf(%22%3F%22)%3Fi%2B%3D%22%26%22%2Bn%3Ai%2B%3D%22%3F%22%2Bn)%2Ci%2Bt%7D(e%2C%22https%3A%2F%2Ftrace.mediago.io%2Fapi%2Flog%2Ftrack%22))%7Dcatch(t)%7B%7D%7Dfunction%20g(t%2Ce%2Cn)%7B(t%3Dt%3Ft.split(%22%3B%3B%3B%22)%3A%5B%5D).map(function(t)%7Btry%7B0%3C%3Dt.indexOf(%22%2Fapi%2Fbidder%2Ftrack%22)%26%26n%26%26(t%2B%3D%22%26inIframe%3D%22.concat(!(!self.frameElement%7C%7C%22IFRAME%22!%3Dself.frameElement.tagName)%7C%7Cwindow.frames.length!%3Dparent.frames.length%7C%7Cself!%3Dtop)%2Ct%2B%3D%22%26pos_x%3D%22.concat(n.left%2C%22%26pos_y%3D%22).concat(n.top%2C%22%26page_w%3D%22).concat(n.page_width%2C%22%26page_h%3D%22).concat(n.page_height))%7Dcatch(t)%7Bl(%7Btn%3As%2Cwinloss%3A1%2Cfe%3A2%2Cpos_err_c%3A1002%2Cpos_err_m%3At.toString()%7D)%7Dvar%20e%3Dnew%20Image%3Be.src%3Dt%2Ce.style.display%3D%22none%22%2Ce.style.visibility%3D%22hidden%22%2Ce.width%3D0%2Ce.height%3D0%2Cdocument.body.appendChild(e)%7D)%7Dvar%20d%3D%5B%22https%3A%2F%2Ftrace.mediago.io%2Fapi%2Fbidder%2Ftrack%3Ftn%3D39934c2bda4debbe4c680be1dd02f5d3%26price%3DdjUJcggeuWWfbm28q4WXHdgMFkO28DrGw49FnubQ0Bk%26evt%3D101%26rid%3D6e28cfaf115a354ea1ad8e1304d6d7b8%26campaignid%3D1339145%26impid%3D44-300x250-1%26offerid%3D24054386%26test%3D0%26time%3D1660789795%26cp%3DjZDh1xu6_QqJLlKVtCkiHIP_TER6gL9jeTrlHCBoxOM%26acid%3D599%26trackingid%3D99afea272c2b0e8626489674ddb7a0bb%26uid%3Da865b9ae-fa9e-4c09-8204-2db99ac7c8f7%26bm%3D2%26la%3Den%26cn%3Dus%26cid%3D3998296%26info%3DSi3oM-qfCbw2iZRYs01BkUWyH6c5CQWHrA8CQLE0VHcXAcf4ljY9dyLzQ4vAlTWd6-j_ou4ySor3e70Ll7wlKiiauQKaUkZqNoTizHm73C4FK8DYJSTP3VkhJV8RzrYk%26sid%3D128__110__1__12__28__38__163__96__58__24__47__99%26sp%3DdjUJcggeuWWfbm28q4WXHdgMFkO28DrGw49FnubQ0Bk%26scp%3DzK0DRYY1UV-syqSpmcMYBpOebtoQJV9ZEJT0JFqbTQg%26acu%3DUSD%26scu%3DUSD%26sgcp%3DzK0DRYY1UV-syqSpmcMYBpOebtoQJV9ZEJT0JFqbTQg%26gprice%3DdjUJcggeuWWfbm28q4WXHdgMFkO28DrGw49FnubQ0Bk%26gcp%3DzK0DRYY1UV-syqSpmcMYBpOebtoQJV9ZEJT0JFqbTQg%26ah%3D%26de%3Dwjh.popin.cc%26iv%3D0%22%2C%22%24%7BITRACKER2%7D%22%2C%22%24%7BITRACKER3%7D%22%2C%22%24%7BITRACKER4%7D%22%2C%22%24%7BITRACKER5%7D%22%2C%22%24%7BITRACKER6%7D%22%5D%2Cp%3D%5B%22https%3A%2F%2Ftrace.mediago.io%2Fapi%2Fbidder%2Ftrack%3Ftn%3D39934c2bda4debbe4c680be1dd02f5d3%26price%3DdjUJcggeuWWfbm28q4WXHdgMFkO28DrGw49FnubQ0Bk%26evt%3D104%26rid%3D6e28cfaf115a354ea1ad8e1304d6d7b8%26campaignid%3D1339145%26impid%3D44-300x250-1%26offerid%3D24054386%26test%3D0%26time%3D1660789795%26cp%3DjZDh1xu6_QqJLlKVtCkiHIP_TER6gL9jeTrlHCBoxOM%26acid%3D599%26trackingid%3D99afea272c2b0e8626489674ddb7a0bb%26uid%3Da865b9ae-fa9e-4c09-8204-2db99ac7c8f7%26sid%3D128__110__1__12__28__38__163__96__58__24__47__99%26format%3D%26crid%3Dff32b6f9b3bbc45c00b78b6674a2952e%26bm%3D2%26la%3Den%26cn%3Dus%26cid%3D3998296%26info%3DSi3oM-qfCbw2iZRYs01BkUWyH6c5CQWHrA8CQLE0VHcXAcf4ljY9dyLzQ4vAlTWd6-j_ou4ySor3e70Ll7wlKiiauQKaUkZqNoTizHm73C4FK8DYJSTP3VkhJV8RzrYk%26sp%3DdjUJcggeuWWfbm28q4WXHdgMFkO28DrGw49FnubQ0Bk%26scp%3DzK0DRYY1UV-syqSpmcMYBpOebtoQJV9ZEJT0JFqbTQg%26acu%3DUSD%26scu%3DUSD%26sgcp%3DzK0DRYY1UV-syqSpmcMYBpOebtoQJV9ZEJT0JFqbTQg%26gprice%3DdjUJcggeuWWfbm28q4WXHdgMFkO28DrGw49FnubQ0Bk%26gcp%3DzK0DRYY1UV-syqSpmcMYBpOebtoQJV9ZEJT0JFqbTQg%26ah%3D%26de%3Dwjh.popin.cc%26iv%3D0%22%2C%22%24%7BVTRACKER2%7D%22%2C%22%24%7BVTRACKER3%7D%22%2C%22%24%7BVTRACKER4%7D%22%2C%22%24%7BVTRACKER5%7D%22%2C%22%24%7BVTRACKER6%7D%22%5D%2Cs%3D%22f9f2b1ef23fe2759c2cad0953029a94b%22%2Cn%3Ddocument.getElementById(%22mgcontainer-99afea272c2b0e8626489674ddb7a0bb%22)%3Bn%26%26function()%7Bvar%20a%3Dn.getElementsByClassName(%22mediago-placement-track%22)%3Bif(a%26%26a.length)%7Bvar%20t%2Ce%3Dfunction(t)%7Bvar%20e%2Cn%2Co%2Ci%2Cc%2Cr%3B%22object%22%3D%3D%3Df(r%3Da%5Bt%5D)%26%26(e%3Dfunction(t)%7Btry%7Bvar%20e%3Dt.getBoundingClientRect()%2Cn%3De%26%26e.top%7C%7C-1%2Co%3De%26%26e.left%7C%7C-1%2Ci%3Ddocument.body.scrollWidth%7C%7C-1%2Ce%3Ddocument.body.scrollHeight%7C%7C-1%3Breturn%7Btop%3An.toFixed(0)%2Cleft%3Ao.toFixed(0)%2Cpage_width%3Ai%2Cpage_height%3Ae%7D%7Dcatch(o)%7Breturn%20l(%7Btn%3As%2Cwinloss%3A1%2Cfe%3A2%2Cpos_err_c%3A1001%2Cpos_err_m%3Ao.toString()%7D)%2C%7Btop%3A%22-1%22%2Cleft%3A%22-1%22%2Cpage_width%3A%22-1%22%2Cpage_height%3A%22-1%22%7D%7D%7D(r)%2C(n%3Dd%5Bt%5D)%26%26g(n%2C0%2Ce)%2Co%3Dp%5Bt%5D%2Ci%3D!1%2C(c%3Dfunction()%7BsetTimeout(function()%7Bvar%20t%2Ce%3B!i%26%26(t%3Dr%2Ce%3Dwindow.innerHeight%7C%7Cdocument.documentElement.clientHeight%7C%7Cdocument.body.clientHeight%2C(t.getBoundingClientRect()%26%26t.getBoundingClientRect().top)%3C%3De-.75*(t.offsetHeight%7C%7Ct.clientHeight))%3F(i%3D!0%2Co%26%26g(o))%3Ac()%7D%2C500)%7D)())%7D%3Bfor(t%20in%20a)e(t)%7D%7D()%7D()';
+ temp +=
+ '!function()%7B%22use%20strict%22%3Bfunction%20f(t)%7Breturn(f%3D%22function%22%3D%3Dtypeof%20Symbol%26%26%22symbol%22%3D%3Dtypeof%20Symbol.iterator%3Ffunction(t)%7Breturn%20typeof%20t%7D%3Afunction(t)%7Breturn%20t%26%26%22function%22%3D%3Dtypeof%20Symbol%26%26t.constructor%3D%3D%3DSymbol%26%26t!%3D%3DSymbol.prototype%3F%22symbol%22%3Atypeof%20t%7D)(t)%7Dfunction%20l(t)%7Bvar%20e%3D0%3Carguments.length%26%26void%200!%3D%3Dt%3Ft%3A%7B%7D%3Btry%7Be.random_t%3D(new%20Date).getTime()%2Cg(function(t)%7Bvar%20e%3D1%3Carguments.length%26%26void%200!%3D%3Darguments%5B1%5D%3Farguments%5B1%5D%3A%22%22%3Bif(%22object%22!%3D%3Df(t))return%20e%3Bvar%20n%3Dfunction(t)%7Bfor(var%20e%2Cn%3D%5B%5D%2Co%3D0%2Ci%3DObject.keys(t)%3Bo%3Ci.length%3Bo%2B%2B)e%3Di%5Bo%5D%2Cn.push(%22%22.concat(e%2C%22%3D%22).concat(t%5Be%5D))%3Breturn%20n%7D(t).join(%22%26%22)%2Co%3De.indexOf(%22%23%22)%2Ci%3De%2Ct%3D%22%22%3Breturn-1!%3D%3Do%26%26(i%3De.slice(0%2Co)%2Ct%3De.slice(o))%2Cn%26%26(i%26%26-1!%3D%3Di.indexOf(%22%3F%22)%3Fi%2B%3D%22%26%22%2Bn%3Ai%2B%3D%22%3F%22%2Bn)%2Ci%2Bt%7D(e%2C%22https%3A%2F%2Ftrace.mediago.io%2Fapi%2Flog%2Ftrack%22))%7Dcatch(t)%7B%7D%7Dfunction%20g(t%2Ce%2Cn)%7B(t%3Dt%3Ft.split(%22%3B%3B%3B%22)%3A%5B%5D).map(function(t)%7Btry%7B0%3C%3Dt.indexOf(%22%2Fapi%2Fbidder%2Ftrack%22)%26%26n%26%26(t%2B%3D%22%26inIframe%3D%22.concat(!(!self.frameElement%7C%7C%22IFRAME%22!%3Dself.frameElement.tagName)%7C%7Cwindow.frames.length!%3Dparent.frames.length%7C%7Cself!%3Dtop)%2Ct%2B%3D%22%26pos_x%3D%22.concat(n.left%2C%22%26pos_y%3D%22).concat(n.top%2C%22%26page_w%3D%22).concat(n.page_width%2C%22%26page_h%3D%22).concat(n.page_height))%7Dcatch(t)%7Bl(%7Btn%3As%2Cwinloss%3A1%2Cfe%3A2%2Cpos_err_c%3A1002%2Cpos_err_m%3At.toString()%7D)%7Dvar%20e%3Dnew%20Image%3Be.src%3Dt%2Ce.style.display%3D%22none%22%2Ce.style.visibility%3D%22hidden%22%2Ce.width%3D0%2Ce.height%3D0%2Cdocument.body.appendChild(e)%7D)%7Dvar%20d%3D%5B%22https%3A%2F%2Ftrace.mediago.io%2Fapi%2Fbidder%2Ftrack%3Ftn%3D39934c2bda4debbe4c680be1dd02f5d3%26price%3DdjUJcggeuWWfbm28q4WXHdgMFkO28DrGw49FnubQ0Bk%26evt%3D101%26rid%3D6e28cfaf115a354ea1ad8e1304d6d7b8%26campaignid%3D1339145%26impid%3D44-300x250-1%26offerid%3D24054386%26test%3D0%26time%3D1660789795%26cp%3DjZDh1xu6_QqJLlKVtCkiHIP_TER6gL9jeTrlHCBoxOM%26acid%3D599%26trackingid%3D99afea272c2b0e8626489674ddb7a0bb%26uid%3Da865b9ae-fa9e-4c09-8204-2db99ac7c8f7%26bm%3D2%26la%3Den%26cn%3Dus%26cid%3D3998296%26info%3DSi3oM-qfCbw2iZRYs01BkUWyH6c5CQWHrA8CQLE0VHcXAcf4ljY9dyLzQ4vAlTWd6-j_ou4ySor3e70Ll7wlKiiauQKaUkZqNoTizHm73C4FK8DYJSTP3VkhJV8RzrYk%26sid%3D128__110__1__12__28__38__163__96__58__24__47__99%26sp%3DdjUJcggeuWWfbm28q4WXHdgMFkO28DrGw49FnubQ0Bk%26scp%3DzK0DRYY1UV-syqSpmcMYBpOebtoQJV9ZEJT0JFqbTQg%26acu%3DUSD%26scu%3DUSD%26sgcp%3DzK0DRYY1UV-syqSpmcMYBpOebtoQJV9ZEJT0JFqbTQg%26gprice%3DdjUJcggeuWWfbm28q4WXHdgMFkO28DrGw49FnubQ0Bk%26gcp%3DzK0DRYY1UV-syqSpmcMYBpOebtoQJV9ZEJT0JFqbTQg%26ah%3D%26de%3Dwjh.popin.cc%26iv%3D0%22%2C%22%24%7BITRACKER2%7D%22%2C%22%24%7BITRACKER3%7D%22%2C%22%24%7BITRACKER4%7D%22%2C%22%24%7BITRACKER5%7D%22%2C%22%24%7BITRACKER6%7D%22%5D%2Cp%3D%5B%22https%3A%2F%2Ftrace.mediago.io%2Fapi%2Fbidder%2Ftrack%3Ftn%3D39934c2bda4debbe4c680be1dd02f5d3%26price%3DdjUJcggeuWWfbm28q4WXHdgMFkO28DrGw49FnubQ0Bk%26evt%3D104%26rid%3D6e28cfaf115a354ea1ad8e1304d6d7b8%26campaignid%3D1339145%26impid%3D44-300x250-1%26offerid%3D24054386%26test%3D0%26time%3D1660789795%26cp%3DjZDh1xu6_QqJLlKVtCkiHIP_TER6gL9jeTrlHCBoxOM%26acid%3D599%26trackingid%3D99afea272c2b0e8626489674ddb7a0bb%26uid%3Da865b9ae-fa9e-4c09-8204-2db99ac7c8f7%26sid%3D128__110__1__12__28__38__163__96__58__24__47__99%26format%3D%26crid%3Dff32b6f9b3bbc45c00b78b6674a2952e%26bm%3D2%26la%3Den%26cn%3Dus%26cid%3D3998296%26info%3DSi3oM-qfCbw2iZRYs01BkUWyH6c5CQWHrA8CQLE0VHcXAcf4ljY9dyLzQ4vAlTWd6-j_ou4ySor3e70Ll7wlKiiauQKaUkZqNoTizHm73C4FK8DYJSTP3VkhJV8RzrYk%26sp%3DdjUJcggeuWWfbm28q4WXHdgMFkO28DrGw49FnubQ0Bk%26scp%3DzK0DRYY1UV-syqSpmcMYBpOebtoQJV9ZEJT0JFqbTQg%26acu%3DUSD%26scu%3DUSD%26sgcp%3DzK0DRYY1UV-syqSpmcMYBpOebtoQJV9ZEJT0JFqbTQg%26gprice%3DdjUJcggeuWWfbm28q4WXHdgMFkO28DrGw49FnubQ0Bk%26gcp%3DzK0DRYY1UV-syqSpmcMYBpOebtoQJV9ZEJT0JFqbTQg%26ah%3D%26de%3Dwjh.popin.cc%26iv%3D0%22%2C%22%24%7BVTRACKER2%7D%22%2C%22%24%7BVTRACKER3%7D%22%2C%22%24%7BVTRACKER4%7D%22%2C%22%24%7BVTRACKER5%7D%22%2C%22%24%7BVTRACKER6%7D%22%5D%2Cs%3D%22f9f2b1ef23fe2759c2cad0953029a94b%22%2Cn%3Ddocument.getElementById(%22mgcontainer-99afea272c2b0e8626489674ddb7a0bb%22)%3Bn%26%26function()%7Bvar%20a%3Dn.getElementsByClassName(%22mediago-placement-track%22)%3Bif(a%26%26a.length)%7Bvar%20t%2Ce%3Dfunction(t)%7Bvar%20e%2Cn%2Co%2Ci%2Cc%2Cr%3B%22object%22%3D%3D%3Df(r%3Da%5Bt%5D)%26%26(e%3Dfunction(t)%7Btry%7Bvar%20e%3Dt.getBoundingClientRect()%2Cn%3De%26%26e.top%7C%7C-1%2Co%3De%26%26e.left%7C%7C-1%2Ci%3Ddocument.body.scrollWidth%7C%7C-1%2Ce%3Ddocument.body.scrollHeight%7C%7C-1%3Breturn%7Btop%3An.toFixed(0)%2Cleft%3Ao.toFixed(0)%2Cpage_width%3Ai%2Cpage_height%3Ae%7D%7Dcatch(o)%7Breturn%20l(%7Btn%3As%2Cwinloss%3A1%2Cfe%3A2%2Cpos_err_c%3A1001%2Cpos_err_m%3Ao.toString()%7D)%2C%7Btop%3A%22-1%22%2Cleft%3A%22-1%22%2Cpage_width%3A%22-1%22%2Cpage_height%3A%22-1%22%7D%7D%7D(r)%2C(n%3Dd%5Bt%5D)%26%26g(n%2C0%2Ce)%2Co%3Dp%5Bt%5D%2Ci%3D!1%2C(c%3Dfunction()%7BsetTimeout(function()%7Bvar%20t%2Ce%3B!i%26%26(t%3Dr%2Ce%3Dwindow.innerHeight%7C%7Cdocument.documentElement.clientHeight%7C%7Cdocument.body.clientHeight%2C(t.getBoundingClientRect()%26%26t.getBoundingClientRect().top)%3C%3De-.75*(t.offsetHeight%7C%7Ct.clientHeight))%3F(i%3D!0%2Co%26%26g(o))%3Ac()%7D%2C500)%7D)())%7D%3Bfor(t%20in%20a)e(t)%7D%7D()%7D()';
temp += '%3B%3C%2Fscri';
temp += 'pt%3E';
adm += decodeURIComponent(temp);
@@ -72,13 +238,13 @@ describe('mediago:BidAdapterTests', function () {
cid: '1339145',
crid: 'ff32b6f9b3bbc45c00b78b6674a2952e',
w: 300,
- h: 250,
- },
- ],
- },
+ h: 250
+ }
+ ]
+ }
],
- cur: 'USD',
- },
+ cur: 'USD'
+ }
};
let bids = spec.interpretResponse(serverResponse);
@@ -94,4 +260,324 @@ describe('mediago:BidAdapterTests', function () {
expect(bid.height).to.equal(250);
expect(bid.currency).to.equal('USD');
});
+
+ describe('mediago: getUserSyncs', function() {
+ const COOKY_SYNC_IFRAME_URL = 'https://cdn.mediago.io/js/cookieSync.html';
+ const IFRAME_ENABLED = {
+ iframeEnabled: true,
+ pixelEnabled: false,
+ };
+ const IFRAME_DISABLED = {
+ iframeEnabled: false,
+ pixelEnabled: false,
+ };
+ const GDPR_CONSENT = {
+ consentString: 'gdprConsentString',
+ gdprApplies: true
+ };
+ const USP_CONSENT = {
+ consentString: 'uspConsentString'
+ }
+
+ let syncParamUrl = `dm=${encodeURIComponent(location.origin || `https://${location.host}`)}`;
+ syncParamUrl += '&gdpr=1&gdpr_consent=gdprConsentString&ccpa_consent=uspConsentString';
+ const expectedIframeSyncs = [
+ {
+ type: 'iframe',
+ url: `${COOKY_SYNC_IFRAME_URL}?${syncParamUrl}`
+ }
+ ];
+
+ it('should return nothing if iframe is disabled', () => {
+ const userSyncs = spec.getUserSyncs(IFRAME_DISABLED, undefined, GDPR_CONSENT, USP_CONSENT, undefined);
+ expect(userSyncs).to.be.undefined;
+ });
+
+ it('should do userSyncs if iframe is enabled', () => {
+ const userSyncs = spec.getUserSyncs(IFRAME_ENABLED, undefined, GDPR_CONSENT, USP_CONSENT, undefined);
+ expect(userSyncs).to.deep.equal(expectedIframeSyncs);
+ });
+ });
+});
+
+describe('mediago Bid Adapter Tests', function () {
+ describe('buildRequests', () => {
+ describe('getPageTitle function', function() {
+ let sandbox;
+
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should return the top document title if available', function() {
+ const fakeTopDocument = {
+ title: 'Top Document Title',
+ querySelector: () => ({ content: 'Top Document Title test' })
+ };
+ const fakeTopWindow = {
+ document: fakeTopDocument
+ };
+ const result = getPageTitle({ top: fakeTopWindow });
+ expect(result).to.equal('Top Document Title');
+ });
+
+ it('should return the content of top og:title meta tag if title is empty', function() {
+ const ogTitleContent = 'Top OG Title Content';
+ const fakeTopWindow = {
+ document: {
+ title: '',
+ querySelector: sandbox.stub().withArgs('meta[property="og:title"]').returns({ content: ogTitleContent })
+ }
+ };
+
+ const result = getPageTitle({ top: fakeTopWindow });
+ expect(result).to.equal(ogTitleContent);
+ });
+
+ it('should return the document title if no og:title meta tag is present', function() {
+ document.title = 'Test Page Title';
+ sandbox.stub(document, 'querySelector').withArgs('meta[property="og:title"]').returns(null);
+
+ const result = getPageTitle({ top: undefined });
+ expect(result).to.equal('Test Page Title');
+ });
+
+ it('should return the content of og:title meta tag if present', function() {
+ document.title = '';
+ const ogTitleContent = 'Top OG Title Content';
+ sandbox.stub(document, 'querySelector').withArgs('meta[property="og:title"]').returns({ content: ogTitleContent });
+ const result = getPageTitle({ top: undefined });
+ expect(result).to.equal(ogTitleContent);
+ });
+
+ it('should return an empty string if no title or og:title meta tag is found', function() {
+ document.title = '';
+ sandbox.stub(document, 'querySelector').withArgs('meta[property="og:title"]').returns(null);
+ const result = getPageTitle({ top: undefined });
+ expect(result).to.equal('');
+ });
+
+ it('should handle exceptions when accessing top.document and fallback to current document', function() {
+ const fakeWindow = {
+ get top() {
+ throw new Error('Access denied');
+ }
+ };
+ const ogTitleContent = 'Current OG Title Content';
+ document.title = 'Current Document Title';
+ sandbox.stub(document, 'querySelector').withArgs('meta[property="og:title"]').returns({ content: ogTitleContent });
+ const result = getPageTitle(fakeWindow);
+ expect(result).to.equal('Current Document Title');
+ });
+ });
+
+ describe('getPageDescription function', function() {
+ let sandbox;
+
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should return the top document description if available', function() {
+ const descriptionContent = 'Top Document Description';
+ const fakeTopDocument = {
+ querySelector: sandbox.stub().withArgs('meta[name="description"]').returns({ content: descriptionContent })
+ };
+ const fakeTopWindow = { document: fakeTopDocument };
+ const result = getPageDescription({ top: fakeTopWindow });
+ expect(result).to.equal(descriptionContent);
+ });
+
+ it('should return the top document og:description if description is not present', function() {
+ const ogDescriptionContent = 'Top OG Description';
+ const fakeTopDocument = {
+ querySelector: sandbox.stub().withArgs('meta[property="og:description"]').returns({ content: ogDescriptionContent })
+ };
+ const fakeTopWindow = { document: fakeTopDocument };
+ const result = getPageDescription({ top: fakeTopWindow });
+ expect(result).to.equal(ogDescriptionContent);
+ });
+
+ it('should return the current document description if top document is not accessible', function() {
+ const descriptionContent = 'Current Document Description';
+ sandbox.stub(document, 'querySelector')
+ .withArgs('meta[name="description"]').returns({ content: descriptionContent })
+ const fakeWindow = {
+ get top() {
+ throw new Error('Access denied');
+ }
+ };
+ const result = getPageDescription(fakeWindow);
+ expect(result).to.equal(descriptionContent);
+ });
+
+ it('should return the current document og:description if description is not present and top document is not accessible', function() {
+ const ogDescriptionContent = 'Current OG Description';
+ sandbox.stub(document, 'querySelector')
+ .withArgs('meta[property="og:description"]').returns({ content: ogDescriptionContent });
+
+ const fakeWindow = {
+ get top() {
+ throw new Error('Access denied');
+ }
+ };
+ const result = getPageDescription(fakeWindow);
+ expect(result).to.equal(ogDescriptionContent);
+ });
+ });
+
+ describe('getPageKeywords function', function() {
+ let sandbox;
+
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should return the top document keywords if available', function() {
+ const keywordsContent = 'keyword1, keyword2, keyword3';
+ const fakeTopDocument = {
+ querySelector: sandbox.stub()
+ .withArgs('meta[name="keywords"]').returns({ content: keywordsContent })
+ };
+ const fakeTopWindow = { document: fakeTopDocument };
+
+ const result = getPageKeywords({ top: fakeTopWindow });
+ expect(result).to.equal(keywordsContent);
+ });
+
+ it('should return the current document keywords if top document is not accessible', function() {
+ const keywordsContent = 'keyword1, keyword2, keyword3';
+ sandbox.stub(document, 'querySelector')
+ .withArgs('meta[name="keywords"]').returns({ content: keywordsContent });
+
+ // æ¨ĄæéĄļåąįĒåŖčŽŋéŽåŧ常
+ const fakeWindow = {
+ get top() {
+ throw new Error('Access denied');
+ }
+ };
+
+ const result = getPageKeywords(fakeWindow);
+ expect(result).to.equal(keywordsContent);
+ });
+
+ it('should return an empty string if no keywords meta tag is found', function() {
+ sandbox.stub(document, 'querySelector').withArgs('meta[name="keywords"]').returns(null);
+
+ const result = getPageKeywords();
+ expect(result).to.equal('');
+ });
+ });
+ describe('getConnectionDownLink function', function() {
+ let sandbox;
+
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should return the downlink value as a string if available', function() {
+ const downlinkValue = 2.5;
+ const fakeNavigator = {
+ connection: {
+ downlink: downlinkValue
+ }
+ };
+
+ const result = getConnectionDownLink({ navigator: fakeNavigator });
+ expect(result).to.equal(downlinkValue.toString());
+ });
+
+ it('should return undefined if downlink is not available', function() {
+ const fakeNavigator = {
+ connection: {}
+ };
+
+ const result = getConnectionDownLink({ navigator: fakeNavigator });
+ expect(result).to.be.undefined;
+ });
+
+ it('should return undefined if connection is not available', function() {
+ const fakeNavigator = {};
+
+ const result = getConnectionDownLink({ navigator: fakeNavigator });
+ expect(result).to.be.undefined;
+ });
+
+ it('should handle cases where navigator is not defined', function() {
+ const result = getConnectionDownLink({});
+ expect(result).to.be.undefined;
+ });
+ });
+
+ describe('getUserSyncs with message event listener', function() {
+ function messageHandler(event) {
+ if (!event.data || event.origin !== THIRD_PARTY_COOKIE_ORIGIN) {
+ return;
+ }
+
+ window.removeEventListener('message', messageHandler, true);
+ event.stopImmediatePropagation();
+
+ const response = event.data;
+ if (!response.optout && response.mguid) {
+ storage.setCookie(COOKIE_KEY_MGUID, response.mguid, getCurrentTimeToUTCString());
+ }
+ }
+
+ let sandbox;
+
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+ sandbox.stub(storage, 'setCookie');
+ sandbox.stub(window, 'removeEventListener');
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('should set a cookie when a valid message is received', () => {
+ const fakeEvent = {
+ data: { optout: '', mguid: '12345' },
+ origin: THIRD_PARTY_COOKIE_ORIGIN,
+ stopImmediatePropagation: sinon.spy()
+ };
+
+ messageHandler(fakeEvent);
+
+ expect(fakeEvent.stopImmediatePropagation.calledOnce).to.be.true;
+ expect(window.removeEventListener.calledWith('message', messageHandler, true)).to.be.true;
+ expect(storage.setCookie.calledWith(COOKIE_KEY_MGUID, '12345', sinon.match.string)).to.be.true;
+ });
+ it('should not do anything when an invalid message is received', () => {
+ const fakeEvent = {
+ data: null,
+ origin: 'http://invalid-origin.com',
+ stopImmediatePropagation: sinon.spy()
+ };
+
+ messageHandler(fakeEvent);
+
+ expect(fakeEvent.stopImmediatePropagation.notCalled).to.be.true;
+ expect(window.removeEventListener.notCalled).to.be.true;
+ expect(storage.setCookie.notCalled).to.be.true;
+ });
+ });
+ });
});
diff --git a/test/spec/modules/mediaimpactBidAdapter_spec.js b/test/spec/modules/mediaimpactBidAdapter_spec.js
new file mode 100644
index 00000000000..3d706e59c3f
--- /dev/null
+++ b/test/spec/modules/mediaimpactBidAdapter_spec.js
@@ -0,0 +1,336 @@
+import {expect} from 'chai';
+import {spec, ENDPOINT_PROTOCOL, ENDPOINT_DOMAIN, ENDPOINT_PATH} from 'modules/mediaimpactBidAdapter.js';
+import {newBidder} from 'src/adapters/bidderFactory.js';
+
+const BIDDER_CODE = 'mediaimpact';
+
+describe('MediaimpactAdapter', function () {
+ const adapter = newBidder(spec);
+
+ describe('inherited functions', function () {
+ it('exists and is a function', function () {
+ expect(adapter.callBids).to.be.exist.and.to.be.a('function');
+ });
+ });
+
+ describe('isBidRequestValid', function () {
+ it('should return true when required params found', function () {
+ let validRequest = {
+ 'params': {
+ 'unitId': 123
+ }
+ };
+ expect(spec.isBidRequestValid(validRequest)).to.equal(true);
+ });
+
+ it('should return true when required params is srting', function () {
+ let validRequest = {
+ 'params': {
+ 'unitId': '456'
+ }
+ };
+ expect(spec.isBidRequestValid(validRequest)).to.equal(true);
+ });
+
+ it('should return false when required params are not passed', function () {
+ let validRequest = {
+ 'params': {
+ 'unknownId': 123
+ }
+ };
+ expect(spec.isBidRequestValid(validRequest)).to.equal(false);
+ });
+
+ it('should return false when required params is 0', function () {
+ let validRequest = {
+ 'params': {
+ 'unitId': 0
+ }
+ };
+ expect(spec.isBidRequestValid(validRequest)).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', function () {
+ let validEndpoint = ENDPOINT_PROTOCOL + '://' + ENDPOINT_DOMAIN + ENDPOINT_PATH + '?tag=123,456&partner=777&sizes=300x250|300x600,728x90,300x250&referer=https%3A%2F%2Ftest.domain';
+
+ let validRequest = [
+ {
+ 'bidder': BIDDER_CODE,
+ 'params': {
+ 'unitId': 123
+ },
+ 'adUnitCode': 'adunit-code-1',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '30b31c1838de1e'
+ },
+ {
+ 'bidder': BIDDER_CODE,
+ 'params': {
+ 'unitId': '456'
+ },
+ 'adUnitCode': 'adunit-code-2',
+ 'sizes': [[728, 90]],
+ 'bidId': '22aidtbx5eabd9'
+ },
+ {
+ 'bidder': BIDDER_CODE,
+ 'params': {
+ 'partnerId': 777
+ },
+ 'adUnitCode': 'partner-code-3',
+ 'sizes': [[300, 250]],
+ 'bidId': '5d4531d5a6c013'
+ }
+ ];
+
+ let bidderRequest = {
+ refererInfo: {
+ page: 'https://test.domain'
+ }
+ };
+
+ it('bidRequest HTTP method', function () {
+ const request = spec.buildRequests(validRequest, bidderRequest);
+ expect(request.method).to.equal('POST');
+ });
+
+ it('bidRequest url', function () {
+ const request = spec.buildRequests(validRequest, bidderRequest);
+ expect(request.url).to.equal(validEndpoint);
+ });
+
+ it('bidRequest data', function () {
+ const request = spec.buildRequests(validRequest, bidderRequest);
+ const payload = JSON.parse(request.data);
+ expect(payload[0].unitId).to.equal(123);
+ expect(payload[0].sizes).to.deep.equal([[300, 250], [300, 600]]);
+ expect(payload[0].bidId).to.equal('30b31c1838de1e');
+ expect(payload[1].unitId).to.equal(456);
+ expect(payload[1].sizes).to.deep.equal([[728, 90]]);
+ expect(payload[1].bidId).to.equal('22aidtbx5eabd9');
+ expect(payload[2].partnerId).to.equal(777);
+ expect(payload[2].sizes).to.deep.equal([[300, 250]]);
+ expect(payload[2].bidId).to.equal('5d4531d5a6c013');
+ });
+ });
+
+ describe('joinSizesToString', function () {
+ it('success convert sizes list to string', function () {
+ const sizesStr = spec.joinSizesToString([[300, 250], [300, 600]]);
+ expect(sizesStr).to.equal('300x250|300x600');
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const bidRequest = {
+ 'method': 'POST',
+ 'url': ENDPOINT_PROTOCOL + '://' + ENDPOINT_DOMAIN + ENDPOINT_PATH + '?tag=123,456&partner=777code=adunit-code-1,adunit-code-2,partner-code-3&bid=30b31c1838de1e,22aidtbx5eabd9,5d4531d5a6c013&sizes=300x250|300x600,728x90,300x250&referer=https%3A%2F%2Ftest.domain',
+ 'data': '[{"unitId": 13144370,"adUnitCode": "div-gpt-ad-1460505748561-0","sizes": [[300, 250], [300, 600]],"bidId": "2bdcb0b203c17d","referer": "https://test.domain/index.html"},' +
+ '{"unitId": 13144370,"adUnitCode":"div-gpt-ad-1460505748561-1","sizes": [[768, 90]],"bidId": "3dc6b8084f91a8","referer": "https://test.domain/index.html"},' +
+ '{"unitId": 0,"partnerId": 777,"adUnitCode":"div-gpt-ad-1460505748561-2","sizes": [[300, 250]],"bidId": "5d4531d5a6c013","referer": "https://test.domain/index.html"}]'
+ };
+
+ const bidResponse = {
+ body: {
+ 'div-gpt-ad-1460505748561-0':
+ {
+ 'ad': '
ad
',
+ 'width': 300,
+ 'height': 250,
+ 'creativeId': '8:123456',
+ 'adomain': [
+ 'test.domain'
+ ],
+ 'syncs': [
+ {'type': 'image', 'url': 'https://test.domain/tracker_1.gif'},
+ {'type': 'image', 'url': 'https://test.domain/tracker_2.gif'},
+ {'type': 'image', 'url': 'https://test.domain/tracker_3.gif'}
+ ],
+ 'winNotification': [
+ {
+ 'method': 'POST',
+ 'path': '/hb/bid_won?test=1',
+ 'data': {
+ 'ad': [
+ {'dsp': 8, 'id': 800008, 'cost': 1.0e-5, 'nurl': 'https://test.domain/'}
+ ],
+ 'unit_id': 1234,
+ 'site_id': 123
+ }
+ }
+ ],
+ 'cpm': 0.01,
+ 'currency': 'USD',
+ 'netRevenue': true
+ }
+ },
+ headers: {}
+ };
+
+ it('result is correct', function () {
+ const result = spec.interpretResponse(bidResponse, bidRequest);
+ expect(result[0].requestId).to.equal('2bdcb0b203c17d');
+ expect(result[0].cpm).to.equal(0.01);
+ expect(result[0].width).to.equal(300);
+ expect(result[0].height).to.equal(250);
+ expect(result[0].creativeId).to.equal('8:123456');
+ expect(result[0].currency).to.equal('USD');
+ expect(result[0].ttl).to.equal(60);
+ expect(result[0].meta.advertiserDomains).to.deep.equal(['test.domain']);
+ expect(result[0].winNotification[0]).to.deep.equal({'method': 'POST', 'path': '/hb/bid_won?test=1', 'data': {'ad': [{'dsp': 8, 'id': 800008, 'cost': 1.0e-5, 'nurl': 'https://test.domain/'}], 'unit_id': 1234, 'site_id': 123}});
+ });
+ });
+
+ describe('adResponse', function () {
+ const bid = {
+ 'unitId': 13144370,
+ 'adUnitCode': 'div-gpt-ad-1460505748561-0',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidId': '2bdcb0b203c17d',
+ 'referer': 'https://test.domain/index.html'
+ };
+ const ad = {
+ 'ad': '
ad
',
+ 'width': 300,
+ 'height': 250,
+ 'creativeId': '8:123456',
+ 'syncs': [],
+ 'winNotification': [],
+ 'cpm': 0.01,
+ 'currency': 'USD',
+ 'netRevenue': true,
+ 'adomain': [
+ 'test.domain'
+ ],
+ };
+
+ it('fill ad for response', function () {
+ const result = spec.adResponse(bid, ad);
+ expect(result.requestId).to.equal('2bdcb0b203c17d');
+ expect(result.cpm).to.equal(0.01);
+ expect(result.width).to.equal(300);
+ expect(result.height).to.equal(250);
+ expect(result.creativeId).to.equal('8:123456');
+ expect(result.currency).to.equal('USD');
+ expect(result.ttl).to.equal(60);
+ expect(result.meta.advertiserDomains).to.deep.equal(['test.domain']);
+ });
+ });
+
+ describe('onBidWon', function () {
+ const bid = {
+ winNotification: [
+ {
+ 'method': 'POST',
+ 'path': '/hb/bid_won?test=1',
+ 'data': {
+ 'ad': [
+ {'dsp': 8, 'id': 800008, 'cost': 0.01, 'nurl': 'http://test.domain/'}
+ ],
+ 'unit_id': 1234,
+ 'site_id': 123
+ }
+ }
+ ]
+ };
+
+ let ajaxStub;
+
+ beforeEach(() => {
+ ajaxStub = sinon.stub(spec, 'postRequest')
+ })
+
+ afterEach(() => {
+ ajaxStub.restore()
+ })
+
+ it('calls mediaimpact callback endpoint', () => {
+ const result = spec.onBidWon(bid);
+ expect(result).to.equal(true);
+ expect(ajaxStub.calledOnce).to.equal(true);
+ expect(ajaxStub.firstCall.args[0]).to.equal(ENDPOINT_PROTOCOL + '://' + ENDPOINT_DOMAIN + '/hb/bid_won?test=1');
+ expect(ajaxStub.firstCall.args[1]).to.deep.equal(JSON.stringify(bid.winNotification[0].data));
+ });
+ });
+
+ describe('getUserSyncs', function () {
+ const bidResponse = [{
+ body: {
+ 'div-gpt-ad-1460505748561-0':
+ {
+ 'ad': '
ad
',
+ 'width': 300,
+ 'height': 250,
+ 'creativeId': '8:123456',
+ 'adomain': [
+ 'test.domain'
+ ],
+ 'syncs': [
+ {'type': 'image', 'link': 'https://test.domain/tracker_1.gif'},
+ {'type': 'image', 'link': 'https://test.domain/tracker_2.gif'},
+ {'type': 'image', 'link': 'https://test.domain/tracker_3.gif'}
+ ],
+ 'winNotification': [
+ {
+ 'method': 'POST',
+ 'path': '/hb/bid_won?test=1',
+ 'data': {
+ 'ad': [
+ {'dsp': 8, 'id': 800008, 'cost': 1.0e-5, 'nurl': 'https://test.domain/'}
+ ],
+ 'unit_id': 1234,
+ 'site_id': 123
+ }
+ }
+ ],
+ 'cpm': 0.01,
+ 'currency': 'USD',
+ 'netRevenue': true
+ }
+ },
+ headers: {}
+ }];
+
+ it('should return nothing when sync is disabled', function () {
+ const syncOptions = {
+ 'iframeEnabled': false,
+ 'pixelEnabled': false
+ };
+
+ let syncs = spec.getUserSyncs(syncOptions);
+ expect(syncs).to.deep.equal([]);
+ });
+
+ it('should register image sync when only image is enabled where gdprConsent is undefined', function () {
+ const syncOptions = {
+ 'iframeEnabled': false,
+ 'pixelEnabled': true
+ };
+
+ const gdprConsent = undefined;
+ let syncs = spec.getUserSyncs(syncOptions, bidResponse, gdprConsent);
+ expect(syncs.length).to.equal(3);
+ expect(syncs[0].type).to.equal('image');
+ expect(syncs[0].url).to.equal('https://test.domain/tracker_1.gif');
+ });
+
+ it('should register image sync when only image is enabled where gdprConsent is defined', function () {
+ const syncOptions = {
+ 'iframeEnabled': false,
+ 'pixelEnabled': true
+ };
+ const gdprConsent = {
+ consentString: 'someString',
+ vendorData: {},
+ gdprApplies: true,
+ apiVersion: 2
+ };
+
+ let syncs = spec.getUserSyncs(syncOptions, bidResponse, gdprConsent);
+ expect(syncs.length).to.equal(3);
+ expect(syncs[0].type).to.equal('image');
+ expect(syncs[0].url).to.equal('https://test.domain/tracker_1.gif?gdpr=1&gdpr_consent=someString');
+ });
+ });
+});
diff --git a/test/spec/modules/mediasquareBidAdapter_spec.js b/test/spec/modules/mediasquareBidAdapter_spec.js
index 125d4bef02b..cdeae38aa19 100644
--- a/test/spec/modules/mediasquareBidAdapter_spec.js
+++ b/test/spec/modules/mediasquareBidAdapter_spec.js
@@ -101,10 +101,35 @@ describe('MediaSquare bid adapter tests', function () {
'adomain': ['test.com'],
'context': 'instream',
'increment': 1.0,
+ 'ova': 'cleared',
+ 'dsa': {
+ 'behalf': 'some-behalf',
+ 'paid': 'some-paid',
+ 'transparency': [{
+ 'domain': 'test.com',
+ 'dsaparams': [1, 2, 3]
+ }],
+ 'adrender': 1
+ }
}],
}};
const DEFAULT_OPTIONS = {
+ ortb2: {
+ regs: {
+ ext: {
+ dsa: {
+ dsarequired: '1',
+ pubrender: '2',
+ datatopub: '3',
+ transparency: [{
+ domain: 'test.com',
+ dsaparams: [1, 2, 3]
+ }]
+ }
+ }
+ }
+ },
gdprConsent: {
gdprApplies: true,
consentString: 'BOzZdA0OzZdA0AGABBENDJ-AAAAvh7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__79__3z3_9pxP78k89r7337Mw_v-_v-b7JCPN_Y3v-8Kg',
@@ -143,10 +168,12 @@ describe('MediaSquare bid adapter tests', function () {
expect(requestContent.codes[0]).to.have.property('mediatypes').exist;
expect(requestContent.codes[0]).to.have.property('floor').exist;
expect(requestContent.codes[0].floor).to.deep.equal({});
+ expect(requestContent).to.have.property('dsa');
const requestfloor = spec.buildRequests(FLOORS_PARAMS, DEFAULT_OPTIONS);
const responsefloor = JSON.parse(requestfloor.data);
expect(responsefloor.codes[0]).to.have.property('floor').exist;
expect(responsefloor.codes[0].floor).to.have.property('300x250').and.to.have.property('floor').and.to.equal(1);
+ expect(responsefloor.codes[0].floor).to.have.property('*');
});
it('Verify parse response', function () {
@@ -171,9 +198,11 @@ describe('MediaSquare bid adapter tests', function () {
expect(bid.mediasquare.increment).to.exist;
expect(bid.mediasquare.increment).to.equal(1.0);
expect(bid.mediasquare.code).to.equal([DEFAULT_PARAMS[0].params.owner, DEFAULT_PARAMS[0].params.code].join('/'));
+ expect(bid.mediasquare.ova).to.exist.and.to.equal('cleared');
expect(bid.meta).to.exist;
expect(bid.meta.advertiserDomains).to.exist;
expect(bid.meta.advertiserDomains).to.have.lengthOf(1);
+ expect(bid.meta.dsa).to.exist;
});
it('Verifies match', function () {
const request = spec.buildRequests(DEFAULT_PARAMS, DEFAULT_OPTIONS);
@@ -213,6 +242,7 @@ describe('MediaSquare bid adapter tests', function () {
let message = JSON.parse(server.requests[0].requestBody);
expect(message).to.have.property('increment').exist;
expect(message).to.have.property('increment').and.to.equal('1');
+ expect(message).to.have.property('ova').and.to.equal('cleared');
});
it('Verifies user sync without cookie in bid response', function () {
var syncs = spec.getUserSyncs({}, [BID_RESPONSE], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent);
diff --git a/test/spec/modules/mgidXBidAdapter_spec.js b/test/spec/modules/mgidXBidAdapter_spec.js
index 14619e9c0e1..e0b1e1a84e9 100644
--- a/test/spec/modules/mgidXBidAdapter_spec.js
+++ b/test/spec/modules/mgidXBidAdapter_spec.js
@@ -6,7 +6,6 @@ import { config } from '../../../src/config';
import { USERSYNC_DEFAULT_CONFIG } from '../../../src/userSync';
const bidder = 'mgidX'
-const adUrl = 'https://us-east-x.mgid.com/pbjs';
describe('MGIDXBidAdapter', function () {
const bids = [
@@ -19,6 +18,7 @@ describe('MGIDXBidAdapter', function () {
}
},
params: {
+ region: 'eu',
placementId: 'testBanner',
}
},
@@ -56,6 +56,7 @@ describe('MGIDXBidAdapter', function () {
}
},
params: {
+ region: 'eu',
placementId: 'testNative',
}
}
@@ -76,7 +77,10 @@ describe('MGIDXBidAdapter', function () {
const bidderRequest = {
uspConsent: '1---',
- gdprConsent: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw',
+ gdprConsent: {
+ consentString: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw',
+ vendorData: {}
+ },
refererInfo: {
referer: 'https://test.com'
}
@@ -105,8 +109,16 @@ describe('MGIDXBidAdapter', function () {
expect(serverRequest.method).to.equal('POST');
});
- it('Returns valid URL', function () {
- expect(serverRequest.url).to.equal(adUrl);
+ it('Returns valid EU URL', function () {
+ bids[0].params.region = 'eu';
+ serverRequest = spec.buildRequests(bids, bidderRequest);
+ expect(serverRequest.url).to.equal('https://eu.mgid.com/pbjs');
+ });
+
+ it('Returns valid EAST URL', function () {
+ bids[0].params.region = 'other';
+ serverRequest = spec.buildRequests(bids, bidderRequest);
+ expect(serverRequest.url).to.equal('https://us-east-x.mgid.com/pbjs');
});
it('Returns general data valid', function () {
@@ -131,7 +143,7 @@ describe('MGIDXBidAdapter', function () {
expect(data.host).to.be.a('string');
expect(data.page).to.be.a('string');
expect(data.coppa).to.be.a('number');
- expect(data.gdpr).to.be.a('string');
+ expect(data.gdpr).to.be.a('object');
expect(data.ccpa).to.be.a('string');
expect(data.tmax).to.be.a('number');
expect(data.placements).to.have.lengthOf(3);
@@ -172,8 +184,10 @@ describe('MGIDXBidAdapter', function () {
serverRequest = spec.buildRequests(bids, bidderRequest);
let data = serverRequest.data;
expect(data.gdpr).to.exist;
- expect(data.gdpr).to.be.a('string');
- expect(data.gdpr).to.equal(bidderRequest.gdprConsent);
+ expect(data.gdpr).to.be.a('object');
+ expect(data.gdpr).to.have.property('consentString');
+ expect(data.gdpr).to.not.have.property('vendorData');
+ expect(data.gdpr.consentString).to.equal(bidderRequest.gdprConsent.consentString);
expect(data.ccpa).to.not.exist;
delete bidderRequest.gdprConsent;
});
@@ -188,12 +202,6 @@ describe('MGIDXBidAdapter', function () {
expect(data.ccpa).to.equal(bidderRequest.uspConsent);
expect(data.gdpr).to.not.exist;
});
-
- it('Returns empty data if no valid requests are passed', function () {
- serverRequest = spec.buildRequests([], bidderRequest);
- let data = serverRequest.data;
- expect(data.placements).to.be.an('array').that.is.empty;
- });
});
describe('interpretResponse', function () {
diff --git a/test/spec/modules/microadBidAdapter_spec.js b/test/spec/modules/microadBidAdapter_spec.js
index bd6d04a6312..9eb36d2fa6c 100644
--- a/test/spec/modules/microadBidAdapter_spec.js
+++ b/test/spec/modules/microadBidAdapter_spec.js
@@ -382,6 +382,196 @@ describe('microadBidAdapter', () => {
})
});
})
+
+ describe('should send gpid', () => {
+ it('from gpid', () => {
+ const bidRequest = Object.assign({}, bidRequestTemplate, {
+ ortb2Imp: {
+ ext: {
+ tid: 'transaction-id',
+ gpid: '1111/2222',
+ data: {
+ pbadslot: '3333/4444'
+ }
+ }
+ }
+ });
+ const requests = spec.buildRequests([bidRequest], bidderRequest)
+ requests.forEach(request => {
+ expect(request.data).to.deep.equal(
+ Object.assign({}, expectedResultTemplate, {
+ cbt: request.data.cbt,
+ gpid: '1111/2222',
+ pbadslot: '3333/4444'
+ })
+ );
+ })
+ })
+
+ it('from pbadslot', () => {
+ const bidRequest = Object.assign({}, bidRequestTemplate, {
+ ortb2Imp: {
+ ext: {
+ tid: 'transaction-id',
+ data: {
+ pbadslot: '3333/4444'
+ }
+ }
+ }
+ });
+ const requests = spec.buildRequests([bidRequest], bidderRequest)
+ requests.forEach(request => {
+ expect(request.data).to.deep.equal(
+ Object.assign({}, expectedResultTemplate, {
+ cbt: request.data.cbt,
+ gpid: '3333/4444',
+ pbadslot: '3333/4444'
+ })
+ );
+ })
+ })
+ })
+
+ const notGettingGpids = {
+ 'they are not existing': bidRequestTemplate,
+ 'they are blank': {
+ ortb2Imp: {
+ ext: {
+ tid: 'transaction-id',
+ gpid: '',
+ data: {
+ pbadslot: ''
+ }
+ }
+ }
+ }
+ }
+
+ Object.entries(notGettingGpids).forEach(([testTitle, param]) => {
+ it(`should not send gpid because ${testTitle}`, () => {
+ const bidRequest = Object.assign({}, bidRequestTemplate, param);
+ const requests = spec.buildRequests([bidRequest], bidderRequest)
+ requests.forEach(request => {
+ expect(request.data).to.deep.equal(
+ Object.assign({}, expectedResultTemplate, {
+ cbt: request.data.cbt,
+ })
+ );
+ expect(request.data.gpid).to.be.undefined;
+ expect(request.data.pbadslot).to.be.undefined;
+ })
+ })
+ })
+
+ it('should send adservname', () => {
+ const bidRequest = Object.assign({}, bidRequestTemplate, {
+ ortb2Imp: {
+ ext: {
+ tid: 'transaction-id',
+ data: {
+ adserver: {
+ name: 'gam'
+ }
+ }
+ }
+ }
+ });
+ const requests = spec.buildRequests([bidRequest], bidderRequest)
+ requests.forEach(request => {
+ expect(request.data).to.deep.equal(
+ Object.assign({}, expectedResultTemplate, {
+ cbt: request.data.cbt,
+ adservname: 'gam'
+ })
+ );
+ })
+ })
+
+ const notGettingAdservnames = {
+ 'it is not existing': bidRequestTemplate,
+ 'it is blank': {
+ ortb2Imp: {
+ ext: {
+ tid: 'transaction-id',
+ data: {
+ adserver: {
+ name: ''
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Object.entries(notGettingAdservnames).forEach(([testTitle, param]) => {
+ it(`should not send adservname because ${testTitle}`, () => {
+ const bidRequest = Object.assign({}, bidRequestTemplate, param);
+ const requests = spec.buildRequests([bidRequest], bidderRequest)
+ requests.forEach(request => {
+ expect(request.data).to.deep.equal(
+ Object.assign({}, expectedResultTemplate, {
+ cbt: request.data.cbt,
+ })
+ );
+ expect(request.data.adservname).to.be.undefined;
+ })
+ })
+ })
+
+ it('should send adservadslot', () => {
+ const bidRequest = Object.assign({}, bidRequestTemplate, {
+ ortb2Imp: {
+ ext: {
+ tid: 'transaction-id',
+ data: {
+ adserver: {
+ adslot: '/1111/home'
+ }
+ }
+ }
+ }
+ });
+ const requests = spec.buildRequests([bidRequest], bidderRequest)
+ requests.forEach(request => {
+ expect(request.data).to.deep.equal(
+ Object.assign({}, expectedResultTemplate, {
+ cbt: request.data.cbt,
+ adservadslot: '/1111/home'
+ })
+ );
+ })
+ })
+
+ const notGettingAdservadslots = {
+ 'it is not existing': bidRequestTemplate,
+ 'it is blank': {
+ ortb2Imp: {
+ ext: {
+ tid: 'transaction-id',
+ data: {
+ adserver: {
+ adslot: ''
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Object.entries(notGettingAdservadslots).forEach(([testTitle, param]) => {
+ it(`should not send adservadslot because ${testTitle}`, () => {
+ const bidRequest = Object.assign({}, bidRequestTemplate, param);
+ const requests = spec.buildRequests([bidRequest], bidderRequest)
+ requests.forEach(request => {
+ expect(request.data).to.deep.equal(
+ Object.assign({}, expectedResultTemplate, {
+ cbt: request.data.cbt,
+ })
+ );
+ expect(request.data.adservadslot).to.be.undefined;
+ })
+ })
+ })
});
describe('interpretResponse', () => {
diff --git a/test/spec/modules/minutemediaBidAdapter_spec.js b/test/spec/modules/minutemediaBidAdapter_spec.js
index 48f694bc79d..d5d6cdc5449 100644
--- a/test/spec/modules/minutemediaBidAdapter_spec.js
+++ b/test/spec/modules/minutemediaBidAdapter_spec.js
@@ -178,6 +178,16 @@ describe('minutemediaAdapter', function () {
expect(request.data.bids[1].mediaType).to.equal(BANNER)
});
+ it('should send the correct currency in bid request', function () {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.params = {
+ 'currency': 'EUR'
+ };
+ const expectedCurrency = bid.params.currency;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0].currency).to.equal(expectedCurrency);
+ });
+
it('should respect syncEnabled option', function() {
config.setConfig({
userSync: {
@@ -291,6 +301,22 @@ describe('minutemediaAdapter', function () {
expect(request.data.params).to.have.property('gdpr_consent', 'test-consent-string');
});
+ it('should not send the gpp param if gppConsent is false in the bidRequest', function () {
+ const bidderRequestWithGPP = Object.assign({gppConsent: false}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGPP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('gpp');
+ expect(request.data.params).to.not.have.property('gpp_sid');
+ });
+
+ it('should send the gpp param if gppConsent is true in the bidRequest', function () {
+ const bidderRequestWithGPP = Object.assign({gppConsent: {gppString: 'test-consent-string', applicableSections: [7]}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGPP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('gpp', 'test-consent-string');
+ expect(request.data.params.gpp_sid[0]).to.be.equal(7);
+ });
+
it('should have schain param if it is available in the bidRequest', () => {
const schain = {
ver: '1.0',
diff --git a/test/spec/modules/missenaBidAdapter_spec.js b/test/spec/modules/missenaBidAdapter_spec.js
index f61987298e8..ab1fbdcc074 100644
--- a/test/spec/modules/missenaBidAdapter_spec.js
+++ b/test/spec/modules/missenaBidAdapter_spec.js
@@ -1,23 +1,70 @@
import { expect } from 'chai';
-import { spec, _getPlatform } from 'modules/missenaBidAdapter.js';
-import { newBidder } from 'src/adapters/bidderFactory.js';
+import { spec, storage } from 'modules/missenaBidAdapter.js';
+import { BANNER } from '../../../src/mediaTypes.js';
+
+const REFERRER = 'https://referer';
+const REFERRER2 = 'https://referer2';
+const COOKIE_DEPRECATION_LABEL = 'test';
describe('Missena Adapter', function () {
- const adapter = newBidder(spec);
+ $$PREBID_GLOBAL$$.bidderSettings = {
+ missena: {
+ storageAllowed: true,
+ },
+ };
const bidId = 'abc';
-
const bid = {
bidder: 'missena',
bidId: bidId,
sizes: [[1, 1]],
+ mediaTypes: { banner: { sizes: [[1, 1]] } },
+ ortb2: {
+ device: {
+ ext: { cdep: COOKIE_DEPRECATION_LABEL },
+ },
+ },
params: {
apiKey: 'PA-34745704',
placement: 'sticky',
formats: ['sticky-banner'],
},
+ getFloor: (inputParams) => {
+ if (inputParams.mediaType === BANNER) {
+ return {
+ currency: 'EUR',
+ floor: 3.5,
+ };
+ } else {
+ return {};
+ }
+ },
};
+ const bidWithoutFloor = {
+ bidder: 'missena',
+ bidId: bidId,
+ sizes: [[1, 1]],
+ mediaTypes: { banner: { sizes: [[1, 1]] } },
+ params: {
+ apiKey: 'PA-34745704',
+ placement: 'sticky',
+ formats: ['sticky-banner'],
+ },
+ };
+ const consentString = 'AAAAAAAAA==';
+ const bidderRequest = {
+ gdprConsent: {
+ consentString: consentString,
+ gdprApplies: true,
+ },
+ refererInfo: {
+ topmostLocation: REFERRER,
+ canonicalUrl: 'https://canonical',
+ },
+ };
+
+ const bids = [bid, bidWithoutFloor];
describe('codes', function () {
it('should return a bidder code of missena', function () {
expect(spec.code).to.equal('missena');
@@ -31,34 +78,27 @@ describe('Missena Adapter', function () {
it('should return false if the apiKey is missing', function () {
expect(
- spec.isBidRequestValid(Object.assign(bid, { params: {} }))
+ spec.isBidRequestValid(Object.assign(bid, { params: {} })),
).to.equal(false);
});
it('should return false if the apiKey is an empty string', function () {
expect(
- spec.isBidRequestValid(Object.assign(bid, { params: { apiKey: '' } }))
+ spec.isBidRequestValid(Object.assign(bid, { params: { apiKey: '' } })),
).to.equal(false);
});
});
describe('buildRequests', function () {
- const consentString = 'AAAAAAAAA==';
-
- const bidderRequest = {
- gdprConsent: {
- consentString: consentString,
- gdprApplies: true,
- },
- refererInfo: {
- topmostLocation: 'https://referer',
- canonicalUrl: 'https://canonical',
- },
- };
+ let getDataFromLocalStorageStub = sinon.stub(
+ storage,
+ 'getDataFromLocalStorage',
+ );
- const requests = spec.buildRequests([bid, bid], bidderRequest);
+ const requests = spec.buildRequests(bids, bidderRequest);
const request = requests[0];
const payload = JSON.parse(request.data);
+ const payloadNoFloor = JSON.parse(requests[1].data);
it('should return as many server requests as bidder requests', function () {
expect(requests.length).to.equal(2);
@@ -81,7 +121,7 @@ describe('Missena Adapter', function () {
});
it('should send referer information to the request', function () {
- expect(payload.referer).to.equal('https://referer');
+ expect(payload.referer).to.equal(REFERRER);
expect(payload.referer_canonical).to.equal('https://canonical');
});
@@ -89,6 +129,78 @@ describe('Missena Adapter', function () {
expect(payload.consent_string).to.equal(consentString);
expect(payload.consent_required).to.equal(true);
});
+ it('should send floor data', function () {
+ expect(payload.floor).to.equal(3.5);
+ expect(payload.floor_currency).to.equal('EUR');
+ });
+ it('should not send floor data if not available', function () {
+ expect(payloadNoFloor.floor).to.equal(undefined);
+ expect(payloadNoFloor.floor_currency).to.equal(undefined);
+ });
+ it('should send the idempotency key', function () {
+ expect(window.msna_ik).to.not.equal(undefined);
+ expect(payload.ik).to.equal(window.msna_ik);
+ });
+
+ getDataFromLocalStorageStub.restore();
+ getDataFromLocalStorageStub = sinon.stub(
+ storage,
+ 'getDataFromLocalStorage',
+ );
+ const localStorageData = {
+ [`missena.missena.capper.remove-bubble.${bid.params.apiKey}`]:
+ JSON.stringify({
+ expiry: new Date().getTime() + 600_000, // 10 min into the future
+ }),
+ };
+ getDataFromLocalStorageStub.callsFake((key) => localStorageData[key]);
+ const cappedRequests = spec.buildRequests(bids, bidderRequest);
+
+ it('should not participate if capped', function () {
+ expect(cappedRequests.length).to.equal(0);
+ });
+
+ const localStorageDataSamePage = {
+ [`missena.missena.capper.remove-bubble.${bid.params.apiKey}`]:
+ JSON.stringify({
+ expiry: new Date().getTime() + 600_000, // 10 min into the future
+ referer: REFERRER,
+ }),
+ };
+
+ getDataFromLocalStorageStub.callsFake(
+ (key) => localStorageDataSamePage[key],
+ );
+ const cappedRequestsSamePage = spec.buildRequests(bids, bidderRequest);
+
+ it('should not participate if capped on same page', function () {
+ expect(cappedRequestsSamePage.length).to.equal(0);
+ });
+
+ const localStorageDataOtherPage = {
+ [`missena.missena.capper.remove-bubble.${bid.params.apiKey}`]:
+ JSON.stringify({
+ expiry: new Date().getTime() + 600_000, // 10 min into the future
+ referer: REFERRER2,
+ }),
+ };
+
+ getDataFromLocalStorageStub.callsFake(
+ (key) => localStorageDataOtherPage[key],
+ );
+ const cappedRequestsOtherPage = spec.buildRequests(bids, bidderRequest);
+
+ it('should participate if capped on a different page', function () {
+ expect(cappedRequestsOtherPage.length).to.equal(2);
+ });
+
+ it('should send the prebid version', function () {
+ expect(payload.version).to.equal('$prebid.version$');
+ });
+
+ it('should send cookie deprecation', function () {
+ expect(payload.cdep).to.equal(COOKIE_DEPRECATION_LABEL);
+ });
});
describe('interpretResponse', function () {
@@ -121,14 +233,14 @@ describe('Missena Adapter', function () {
expect(result.length).to.equal(1);
expect(Object.keys(result[0])).to.have.members(
- Object.keys(serverResponse)
+ Object.keys(serverResponse),
);
});
it('should return an empty response when the server answers with a timeout', function () {
const result = spec.interpretResponse(
{ body: serverTimeoutResponse },
- bid
+ bid,
);
expect(result).to.deep.equal([]);
});
@@ -136,7 +248,7 @@ describe('Missena Adapter', function () {
it('should return an empty response when the server answers with an empty ad', function () {
const result = spec.interpretResponse(
{ body: serverEmptyAdResponse },
- bid
+ bid,
);
expect(result).to.deep.equal([]);
});
diff --git a/test/spec/modules/mygaruIdSystem_spec.js b/test/spec/modules/mygaruIdSystem_spec.js
new file mode 100644
index 00000000000..2bfb5fdd4af
--- /dev/null
+++ b/test/spec/modules/mygaruIdSystem_spec.js
@@ -0,0 +1,62 @@
+import { mygaruIdSubmodule } from 'modules/mygaruIdSystem.js';
+import { server } from '../../mocks/xhr';
+
+describe('MygaruID module', function () {
+ it('should respond with async callback and get valid id', async () => {
+ const callBackSpy = sinon.spy();
+ const expectedUrl = `https://ident.mygaru.com/v2/id?gdprApplies=0`;
+ const result = mygaruIdSubmodule.getId({});
+
+ expect(result.callback).to.be.an('function');
+ const promise = result.callback(callBackSpy);
+
+ const request = server.requests[0];
+ expect(request.url).to.be.eq(expectedUrl);
+
+ request.respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({ iuid: '123' })
+ );
+ await promise;
+
+ expect(callBackSpy.calledOnce).to.be.true;
+ expect(callBackSpy.calledWith({mygaruId: '123'})).to.be.true;
+ });
+ it('should not fail on error', async () => {
+ const callBackSpy = sinon.spy();
+ const expectedUrl = `https://ident.mygaru.com/v2/id?gdprApplies=0`;
+ const result = mygaruIdSubmodule.getId({});
+
+ expect(result.callback).to.be.an('function');
+ const promise = result.callback(callBackSpy);
+
+ const request = server.requests[0];
+ expect(request.url).to.be.eq(expectedUrl);
+
+ request.respond(
+ 500,
+ {},
+ ''
+ );
+ await promise;
+
+ expect(callBackSpy.calledOnce).to.be.true;
+ expect(callBackSpy.calledWith({mygaruId: undefined})).to.be.true;
+ });
+
+ it('should not modify while decoding', () => {
+ const id = '222';
+ const newId = mygaruIdSubmodule.decode(id)
+
+ expect(id).to.eq(newId);
+ })
+ it('should buildUrl with consent data', () => {
+ const result = mygaruIdSubmodule.getId({}, {
+ gdprApplies: true,
+ consentString: 'consentString'
+ });
+
+ expect(result.url).to.eq('https://ident.mygaru.com/v2/id?gdprApplies=1&gdprConsentString=consentString');
+ })
+});
diff --git a/test/spec/modules/nextMillenniumBidAdapter_spec.js b/test/spec/modules/nextMillenniumBidAdapter_spec.js
index 564788c8b56..ff58671b17b 100644
--- a/test/spec/modules/nextMillenniumBidAdapter_spec.js
+++ b/test/spec/modules/nextMillenniumBidAdapter_spec.js
@@ -1,32 +1,582 @@
import { expect } from 'chai';
-import { spec } from 'modules/nextMillenniumBidAdapter.js';
+import {
+ getImp,
+ replaceUsersyncMacros,
+ setConsentStrings,
+ setOrtb2Parameters,
+ setEids,
+ spec,
+} from 'modules/nextMillenniumBidAdapter.js';
+
+describe('nextMillenniumBidAdapterTests', () => {
+ describe('function getImp', () => {
+ const dataTests = [
+ {
+ title: 'imp - banner',
+ data: {
+ id: '123',
+ bid: {
+ mediaTypes: {banner: {sizes: [[300, 250], [320, 250]]}},
+ adUnitCode: 'test-banner-1',
+ },
+
+ mediaTypes: {
+ banner: {
+ data: {sizes: [[300, 250], [320, 250]]},
+ bidfloorcur: 'EUR',
+ bidfloor: 1.11,
+ },
+ },
+ },
-describe('nextMillenniumBidAdapterTests', function() {
- const bidRequestData = [
- {
- adUnitCode: 'test-div',
- bidId: 'bid1234',
- auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917',
- bidder: 'nextMillennium',
- params: { placement_id: '-1' },
- sizes: [[300, 250]],
- uspConsent: '1---',
- gdprConsent: {
- consentString: 'kjfdniwjnifwenrif3',
- gdprApplies: true
+ expected: {
+ id: 'test-banner-1',
+ bidfloorcur: 'EUR',
+ bidfloor: 1.11,
+ ext: {prebid: {storedrequest: {id: '123'}}},
+ banner: {w: 300, h: 250, format: [{w: 300, h: 250}, {w: 320, h: 250}]},
+ },
},
- ortb2: {
- device: {
- w: 1500,
- h: 1000
+
+ {
+ title: 'imp - video',
+ data: {
+ id: '234',
+ bid: {
+ mediaTypes: {video: {playerSize: [400, 300], api: [2], placement: 1, plcmt: 1}},
+ adUnitCode: 'test-video-1',
+ },
+
+ mediaTypes: {
+ video: {
+ data: {playerSize: [400, 300], api: [2], placement: 1, plcmt: 1},
+ bidfloorcur: 'USD',
+ },
+ },
},
- site: {
- domain: 'example.com',
- page: 'http://example.com'
- }
+
+ expected: {
+ id: 'test-video-1',
+ bidfloorcur: 'USD',
+ ext: {prebid: {storedrequest: {id: '234'}}},
+ video: {
+ mimes: ['video/mp4', 'video/x-ms-wmv', 'application/javascript'],
+ api: [2],
+ placement: 1,
+ plcmt: 1,
+ w: 400,
+ h: 300,
+ },
+ },
+ },
+
+ {
+ title: 'imp - mediaTypes.video is empty',
+ data: {
+ id: '234',
+ bid: {
+ mediaTypes: {video: {w: 640, h: 480}},
+ adUnitCode: 'test-video-2',
+ },
+
+ mediaTypes: {
+ video: {
+ data: {w: 640, h: 480},
+ bidfloorcur: 'USD',
+ },
+ },
+ },
+
+ expected: {
+ id: 'test-video-2',
+ bidfloorcur: 'USD',
+ ext: {prebid: {storedrequest: {id: '234'}}},
+ video: {w: 640, h: 480, mimes: ['video/mp4', 'video/x-ms-wmv', 'application/javascript']},
+ },
+ },
+ ];
+
+ for (let {title, data, expected} of dataTests) {
+ it(title, () => {
+ const {bid, id, mediaTypes} = data;
+ const imp = getImp(bid, id, mediaTypes);
+ expect(imp).to.deep.equal(expected);
+ });
+ }
+ });
+
+ describe('function setConsentStrings', () => {
+ const dataTests = [
+ {
+ title: 'full: uspConsent, gdprConsent and gppConsent',
+ data: {
+ postBody: {},
+ bidderRequest: {
+ uspConsent: '1---',
+ gppConsent: {gppString: 'DBACNYA~CPXxRfAPXxR', applicableSections: [7]},
+ gdprConsent: {consentString: 'kjfdniwjnifwenrif3', gdprApplies: true},
+ ortb2: {regs: {gpp: 'DSFHFHWEUYVDC', gpp_sid: [8, 9, 10]}},
+ },
+ },
+
+ expected: {
+ user: {ext: {consent: 'kjfdniwjnifwenrif3'}},
+ regs: {
+ gpp: 'DBACNYA~CPXxRfAPXxR',
+ gpp_sid: [7],
+ ext: {gdpr: 1, us_privacy: '1---'},
+ },
+ },
+ },
+
+ {
+ title: 'gdprConsent(false) and ortb2(gpp)',
+ data: {
+ postBody: {},
+ bidderRequest: {
+ gdprConsent: {consentString: 'ewtewbefbawyadexv', gdprApplies: false},
+ ortb2: {regs: {gpp: 'DSFHFHWEUYVDC', gpp_sid: [8, 9, 10]}},
+ },
+ },
+
+ expected: {
+ user: {ext: {consent: 'ewtewbefbawyadexv'}},
+ regs: {
+ gpp: 'DSFHFHWEUYVDC',
+ gpp_sid: [8, 9, 10],
+ ext: {gdpr: 0},
+ },
+ },
+ },
+
+ {
+ title: 'gdprConsent(false)',
+ data: {
+ postBody: {},
+ bidderRequest: {gdprConsent: {gdprApplies: false}},
+ },
+
+ expected: {
+ regs: {ext: {gdpr: 0}},
+ },
+ },
+
+ {
+ title: 'empty',
+ data: {
+ postBody: {},
+ bidderRequest: {},
+ },
+
+ expected: {},
+ },
+ ];
+
+ for (let {title, data, expected} of dataTests) {
+ it(title, () => {
+ const {postBody, bidderRequest} = data;
+ setConsentStrings(postBody, bidderRequest);
+ expect(postBody).to.deep.equal(expected);
+ });
+ }
+ });
+
+ describe('function replaceUsersyncMacros', () => {
+ const dataTests = [
+ {
+ title: 'url with all macroses - consents full: uspConsent, gdprConsent and gppConsent',
+ data: {
+ url: 'https://some.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&type={{.TYPE_PIXEL}}',
+ uspConsent: '1---',
+ gppConsent: {gppString: 'DBACNYA~CPXxRfAPXxR', applicableSections: [7, 8]},
+ gdprConsent: {consentString: 'kjfdniwjnifwenrif3', gdprApplies: true},
+ type: 'image',
+ },
+
+ expected: 'https://some.url?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&us_privacy=1---&gpp=DBACNYA~CPXxRfAPXxR&gpp_sid=7,8&type=image',
+ },
+
+ {
+ title: 'url with some macroses - consents full: uspConsent, gdprConsent and gppConsent',
+ data: {
+ url: 'https://some.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&type={{.TYPE_PIXEL}}',
+ uspConsent: '1---',
+ gppConsent: {gppString: 'DBACNYA~CPXxRfAPXxR', applicableSections: [7, 8]},
+ gdprConsent: {consentString: 'kjfdniwjnifwenrif3', gdprApplies: false},
+ type: 'iframe',
+ },
+
+ expected: 'https://some.url?gdpr=0&gdpr_consent=kjfdniwjnifwenrif3&type=iframe',
+ },
+
+ {
+ title: 'url without macroses - consents full: uspConsent, gdprConsent and gppConsent',
+ data: {
+ url: 'https://some.url?param1=value1¶m2=value2',
+ uspConsent: '1---',
+ gppConsent: {gppString: 'DBACNYA~CPXxRfAPXxR', applicableSections: [7, 8]},
+ gdprConsent: {consentString: 'kjfdniwjnifwenrif3', gdprApplies: false},
+ type: 'iframe',
+ },
+
+ expected: 'https://some.url?param1=value1¶m2=value2',
+ },
+
+ {
+ title: 'url with all macroses - consents are empty',
+ data: {
+ url: 'https://some.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&type={{.TYPE_PIXEL}}',
+ },
+
+ expected: 'https://some.url?gdpr=0&gdpr_consent=&us_privacy=&gpp=&gpp_sid=&type=',
+ },
+ ];
+
+ for (let {title, data, expected} of dataTests) {
+ it(title, () => {
+ const {url, gdprConsent, uspConsent, gppConsent, type} = data;
+ const newUrl = replaceUsersyncMacros(url, gdprConsent, uspConsent, gppConsent, type);
+ expect(newUrl).to.equal(expected);
+ });
+ }
+ });
+
+ describe('function spec.getUserSyncs', () => {
+ const dataTests = [
+ {
+ title: 'pixels from responses ({iframeEnabled: true, pixelEnabled: true})',
+ data: {
+ syncOptions: {iframeEnabled: true, pixelEnabled: true},
+ responses: [
+ {body: {ext: {sync: {
+ image: [
+ 'https://some.1.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}',
+ 'https://some.2.url?us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}',
+ 'https://some.3.url?param=1234',
+ ],
+
+ iframe: [
+ 'https://some.4.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}',
+ 'https://some.5.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}',
+ ],
+ }}}},
+
+ {body: {ext: {sync: {
+ iframe: [
+ 'https://some.6.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}',
+ 'https://some.7.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}',
+ ],
+ }}}},
+
+ {body: {ext: {sync: {
+ image: [
+ 'https://some.8.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}',
+ ],
+ }}}},
+ ],
+
+ uspConsent: '1---',
+ gppConsent: {gppString: 'DBACNYA~CPXxRfAPXxR', applicableSections: [7, 8]},
+ gdprConsent: {consentString: 'kjfdniwjnifwenrif3', gdprApplies: true},
+ },
+
+ expected: [
+ {type: 'image', url: 'https://some.1.url?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&us_privacy=1---&gpp=DBACNYA~CPXxRfAPXxR&gpp_sid=7,8'},
+ {type: 'image', url: 'https://some.2.url?us_privacy=1---&gpp=DBACNYA~CPXxRfAPXxR&gpp_sid=7,8'},
+ {type: 'image', url: 'https://some.3.url?param=1234'},
+ {type: 'iframe', url: 'https://some.4.url?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&gpp=DBACNYA~CPXxRfAPXxR&gpp_sid=7,8'},
+ {type: 'iframe', url: 'https://some.5.url?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&us_privacy=1---'},
+ {type: 'iframe', url: 'https://some.6.url?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&gpp=DBACNYA~CPXxRfAPXxR&gpp_sid=7,8'},
+ {type: 'iframe', url: 'https://some.7.url?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&us_privacy=1---'},
+ {type: 'image', url: 'https://some.8.url?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&us_privacy=1---&gpp=DBACNYA~CPXxRfAPXxR&gpp_sid=7,8'},
+ ],
+ },
+
+ {
+ title: 'pixels from responses ({iframeEnabled: true, pixelEnabled: false})',
+ data: {
+ syncOptions: {iframeEnabled: true, pixelEnabled: false},
+ responses: [
+ {body: {ext: {sync: {
+ image: [
+ 'https://some.1.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}',
+ 'https://some.2.url?us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}',
+ 'https://some.3.url?param=1234',
+ ],
+
+ iframe: [
+ 'https://some.4.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}',
+ 'https://some.5.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}',
+ ],
+ }}}},
+ ],
+
+ uspConsent: '1---',
+ gppConsent: {gppString: 'DBACNYA~CPXxRfAPXxR', applicableSections: [7, 8]},
+ gdprConsent: {consentString: 'kjfdniwjnifwenrif3', gdprApplies: true},
+ },
+
+ expected: [
+ {type: 'iframe', url: 'https://some.4.url?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&gpp=DBACNYA~CPXxRfAPXxR&gpp_sid=7,8'},
+ {type: 'iframe', url: 'https://some.5.url?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&us_privacy=1---'},
+ ],
+ },
+
+ {
+ title: 'pixels from responses ({iframeEnabled: false, pixelEnabled: true})',
+ data: {
+ syncOptions: {iframeEnabled: false, pixelEnabled: true},
+ responses: [
+ {body: {ext: {sync: {
+ image: [
+ 'https://some.1.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}',
+ 'https://some.2.url?us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}',
+ 'https://some.3.url?param=1234',
+ ],
+
+ iframe: [
+ 'https://some.4.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}',
+ 'https://some.5.url?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}',
+ ],
+ }}}},
+ ],
+
+ uspConsent: '1---',
+ gppConsent: {gppString: 'DBACNYA~CPXxRfAPXxR', applicableSections: [7, 8]},
+ gdprConsent: {consentString: 'kjfdniwjnifwenrif3', gdprApplies: true},
+ },
+
+ expected: [
+ {type: 'image', url: 'https://some.1.url?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&us_privacy=1---&gpp=DBACNYA~CPXxRfAPXxR&gpp_sid=7,8'},
+ {type: 'image', url: 'https://some.2.url?us_privacy=1---&gpp=DBACNYA~CPXxRfAPXxR&gpp_sid=7,8'},
+ {type: 'image', url: 'https://some.3.url?param=1234'},
+ ],
+ },
+
+ {
+ title: 'pixels - responses is empty ({iframeEnabled: true, pixelEnabled: true})',
+ data: {
+ syncOptions: {iframeEnabled: true, pixelEnabled: true},
+ responses: [],
+ uspConsent: '1---',
+ gppConsent: {gppString: 'DBACNYA~CPXxRfAPXxR', applicableSections: [7, 8]},
+ gdprConsent: {consentString: 'kjfdniwjnifwenrif3', gdprApplies: true},
+ },
+
+ expected: [
+ {type: 'image', url: 'https://cookies.nextmillmedia.com/sync?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&us_privacy=1---&gpp=DBACNYA~CPXxRfAPXxR&gpp_sid=7,8&type=image'},
+ {type: 'iframe', url: 'https://cookies.nextmillmedia.com/sync?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&us_privacy=1---&gpp=DBACNYA~CPXxRfAPXxR&gpp_sid=7,8&type=iframe'},
+ ],
+ },
+
+ {
+ title: 'pixels - responses is empty ({iframeEnabled: true, pixelEnabled: false})',
+ data: {
+ syncOptions: {iframeEnabled: true, pixelEnabled: false},
+ uspConsent: '1---',
+ gppConsent: {gppString: 'DBACNYA~CPXxRfAPXxR', applicableSections: [7, 8]},
+ gdprConsent: {consentString: 'kjfdniwjnifwenrif3', gdprApplies: true},
+ },
+
+ expected: [
+ {type: 'iframe', url: 'https://cookies.nextmillmedia.com/sync?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&us_privacy=1---&gpp=DBACNYA~CPXxRfAPXxR&gpp_sid=7,8&type=iframe'},
+ ],
+ },
+
+ {
+ title: 'pixels - responses is empty ({iframeEnabled: false, pixelEnabled: false})',
+ data: {
+ syncOptions: {iframeEnabled: false, pixelEnabled: false},
+ uspConsent: '1---',
+ gppConsent: {gppString: 'DBACNYA~CPXxRfAPXxR', applicableSections: [7, 8]},
+ gdprConsent: {consentString: 'kjfdniwjnifwenrif3', gdprApplies: true},
+ },
+
+ expected: [],
+ },
+ ];
+
+ for (let {title, data, expected} of dataTests) {
+ it(title, () => {
+ const {syncOptions, responses, gdprConsent, uspConsent, gppConsent} = data;
+ const pixels = spec.getUserSyncs(syncOptions, responses, gdprConsent, uspConsent, gppConsent);
+ expect(pixels).to.deep.equal(expected);
+ });
+ }
+ });
+
+ describe('function setOrtb2Parameters', () => {
+ const dataTests = [
+ {
+ title: 'site.pagecat, site.content.cat and site.content.language',
+ data: {
+ postBody: {},
+ ortb2: {site: {
+ pagecat: ['IAB2-11', 'IAB2-12', 'IAB2-14'],
+ content: {cat: ['IAB2-11', 'IAB2-12', 'IAB2-14'], language: 'EN'},
+ }},
+ },
+
+ expected: {site: {
+ pagecat: ['IAB2-11', 'IAB2-12', 'IAB2-14'],
+ content: {cat: ['IAB2-11', 'IAB2-12', 'IAB2-14'], language: 'EN'},
+ }},
+ },
+
+ {
+ title: 'site.keywords, site.content.keywords and user.keywords',
+ data: {
+ postBody: {},
+ ortb2: {
+ user: {keywords: 'key7,key8,key9'},
+ site: {
+ keywords: 'key1,key2,key3',
+ content: {keywords: 'key4,key5,key6'},
+ },
+ },
+ },
+
+ expected: {
+ user: {keywords: 'key7,key8,key9'},
+ site: {
+ keywords: 'key1,key2,key3',
+ content: {keywords: 'key4,key5,key6'},
+ },
+ },
+ },
+
+ {
+ title: 'only site.content.language',
+ data: {
+ postBody: {site: {domain: 'some.domain'}},
+ ortb2: {site: {
+ content: {language: 'EN'},
+ }},
+ },
+
+ expected: {site: {
+ domain: 'some.domain',
+ content: {language: 'EN'},
+ }},
+ },
+
+ {
+ title: 'object ortb2 is empty',
+ data: {
+ postBody: {imp: []},
+ },
+
+ expected: {imp: []},
+ },
+ ];
+
+ for (let {title, data, expected} of dataTests) {
+ it(title, () => {
+ const {postBody, ortb2} = data;
+ setOrtb2Parameters(postBody, ortb2);
+ expect(postBody).to.deep.equal(expected);
+ });
+ };
+ });
+
+ describe('function setEids', () => {
+ const dataTests = [
+ {
+ title: 'setEids - userIdAsEids is empty',
+ data: {
+ postBody: {},
+ bid: {
+ userIdAsEids: undefined,
+ },
+ },
+
+ expected: {},
+ },
+
+ {
+ title: 'setEids - userIdAsEids - array is empty',
+ data: {
+ postBody: {},
+ bid: {
+ userIdAsEids: [],
+ },
+ },
+
+ expected: {},
+ },
+
+ {
+ title: 'setEids - userIdAsEids is',
+ data: {
+ postBody: {},
+ bid: {
+ userIdAsEids: [
+ {
+ source: '33across.com',
+ uids: [{id: 'some-random-id-value', atype: 1}],
+ },
+
+ {
+ source: 'utiq.com',
+ uids: [{id: 'some-random-id-value', atype: 1}],
+ },
+ ],
+ },
+ },
+
+ expected: {
+ user: {
+ eids: [
+ {
+ source: '33across.com',
+ uids: [{id: 'some-random-id-value', atype: 1}],
+ },
+
+ {
+ source: 'utiq.com',
+ uids: [{id: 'some-random-id-value', atype: 1}],
+ },
+ ],
+ },
+ },
+ },
+ ];
+
+ for (let { title, data, expected } of dataTests) {
+ it(title, () => {
+ const { postBody, bid } = data;
+ setEids(postBody, bid);
+ expect(postBody).to.deep.equal(expected);
+ });
+ }
+ });
+
+ const bidRequestData = [{
+ adUnitCode: 'test-div',
+ bidId: 'bid1234',
+ auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917',
+ bidder: 'nextMillennium',
+ params: { placement_id: '-1' },
+ sizes: [[300, 250]],
+ uspConsent: '1---',
+ gppConsent: {gppString: 'DBACNYA~CPXxRfAPXxR', applicableSections: [7]},
+ gdprConsent: {
+ consentString: 'kjfdniwjnifwenrif3',
+ gdprApplies: true
+ },
+
+ ortb2: {
+ device: {
+ w: 1500,
+ h: 1000
+ },
+
+ site: {
+ domain: 'example.com',
+ page: 'http://example.com'
}
}
- ];
+ }];
const serverResponse = {
body: {
@@ -49,7 +599,7 @@ describe('nextMillenniumBidAdapterTests', function() {
cur: 'USD',
ext: {
sync: {
- image: ['urlA?gdpr={{.GDPR}}'],
+ image: ['urlA?gdpr={{.GDPR}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}'],
iframe: ['urlB'],
}
}
@@ -117,61 +667,6 @@ describe('nextMillenniumBidAdapterTests', function() {
},
];
- it('Request params check with GDPR and USP Consent', function () {
- const request = spec.buildRequests(bidRequestData, bidRequestData[0]);
- expect(JSON.parse(request[0].data).user.ext.consent).to.equal('kjfdniwjnifwenrif3');
- expect(JSON.parse(request[0].data).regs.ext.us_privacy).to.equal('1---');
- expect(JSON.parse(request[0].data).regs.ext.gdpr).to.equal(1);
- });
-
- it('Test getUserSyncs function', function () {
- const syncOptions = {
- 'iframeEnabled': false,
- 'pixelEnabled': true
- }
- let userSync = spec.getUserSyncs(syncOptions, [serverResponse], bidRequestData[0].gdprConsent, bidRequestData[0].uspConsent);
- expect(userSync).to.be.an('array').with.lengthOf(1);
- expect(userSync[0].type).to.equal('image');
- expect(userSync[0].url).to.equal('urlA?gdpr=1');
-
- syncOptions.iframeEnabled = true;
- syncOptions.pixelEnabled = false;
- userSync = spec.getUserSyncs(syncOptions, [serverResponse], bidRequestData[0].gdprConsent, bidRequestData[0].uspConsent);
- expect(userSync).to.be.an('array').with.lengthOf(1);
- expect(userSync[0].type).to.equal('iframe');
- expect(userSync[0].url).to.equal('urlB');
- });
-
- it('Test getUserSyncs with no response', function () {
- const syncOptions = {
- 'iframeEnabled': true,
- 'pixelEnabled': false
- }
- let userSync = spec.getUserSyncs(syncOptions, [], bidRequestData[0].gdprConsent, bidRequestData[0].uspConsent);
- expect(userSync).to.be.an('array')
- expect(userSync[0].type).to.equal('iframe')
- expect(userSync[0].url).to.equal('https://cookies.nextmillmedia.com/sync?gdpr=1&gdpr_consent=kjfdniwjnifwenrif3&us_privacy=1---&type=iframe')
- })
-
- it('Test getUserSyncs function if GDPR is undefined', function () {
- const syncOptions = {
- 'iframeEnabled': false,
- 'pixelEnabled': true
- }
-
- let userSync = spec.getUserSyncs(syncOptions, [serverResponse], undefined, bidRequestData[0].uspConsent);
- expect(userSync).to.be.an('array').with.lengthOf(1);
- expect(userSync[0].type).to.equal('image');
- expect(userSync[0].url).to.equal('urlA?gdpr=0');
- });
-
- it('Request params check without GDPR Consent', function () {
- delete bidRequestData[0].gdprConsent
- const request = spec.buildRequests(bidRequestData, bidRequestData[0]);
- expect(JSON.parse(request[0].data).regs.ext.gdpr).to.be.undefined;
- expect(JSON.parse(request[0].data).regs.ext.us_privacy).to.equal('1---');
- });
-
it('validate_generated_params', function() {
const request = spec.buildRequests(bidRequestData, {bidderRequestId: 'mock-uuid'});
expect(request[0].bidId).to.equal('bid1234');
@@ -190,7 +685,7 @@ describe('nextMillenniumBidAdapterTests', function() {
it('Check if refresh_count param is incremented', function() {
const request = spec.buildRequests(bidRequestData);
- expect(JSON.parse(request[0].data).ext.nextMillennium.refresh_count).to.equal(3);
+ expect(JSON.parse(request[0].data).ext.nextMillennium.refresh_count).to.equal(1);
});
it('Check if domain was added', function() {
@@ -439,7 +934,7 @@ describe('nextMillenniumBidAdapterTests', function() {
];
for (let {eventName, bid, expected} of dataForTests) {
- const url = spec.getUrlPixelMetric(eventName, bid);
+ const url = spec._getUrlPixelMetric(eventName, bid);
expect(url).to.equal(expected);
};
})
diff --git a/test/spec/modules/nexx360BidAdapter_spec.js b/test/spec/modules/nexx360BidAdapter_spec.js
index 7091bb56631..f18e0365226 100644
--- a/test/spec/modules/nexx360BidAdapter_spec.js
+++ b/test/spec/modules/nexx360BidAdapter_spec.js
@@ -20,12 +20,12 @@ const instreamResponse = {
'crid': '97517771',
'h': 1,
'w': 1,
+ 'adm': '
\n \n \n Nexx360 Wrapper \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ',
'ext': {
'mediaType': 'instream',
'ssp': 'appnexus',
'divId': 'video1',
'adUnitCode': 'video1',
- 'vastXml': '
\n \n \n Nexx360 Wrapper \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n '
}
}
],
@@ -374,7 +374,7 @@ describe('Nexx360 bid adapter tests', function () {
expect(requestContent.imp[1].tagid).to.be.eql('div-2-abcd');
expect(requestContent.imp[1].ext.adUnitCode).to.be.eql('div-2-abcd');
expect(requestContent.imp[1].ext.divId).to.be.eql('div-2-abcd');
- expect(requestContent.ext.bidderVersion).to.be.eql('3.0');
+ expect(requestContent.ext.bidderVersion).to.be.eql('4.0');
expect(requestContent.ext.source).to.be.eql('prebid.js');
});
@@ -561,7 +561,7 @@ describe('Nexx360 bid adapter tests', function () {
}
};
const output = spec.interpretResponse(response);
- expect(output[0].vastXml).to.be.eql(response.body.seatbid[0].bid[0].ext.vastXml);
+ expect(output[0].vastXml).to.be.eql(response.body.seatbid[0].bid[0].adm);
expect(output[0].mediaType).to.be.eql('video');
expect(output[0].currency).to.be.eql(response.body.cur);
expect(output[0].cpm).to.be.eql(response.body.seatbid[0].bid[0].price);
@@ -585,11 +585,11 @@ describe('Nexx360 bid adapter tests', function () {
'crid': '97517771',
'h': 1,
'w': 1,
+ 'adm': '
\n \n \n Nexx360 Wrapper \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ',
'ext': {
'mediaType': 'outstream',
'ssp': 'appnexus',
'adUnitCode': 'div-1',
- 'vastXml': '
\n \n \n Nexx360 Wrapper \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n '
}
}
],
@@ -602,7 +602,7 @@ describe('Nexx360 bid adapter tests', function () {
}
};
const output = spec.interpretResponse(response);
- expect(output[0].vastXml).to.be.eql(response.body.seatbid[0].bid[0].ext.vastXml);
+ expect(output[0].vastXml).to.be.eql(response.body.seatbid[0].bid[0].adm);
expect(output[0].mediaType).to.be.eql('video');
expect(output[0].currency).to.be.eql(response.body.cur);
expect(typeof output[0].renderer).to.be.eql('object');
diff --git a/test/spec/modules/nobidAnalyticsAdapter_spec.js b/test/spec/modules/nobidAnalyticsAdapter_spec.js
index 742b4c16abb..f6c741bb7ff 100644
--- a/test/spec/modules/nobidAnalyticsAdapter_spec.js
+++ b/test/spec/modules/nobidAnalyticsAdapter_spec.js
@@ -127,9 +127,9 @@ describe('NoBid Prebid Analytic', function () {
mediaType: 'banner',
source: 'client',
cpm: 6.4,
+ currency: 'EUR',
creativeId: 'TEST',
dealId: '',
- currency: 'USD',
netRevenue: true,
ttl: 300,
ad: 'AD HERE',
@@ -167,13 +167,17 @@ describe('NoBid Prebid Analytic', function () {
]
};
- const requestOutgoing = {
+ const expectedOutgoingRequest = {
+ version: nobidAnalyticsVersion,
bidderCode: 'nobid',
statusMessage: 'Bid available',
adId: '106d14b7d06b607',
requestId: '67a7f0e7ea55c4',
mediaType: 'banner',
cpm: 6.4,
+ currency: 'EUR',
+ originalCpm: 6.44,
+ originalCurrency: 'USD',
adUnitCode: 'leaderboard',
timeToRespond: 545,
size: '728x90',
@@ -197,16 +201,20 @@ describe('NoBid Prebid Analytic', function () {
clock.tick(5000);
expect(server.requests).to.have.length(1);
const bidWonRequest = JSON.parse(server.requests[0].requestBody);
- expect(bidWonRequest).to.have.property('bidderCode', requestOutgoing.bidderCode);
- expect(bidWonRequest).to.have.property('statusMessage', requestOutgoing.statusMessage);
- expect(bidWonRequest).to.have.property('adId', requestOutgoing.adId);
- expect(bidWonRequest).to.have.property('requestId', requestOutgoing.requestId);
- expect(bidWonRequest).to.have.property('mediaType', requestOutgoing.mediaType);
- expect(bidWonRequest).to.have.property('cpm', requestOutgoing.cpm);
- expect(bidWonRequest).to.have.property('adUnitCode', requestOutgoing.adUnitCode);
- expect(bidWonRequest).to.have.property('timeToRespond', requestOutgoing.timeToRespond);
- expect(bidWonRequest).to.have.property('size', requestOutgoing.size);
- expect(bidWonRequest).to.have.property('topLocation', requestOutgoing.topLocation);
+ expect(bidWonRequest).to.have.property('version', nobidAnalyticsVersion);
+ expect(bidWonRequest).to.have.property('bidderCode', expectedOutgoingRequest.bidderCode);
+ expect(bidWonRequest).to.have.property('statusMessage', expectedOutgoingRequest.statusMessage);
+ expect(bidWonRequest).to.have.property('adId', expectedOutgoingRequest.adId);
+ expect(bidWonRequest).to.have.property('requestId', expectedOutgoingRequest.requestId);
+ expect(bidWonRequest).to.have.property('mediaType', expectedOutgoingRequest.mediaType);
+ expect(bidWonRequest).to.have.property('cpm', expectedOutgoingRequest.cpm);
+ expect(bidWonRequest).to.have.property('currency', expectedOutgoingRequest.currency);
+ expect(bidWonRequest).to.have.property('originalCpm', expectedOutgoingRequest.originalCpm);
+ expect(bidWonRequest).to.have.property('originalCurrency', expectedOutgoingRequest.originalCurrency);
+ expect(bidWonRequest).to.have.property('adUnitCode', expectedOutgoingRequest.adUnitCode);
+ expect(bidWonRequest).to.have.property('timeToRespond', expectedOutgoingRequest.timeToRespond);
+ expect(bidWonRequest).to.have.property('size', expectedOutgoingRequest.size);
+ expect(bidWonRequest).to.have.property('topLocation', expectedOutgoingRequest.topLocation);
expect(bidWonRequest).to.not.have.property('pbCg');
done();
@@ -304,10 +312,10 @@ describe('NoBid Prebid Analytic', function () {
auctionId: '4c056b3c-f1a6-46bd-8d82-58c15b22fcfa',
mediaType: 'banner',
source: 'client',
- cpm: 6.44,
+ cpm: 5.93,
+ currency: 'EUR',
creativeId: 'TEST',
dealId: '',
- currency: 'USD',
netRevenue: true,
ttl: 300,
ad: '',
@@ -336,7 +344,7 @@ describe('NoBid Prebid Analytic', function () {
timeout: 3000
};
- const requestOutgoing = {
+ const expectedOutgoingRequest = {
auctionId: '4c056b3c-f1a6-46bd-8d82-58c15b22fcfa',
bidderRequests: [
{
@@ -344,7 +352,6 @@ describe('NoBid Prebid Analytic', function () {
bidderRequestId: '7c1940bb285731',
bids: [
{
- bidder: 'nobid',
params: { siteId: SITE_ID },
mediaTypes: { banner: { sizes: [[728, 90]] } },
adUnitCode: 'leaderboard',
@@ -365,7 +372,10 @@ describe('NoBid Prebid Analytic', function () {
width: 728,
height: 90,
mediaType: 'banner',
- cpm: 6.44,
+ cpm: 5.93,
+ currency: 'EUR',
+ originalCpm: 6.44,
+ originalCurrency: 'USD',
adUnitCode: 'leaderboard'
}
]
@@ -388,21 +398,34 @@ describe('NoBid Prebid Analytic', function () {
clock.tick(5000);
expect(server.requests).to.have.length(1);
const auctionEndRequest = JSON.parse(server.requests[0].requestBody);
- expect(auctionEndRequest).to.have.property('auctionId', requestOutgoing.auctionId);
+ expect(auctionEndRequest).to.have.property('version', nobidAnalyticsVersion);
+ expect(auctionEndRequest).to.have.property('auctionId', expectedOutgoingRequest.auctionId);
expect(auctionEndRequest.bidderRequests).to.have.length(1);
- expect(auctionEndRequest.bidderRequests[0]).to.have.property('bidderCode', requestOutgoing.bidderRequests[0].bidderCode);
+ expect(auctionEndRequest.bidderRequests[0].bidderCode).to.equal(expectedOutgoingRequest.bidderRequests[0].bidderCode);
expect(auctionEndRequest.bidderRequests[0].bids).to.have.length(1);
- expect(auctionEndRequest.bidderRequests[0].bids[0]).to.have.property('bidder', requestOutgoing.bidderRequests[0].bids[0].bidder);
- expect(auctionEndRequest.bidderRequests[0].bids[0]).to.have.property('adUnitCode', requestOutgoing.bidderRequests[0].bids[0].adUnitCode);
- expect(auctionEndRequest.bidderRequests[0].bids[0].params).to.have.property('siteId', requestOutgoing.bidderRequests[0].bids[0].params.siteId);
- expect(auctionEndRequest.bidderRequests[0].refererInfo).to.have.property('topmostLocation', requestOutgoing.bidderRequests[0].refererInfo.topmostLocation);
+ expect(typeof auctionEndRequest.bidderRequests[0].bids[0].bidder).to.equal('undefined');
+ expect(auctionEndRequest.bidderRequests[0].bids[0].adUnitCode).to.equal(expectedOutgoingRequest.bidderRequests[0].bids[0].adUnitCode);
+ expect(typeof auctionEndRequest.bidderRequests[0].bids[0].params).to.equal('undefined');
+ expect(typeof auctionEndRequest.bidderRequests[0].bids[0].src).to.equal('undefined');
+ expect(auctionEndRequest.bidderRequests[0].refererInfo.topmostLocation).to.equal(expectedOutgoingRequest.bidderRequests[0].refererInfo.topmostLocation);
+ expect(auctionEndRequest.bidsReceived).to.have.length(1);
+ expect(auctionEndRequest.bidsReceived[0].bidderCode).to.equal(expectedOutgoingRequest.bidsReceived[0].bidderCode);
+ expect(auctionEndRequest.bidsReceived[0].width).to.equal(expectedOutgoingRequest.bidsReceived[0].width);
+ expect(auctionEndRequest.bidsReceived[0].height).to.equal(expectedOutgoingRequest.bidsReceived[0].height);
+ expect(auctionEndRequest.bidsReceived[0].mediaType).to.equal(expectedOutgoingRequest.bidsReceived[0].mediaType);
+ expect(auctionEndRequest.bidsReceived[0].cpm).to.equal(expectedOutgoingRequest.bidsReceived[0].cpm);
+ expect(auctionEndRequest.bidsReceived[0].currency).to.equal(expectedOutgoingRequest.bidsReceived[0].currency);
+ expect(auctionEndRequest.bidsReceived[0].originalCpm).to.equal(expectedOutgoingRequest.bidsReceived[0].originalCpm);
+ expect(auctionEndRequest.bidsReceived[0].originalCurrency).to.equal(expectedOutgoingRequest.bidsReceived[0].originalCurrency);
+ expect(auctionEndRequest.bidsReceived[0].adUnitCode).to.equal(expectedOutgoingRequest.bidsReceived[0].adUnitCode);
+ expect(typeof auctionEndRequest.bidsReceived[0].source).to.equal('undefined');
done();
});
it('Analytics disabled test', function (done) {
let disabled;
- nobidAnalytics.processServerResponse(JSON.stringify({disabled: false}));
+ nobidAnalytics.processServerResponse(JSON.stringify({disabled: 0}));
disabled = nobidAnalytics.isAnalyticsDisabled();
expect(disabled).to.equal(false);
events.emit(constants.EVENTS.AUCTION_END, {auctionId: '1234567890'});
@@ -417,7 +440,7 @@ describe('NoBid Prebid Analytic', function () {
clock.tick(1000);
expect(server.requests).to.have.length(3);
- nobidAnalytics.processServerResponse(JSON.stringify({disabled: true}));
+ nobidAnalytics.processServerResponse(JSON.stringify({disabled: 1}));
disabled = nobidAnalytics.isAnalyticsDisabled();
expect(disabled).to.equal(true);
events.emit(constants.EVENTS.AUCTION_END, {auctionId: '12345678902'});
@@ -425,7 +448,7 @@ describe('NoBid Prebid Analytic', function () {
expect(server.requests).to.have.length(3);
nobidAnalytics.retentionSeconds = 5;
- nobidAnalytics.processServerResponse(JSON.stringify({disabled: true}));
+ nobidAnalytics.processServerResponse(JSON.stringify({disabled: 1}));
clock.tick(1000);
disabled = nobidAnalytics.isAnalyticsDisabled();
expect(disabled).to.equal(true);
@@ -437,6 +460,100 @@ describe('NoBid Prebid Analytic', function () {
});
});
+ describe('Analytics disabled event type test', function () {
+ beforeEach(function () {
+ sinon.stub(events, 'getEvents').returns([]);
+ clock = sinon.useFakeTimers(Date.now());
+ });
+
+ afterEach(function () {
+ events.getEvents.restore();
+ clock.restore();
+ });
+
+ after(function () {
+ nobidAnalytics.disableAnalytics();
+ });
+
+ it('Analytics disabled event type test', function (done) {
+ // Initialize adapter
+ const initOptions = { options: { siteId: SITE_ID } };
+ nobidAnalytics.enableAnalytics(initOptions);
+ adapterManager.enableAnalytics({ provider: 'nobid', options: initOptions });
+
+ let eventType = constants.EVENTS.AUCTION_END;
+ let disabled;
+ nobidAnalytics.processServerResponse(JSON.stringify({disabled: 0}));
+ disabled = nobidAnalytics.isAnalyticsDisabled();
+ expect(disabled).to.equal(false);
+ events.emit(eventType, {auctionId: '1234567890'});
+ clock.tick(1000);
+ expect(server.requests).to.have.length(1);
+ events.emit(eventType, {auctionId: '12345678901'});
+ clock.tick(1000);
+ expect(server.requests).to.have.length(2);
+
+ server.requests.length = 0;
+ expect(server.requests).to.have.length(0);
+
+ nobidAnalytics.processServerResponse(JSON.stringify({disabled_auctionEnd: 1}));
+ disabled = nobidAnalytics.isAnalyticsDisabled(eventType);
+ expect(disabled).to.equal(true);
+ events.emit(eventType, {auctionId: '1234567890'});
+ clock.tick(1000);
+ expect(server.requests).to.have.length(0);
+
+ server.requests.length = 0;
+
+ nobidAnalytics.processServerResponse(JSON.stringify({disabled_auctionEnd: 0}));
+ disabled = nobidAnalytics.isAnalyticsDisabled(eventType);
+ expect(disabled).to.equal(false);
+ events.emit(constants.EVENTS.AUCTION_END, {auctionId: '1234567890'});
+ clock.tick(1000);
+ expect(server.requests).to.have.length(1);
+
+ server.requests.length = 0;
+ expect(server.requests).to.have.length(0);
+
+ eventType = constants.EVENTS.BID_WON;
+ nobidAnalytics.processServerResponse(JSON.stringify({disabled_bidWon: 1}));
+ disabled = nobidAnalytics.isAnalyticsDisabled(eventType);
+ expect(disabled).to.equal(true);
+ events.emit(eventType, {bidderCode: 'nobid'});
+ clock.tick(1000);
+ expect(server.requests).to.have.length(0);
+
+ server.requests.length = 0;
+ expect(server.requests).to.have.length(0);
+
+ eventType = constants.EVENTS.AUCTION_END;
+ nobidAnalytics.processServerResponse(JSON.stringify({disabled: 1}));
+ disabled = nobidAnalytics.isAnalyticsDisabled(eventType);
+ expect(disabled).to.equal(true);
+ events.emit(eventType, {auctionId: '1234567890'});
+ clock.tick(1000);
+ expect(server.requests).to.have.length(0);
+
+ server.requests.length = 0;
+ expect(server.requests).to.have.length(0);
+
+ eventType = constants.EVENTS.AUCTION_END;
+ nobidAnalytics.processServerResponse(JSON.stringify({disabled_auctionEnd: 1, disabled_bidWon: 0}));
+ disabled = nobidAnalytics.isAnalyticsDisabled(eventType);
+ expect(disabled).to.equal(true);
+ events.emit(eventType, {auctionId: '1234567890'});
+ clock.tick(1000);
+ expect(server.requests).to.have.length(0);
+ disabled = nobidAnalytics.isAnalyticsDisabled(constants.EVENTS.BID_WON);
+ expect(disabled).to.equal(false);
+ events.emit(constants.EVENTS.BID_WON, {bidderCode: 'nobid'});
+ clock.tick(1000);
+ expect(server.requests).to.have.length(1);
+
+ done();
+ });
+ });
+
describe('NoBid Carbonizer', function () {
beforeEach(function () {
sinon.stub(events, 'getEvents').returns([]);
@@ -456,7 +573,8 @@ describe('NoBid Prebid Analytic', function () {
let active = nobidCarbonizer.isActive();
expect(active).to.equal(false);
- active = nobidCarbonizer.isActive(JSON.stringify({carbonizer_active: false}));
+ nobidAnalytics.processServerResponse(JSON.stringify({carbonizer_active: false}));
+ active = nobidCarbonizer.isActive();
expect(active).to.equal(false);
nobidAnalytics.processServerResponse(JSON.stringify({carbonizer_active: true}));
@@ -466,15 +584,15 @@ describe('NoBid Prebid Analytic', function () {
const previousRetention = nobidAnalytics.retentionSeconds;
nobidAnalytics.retentionSeconds = 3;
nobidAnalytics.processServerResponse(JSON.stringify({carbonizer_active: true}));
- const stored = nobidCarbonizer.getStoredLocalData();
- expect(stored).to.contain(`{"carbonizer_active":true,"ts":`);
+ let stored = nobidCarbonizer.getStoredLocalData();
+ expect(stored[nobidAnalytics.ANALYTICS_DATA_NAME]).to.contain(`{"carbonizer_active":true,"ts":`);
clock.tick(5000);
- active = nobidCarbonizer.isActive(adunits, true);
+ active = nobidCarbonizer.isActive();
expect(active).to.equal(false);
nobidAnalytics.retentionSeconds = previousRetention;
nobidAnalytics.processServerResponse(JSON.stringify({carbonizer_active: true}));
- active = nobidCarbonizer.isActive(adunits, true);
+ active = nobidCarbonizer.isActive();
expect(active).to.equal(true);
let adunits = [
@@ -486,6 +604,10 @@ describe('NoBid Prebid Analytic', function () {
}
]
nobidCarbonizer.carbonizeAdunits(adunits, true);
+ stored = nobidCarbonizer.getStoredLocalData();
+ expect(stored[nobidAnalytics.ANALYTICS_DATA_NAME]).to.contain('{"carbonizer_active":true,"ts":');
+ expect(stored[nobidAnalytics.ANALYTICS_OPT_NAME]).to.contain('{"bidder1":1,"bidder2":1}');
+ clock.tick(5000);
expect(adunits[0].bids.length).to.equal(0);
done();
diff --git a/test/spec/modules/oguryBidAdapter_spec.js b/test/spec/modules/oguryBidAdapter_spec.js
index ed358af19b6..aad753571a8 100644
--- a/test/spec/modules/oguryBidAdapter_spec.js
+++ b/test/spec/modules/oguryBidAdapter_spec.js
@@ -42,7 +42,21 @@ describe('OguryBidAdapter', function () {
return floorResult;
},
- transactionId: 'transactionId'
+ transactionId: 'transactionId',
+ userId: {
+ pubcid: '2abb10e5-c4f6-4f70-9f45-2200e4487714'
+ },
+ userIdAsEids: [
+ {
+ source: 'pubcid.org',
+ uids: [
+ {
+ id: '2abb10e5-c4f6-4f70-9f45-2200e4487714',
+ atype: 1
+ }
+ ]
+ }
+ ]
},
{
adUnitCode: 'adUnitCode2',
@@ -407,12 +421,26 @@ describe('OguryBidAdapter', function () {
},
user: {
ext: {
- consent: bidderRequest.gdprConsent.consentString
+ consent: bidderRequest.gdprConsent.consentString,
+ uids: {
+ pubcid: '2abb10e5-c4f6-4f70-9f45-2200e4487714'
+ },
+ eids: [
+ {
+ source: 'pubcid.org',
+ uids: [
+ {
+ id: '2abb10e5-c4f6-4f70-9f45-2200e4487714',
+ atype: 1
+ }
+ ]
+ }
+ ],
},
},
ext: {
prebidversion: '$prebid.version$',
- adapterversion: '1.5.0'
+ adapterversion: '1.6.0'
},
device: {
w: stubbedWidth,
@@ -637,7 +665,9 @@ describe('OguryBidAdapter', function () {
},
user: {
ext: {
- consent: ''
+ consent: '',
+ uids: expectedRequestObject.user.ext.uids,
+ eids: expectedRequestObject.user.ext.eids
},
}
};
@@ -663,7 +693,9 @@ describe('OguryBidAdapter', function () {
},
user: {
ext: {
- consent: ''
+ consent: '',
+ uids: expectedRequestObject.user.ext.uids,
+ eids: expectedRequestObject.user.ext.eids
},
}
};
@@ -689,7 +721,9 @@ describe('OguryBidAdapter', function () {
},
user: {
ext: {
- consent: ''
+ consent: '',
+ uids: expectedRequestObject.user.ext.uids,
+ eids: expectedRequestObject.user.ext.eids
},
}
};
@@ -701,6 +735,48 @@ describe('OguryBidAdapter', function () {
expect(request.data.regs.ext.gdpr).to.be.a('number');
});
+ it('should should not add uids infos if userId is undefined', () => {
+ const expectedRequestWithUndefinedUserId = {
+ ...expectedRequestObject,
+ user: {
+ ext: {
+ consent: expectedRequestObject.user.ext.consent,
+ eids: expectedRequestObject.user.ext.eids
+ }
+ }
+ };
+
+ const validBidRequests = utils.deepClone(bidRequests);
+ validBidRequests[0] = {
+ ...validBidRequests[0],
+ userId: undefined
+ };
+
+ const request = spec.buildRequests(validBidRequests, bidderRequest);
+ expect(request.data).to.deep.equal(expectedRequestWithUndefinedUserId);
+ });
+
+ it('should should not add uids infos if userIdAsEids is undefined', () => {
+ const expectedRequestWithUndefinedUserIdAsEids = {
+ ...expectedRequestObject,
+ user: {
+ ext: {
+ consent: expectedRequestObject.user.ext.consent,
+ uids: expectedRequestObject.user.ext.uids
+ }
+ }
+ };
+
+ const validBidRequests = utils.deepClone(bidRequests);
+ validBidRequests[0] = {
+ ...validBidRequests[0],
+ userIdAsEids: undefined
+ };
+
+ const request = spec.buildRequests(validBidRequests, bidderRequest);
+ expect(request.data).to.deep.equal(expectedRequestWithUndefinedUserIdAsEids);
+ });
+
it('should handle bidFloor undefined', () => {
const expectedRequestWithUndefinedFloor = {
...expectedRequestObject
@@ -814,7 +890,7 @@ describe('OguryBidAdapter', function () {
advertiserDomains: openRtbBidResponse.body.seatbid[0].bid[0].adomain
},
nurl: openRtbBidResponse.body.seatbid[0].bid[0].nurl,
- adapterVersion: '1.5.0',
+ adapterVersion: '1.6.0',
prebidVersion: '$prebid.version$'
}, {
requestId: openRtbBidResponse.body.seatbid[0].bid[1].impid,
@@ -831,7 +907,7 @@ describe('OguryBidAdapter', function () {
advertiserDomains: openRtbBidResponse.body.seatbid[0].bid[1].adomain
},
nurl: openRtbBidResponse.body.seatbid[0].bid[1].nurl,
- adapterVersion: '1.5.0',
+ adapterVersion: '1.6.0',
prebidVersion: '$prebid.version$'
}]
diff --git a/test/spec/modules/omsBidAdapter_spec.js b/test/spec/modules/omsBidAdapter_spec.js
new file mode 100644
index 00000000000..10a9c4c946c
--- /dev/null
+++ b/test/spec/modules/omsBidAdapter_spec.js
@@ -0,0 +1,420 @@
+import {expect} from 'chai';
+import * as utils from 'src/utils.js';
+import {spec} from 'modules/omsBidAdapter';
+import {newBidder} from 'src/adapters/bidderFactory.js';
+import {config} from '../../../src/config';
+
+const URL = 'https://rt.marphezis.com/hb';
+
+describe('omsBidAdapter', function () {
+ const adapter = newBidder(spec);
+ let element, win;
+ let bidRequests;
+ let sandbox;
+
+ beforeEach(function () {
+ element = {
+ x: 0,
+ y: 0,
+
+ width: 0,
+ height: 0,
+
+ getBoundingClientRect: () => {
+ return {
+ width: element.width,
+ height: element.height,
+
+ left: element.x,
+ top: element.y,
+ right: element.x + element.width,
+ bottom: element.y + element.height
+ };
+ }
+ };
+ win = {
+ document: {
+ visibilityState: 'visible'
+ },
+
+ innerWidth: 800,
+ innerHeight: 600
+ };
+ bidRequests = [{
+ 'bidder': 'oms',
+ 'params': {
+ 'publisherId': 1234567
+ },
+ 'adUnitCode': 'adunit-code',
+ 'mediaTypes': {
+ 'banner': {
+ 'sizes': [[300, 250], [300, 600]]
+ }
+ },
+ 'bidId': '5fb26ac22bde4',
+ 'bidderRequestId': '4bf93aeb730cb9',
+ 'auctionId': 'ffe9a1f7-7b67-4bda-a8e0-9ee5dc9f442e',
+ 'schain': {
+ 'ver': '1.0',
+ 'complete': 1,
+ 'nodes': [
+ {
+ 'asi': 'exchange1.com',
+ 'sid': '1234',
+ 'hp': 1,
+ 'rid': 'bid-request-1',
+ 'name': 'publisher',
+ 'domain': 'publisher.com'
+ }
+ ]
+ },
+ }];
+
+ sandbox = sinon.sandbox.create();
+ sandbox.stub(document, 'getElementById').withArgs('adunit-code').returns(element);
+ sandbox.stub(utils, 'getWindowTop').returns(win);
+ sandbox.stub(utils, 'getWindowSelf').returns(win);
+ });
+
+ afterEach(function () {
+ sandbox.restore();
+ });
+
+ describe('isBidRequestValid', function () {
+ let bid = {
+ 'bidder': 'oms',
+ 'params': {
+ 'publisherId': 1234567
+ },
+ 'adUnitCode': 'adunit-code',
+ 'mediaTypes': {
+ 'banner': {
+ 'sizes': [[300, 250], [300, 600]]
+ }
+ },
+ 'bidId': '5fb26ac22bde4',
+ 'bidderRequestId': '4bf93aeb730cb9',
+ 'auctionId': 'ffe9a1f7-7b67-4bda-a8e0-9ee5dc9f442e',
+ };
+
+ it('should return true when required params found', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+
+ it('should return false when publisherId not passed correctly', function () {
+ bid.params.publisherId = undefined;
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+
+ it('should return false when require params are not passed', function () {
+ let bid = Object.assign({}, bid);
+ bid.params = {};
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', function () {
+ it('sends bid request to our endpoint via POST', function () {
+ const request = spec.buildRequests(bidRequests);
+ expect(request.method).to.equal('POST');
+ });
+
+ it('request url should match our endpoint url', function () {
+ const request = spec.buildRequests(bidRequests);
+ expect(request.url).to.equal(URL);
+ });
+
+ it('sets the proper banner object', function () {
+ const request = spec.buildRequests(bidRequests);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}, {w: 300, h: 600}]);
+ });
+
+ it('accepts a single array as a size', function () {
+ bidRequests[0].mediaTypes.banner.sizes = [300, 250];
+ const request = spec.buildRequests(bidRequests);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}]);
+ });
+
+ it('sends bidfloor param if present', function () {
+ bidRequests[0].params.bidFloor = 0.05;
+ const request = spec.buildRequests(bidRequests);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].bidfloor).to.equal(0.05);
+ });
+
+ it('sends tagid', function () {
+ const request = spec.buildRequests(bidRequests);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].tagid).to.equal('adunit-code');
+ });
+
+ it('sends publisher id', function () {
+ const request = spec.buildRequests(bidRequests);
+ const payload = JSON.parse(request.data);
+ expect(payload.site.publisher.id).to.equal(1234567);
+ });
+
+ it('sends gdpr info if exists', function () {
+ const consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A==';
+ const bidderRequest = {
+ 'bidderCode': 'oms',
+ 'auctionId': '1d1a030790a437',
+ 'bidderRequestId': '22edbae2744bf5',
+ 'timeout': 3000,
+ gdprConsent: {
+ consentString: consentString,
+ gdprApplies: true
+ },
+ refererInfo: {
+ page: 'http://example.com/page.html',
+ domain: 'example.com',
+ }
+ };
+ bidderRequest.bids = bidRequests;
+
+ const data = JSON.parse(spec.buildRequests(bidRequests, bidderRequest).data);
+
+ expect(data.regs.ext.gdpr).to.exist.and.to.be.a('number');
+ expect(data.regs.ext.gdpr).to.equal(1);
+ expect(data.user.ext.consent).to.exist.and.to.be.a('string');
+ expect(data.user.ext.consent).to.equal(consentString);
+ });
+
+ it('sends coppa', function () {
+ const data = JSON.parse(spec.buildRequests(bidRequests, {ortb2: {regs: {coppa: 1}}}).data)
+ expect(data.regs).to.not.be.undefined;
+ expect(data.regs.coppa).to.equal(1);
+ });
+
+ it('sends schain', function () {
+ const data = JSON.parse(spec.buildRequests(bidRequests).data);
+ expect(data).to.not.be.undefined;
+ expect(data.source).to.not.be.undefined;
+ expect(data.source.ext).to.not.be.undefined;
+ expect(data.source.ext.schain).to.not.be.undefined;
+ expect(data.source.ext.schain.complete).to.equal(1);
+ expect(data.source.ext.schain.ver).to.equal('1.0');
+ expect(data.source.ext.schain.nodes).to.not.be.undefined;
+ expect(data.source.ext.schain.nodes).to.lengthOf(1);
+ expect(data.source.ext.schain.nodes[0].asi).to.equal('exchange1.com');
+ expect(data.source.ext.schain.nodes[0].sid).to.equal('1234');
+ expect(data.source.ext.schain.nodes[0].hp).to.equal(1);
+ expect(data.source.ext.schain.nodes[0].rid).to.equal('bid-request-1');
+ expect(data.source.ext.schain.nodes[0].name).to.equal('publisher');
+ expect(data.source.ext.schain.nodes[0].domain).to.equal('publisher.com');
+ });
+
+ it('sends user eid parameters', function () {
+ bidRequests[0].userIdAsEids = [{
+ source: 'pubcid.org',
+ uids: [{
+ id: 'userid_pubcid'
+ }]
+ }, {
+ source: 'adserver.org',
+ uids: [{
+ id: 'userid_ttd',
+ ext: {
+ rtiPartner: 'TDID'
+ }
+ }]
+ }
+ ];
+
+ const data = JSON.parse(spec.buildRequests(bidRequests).data);
+
+ expect(data.user).to.not.be.undefined;
+ expect(data.user.ext).to.not.be.undefined;
+ expect(data.user.ext.eids).to.not.be.undefined;
+ expect(data.user.ext.eids).to.deep.equal(bidRequests[0].userIdAsEids);
+ });
+
+ it('sends user id parameters', function () {
+ const userId = {
+ sharedid: {
+ id: '01*******',
+ third: '01E*******'
+ }
+ };
+
+ bidRequests[0].userId = userId;
+
+ const data = JSON.parse(spec.buildRequests(bidRequests).data);
+ expect(data.user).to.not.be.undefined;
+ expect(data.user.ext).to.not.be.undefined;
+ expect(data.user.ext.ids).is.deep.equal(userId);
+ });
+
+ it('sends gpid parameters', function () {
+ bidRequests[0].ortb2Imp = {
+ 'ext': {
+ 'gpid': '/1111/home-left',
+ 'data': {
+ 'adserver': {
+ 'name': 'gam',
+ 'adslot': '/1111/home'
+ },
+ 'pbadslot': '/1111/home-left'
+ }
+ }
+ }
+
+ const data = JSON.parse(spec.buildRequests(bidRequests).data);
+ expect(data.imp[0].ext).to.not.be.undefined;
+ expect(data.imp[0].ext.gpid).to.not.be.undefined;
+ expect(data.imp[0].ext.adserverName).to.not.be.undefined;
+ expect(data.imp[0].ext.adslot).to.not.be.undefined;
+ expect(data.imp[0].ext.pbadslot).to.not.be.undefined;
+ });
+
+ context('when element is fully in view', function () {
+ it('returns 100', function () {
+ Object.assign(element, {width: 600, height: 400});
+ const request = spec.buildRequests(bidRequests);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].banner.ext.viewability).to.equal(100);
+ });
+ });
+
+ context('when element is out of view', function () {
+ it('returns 0', function () {
+ Object.assign(element, {x: -300, y: 0, width: 207, height: 320});
+ const request = spec.buildRequests(bidRequests);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].banner.ext.viewability).to.equal(0);
+ });
+ });
+
+ context('when element is partially in view', function () {
+ it('returns percentage', function () {
+ Object.assign(element, {width: 800, height: 800});
+ const request = spec.buildRequests(bidRequests);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].banner.ext.viewability).to.equal(75);
+ });
+ });
+
+ context('when width or height of the element is zero', function () {
+ it('try to use alternative values', function () {
+ Object.assign(element, {width: 0, height: 0});
+ bidRequests[0].mediaTypes.banner.sizes = [[800, 2400]];
+ const request = spec.buildRequests(bidRequests);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].banner.ext.viewability).to.equal(25);
+ });
+ });
+
+ context('when nested iframes', function () {
+ it('returns \'na\'', function () {
+ Object.assign(element, {width: 600, height: 400});
+
+ utils.getWindowTop.restore();
+ utils.getWindowSelf.restore();
+ sandbox.stub(utils, 'getWindowTop').returns(win);
+ sandbox.stub(utils, 'getWindowSelf').returns({});
+
+ const request = spec.buildRequests(bidRequests);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].banner.ext.viewability).to.equal('na');
+ });
+ });
+
+ context('when tab is inactive', function () {
+ it('returns 0', function () {
+ Object.assign(element, {width: 600, height: 400});
+
+ utils.getWindowTop.restore();
+ win.document.visibilityState = 'hidden';
+ sandbox.stub(utils, 'getWindowTop').returns(win);
+
+ const request = spec.buildRequests(bidRequests);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].banner.ext.viewability).to.equal(0);
+ });
+ });
+ });
+
+ describe('interpretResponse', function () {
+ let response;
+ beforeEach(function () {
+ response = {
+ body: {
+ 'id': '37386aade21a71',
+ 'seatbid': [{
+ 'bid': [{
+ 'id': '376874781',
+ 'impid': '283a9f4cd2415d',
+ 'price': 0.35743275,
+ 'nurl': '',
+ 'adm': '',
+ 'w': 300,
+ 'h': 250,
+ 'adomain': ['example.com']
+ }]
+ }]
+ }
+ };
+ });
+
+ it('should get the correct bid response', function () {
+ let expectedResponse = [{
+ 'requestId': '283a9f4cd2415d',
+ 'cpm': 0.35743275,
+ 'width': 300,
+ 'height': 250,
+ 'creativeId': '376874781',
+ 'currency': 'USD',
+ 'netRevenue': true,
+ 'mediaType': 'banner',
+ 'ad': `
`,
+ 'ttl': 300,
+ 'meta': {
+ 'advertiserDomains': ['example.com']
+ }
+ }];
+
+ let result = spec.interpretResponse(response);
+ expect(result[0]).to.deep.equal(expectedResponse[0]);
+ });
+
+ it('crid should default to the bid id if not on the response', function () {
+ let expectedResponse = [{
+ 'requestId': '283a9f4cd2415d',
+ 'cpm': 0.35743275,
+ 'width': 300,
+ 'height': 250,
+ 'creativeId': response.body.seatbid[0].bid[0].id,
+ 'currency': 'USD',
+ 'netRevenue': true,
+ 'mediaType': 'banner',
+ 'ad': `
`,
+ 'ttl': 300,
+ 'meta': {
+ 'advertiserDomains': ['example.com']
+ }
+ }];
+
+ let result = spec.interpretResponse(response);
+ expect(result[0]).to.deep.equal(expectedResponse[0]);
+ });
+
+ it('handles empty bid response', function () {
+ let response = {
+ body: ''
+ };
+ let result = spec.interpretResponse(response);
+ expect(result.length).to.equal(0);
+ });
+ });
+
+ describe('getUserSyncs ', () => {
+ let syncOptions = {iframeEnabled: true, pixelEnabled: true};
+
+ it('should not return', () => {
+ let returnStatement = spec.getUserSyncs(syncOptions, []);
+ expect(returnStatement).to.be.empty;
+ });
+ });
+});
diff --git a/test/spec/modules/onetagBidAdapter_spec.js b/test/spec/modules/onetagBidAdapter_spec.js
index df6456db82e..93db5ffc57f 100644
--- a/test/spec/modules/onetagBidAdapter_spec.js
+++ b/test/spec/modules/onetagBidAdapter_spec.js
@@ -15,9 +15,14 @@ describe('onetag', function () {
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
'auctionId': '1d1a030790a475',
- ortb2Imp: {
- ext: {
- tid: 'qwerty123'
+ 'ortb2Imp': {
+ 'ext': {
+ 'tid': '0000'
+ }
+ },
+ 'ortb2': {
+ 'source': {
+ 'tid': '1111'
}
},
'schain': {
@@ -184,7 +189,7 @@ describe('onetag', function () {
});
it('Should contain all keys', function () {
expect(data).to.be.an('object');
- expect(data).to.include.all.keys('location', 'referrer', 'stack', 'numIframes', 'sHeight', 'sWidth', 'docHeight', 'wHeight', 'wWidth', 'oHeight', 'oWidth', 'aWidth', 'aHeight', 'sLeft', 'sTop', 'hLength', 'bids', 'docHidden', 'xOffset', 'yOffset', 'networkConnectionType', 'networkEffectiveConnectionType', 'timing', 'version');
+ expect(data).to.include.all.keys('location', 'referrer', 'stack', 'numIframes', 'sHeight', 'sWidth', 'docHeight', 'wHeight', 'wWidth', 'oHeight', 'oWidth', 'aWidth', 'aHeight', 'sLeft', 'sTop', 'hLength', 'bids', 'docHidden', 'xOffset', 'yOffset', 'networkConnectionType', 'networkEffectiveConnectionType', 'timing', 'version', 'fledgeEnabled');
expect(data.location).to.satisfy(function (value) {
return value === null || typeof value === 'string';
});
@@ -208,6 +213,7 @@ describe('onetag', function () {
expect(data.networkEffectiveConnectionType).to.satisfy(function (value) {
return value === null || typeof value === 'string'
});
+ expect(data.fledgeEnabled).to.be.a('boolean');
expect(data.bids).to.be.an('array');
expect(data.version).to.have.all.keys('prebid', 'adapter');
const bids = data['bids'];
@@ -256,8 +262,18 @@ describe('onetag', function () {
expect(dataObj.bids).to.be.an('array').that.is.empty;
} catch (e) { }
});
+ it('Should pick each bid\'s auctionId and transactionId from ortb2 related fields', function () {
+ const serverRequest = spec.buildRequests([bannerBid]);
+ const payload = JSON.parse(serverRequest.data);
+
+ expect(payload).to.exist;
+ expect(payload.bids).to.exist.and.to.have.length(1);
+ expect(payload.bids[0].auctionId).to.equal(bannerBid.ortb2.source.tid);
+ expect(payload.bids[0].transactionId).to.equal(bannerBid.ortb2Imp.ext.tid);
+ });
it('should send GDPR consent data', function () {
let consentString = 'consentString';
+ let addtlConsent = '2~1.35.41.101~dv.9.21.81';
let bidderRequest = {
'bidderCode': 'onetag',
'auctionId': '1d1a030790a475',
@@ -265,7 +281,8 @@ describe('onetag', function () {
'timeout': 3000,
'gdprConsent': {
consentString: consentString,
- gdprApplies: true
+ gdprApplies: true,
+ addtlConsent: addtlConsent
}
};
let serverRequest = spec.buildRequests([bannerBid], bidderRequest);
@@ -274,6 +291,7 @@ describe('onetag', function () {
expect(payload).to.exist;
expect(payload.gdprConsent).to.exist;
expect(payload.gdprConsent.consentString).to.exist.and.to.equal(consentString);
+ expect(payload.gdprConsent.addtlConsent).to.exist.and.to.equal(addtlConsent);
expect(payload.gdprConsent.consentRequired).to.exist.and.to.be.true;
});
it('Should send GPP consent data', function () {
@@ -381,14 +399,90 @@ describe('onetag', function () {
expect(payload.ortb2).to.exist;
expect(payload.ortb2).to.exist.and.to.deep.equal(firtPartyData);
});
+ it('Should send DSA (ortb2 field)', function () {
+ const dsa = {
+ 'regs': {
+ 'ext': {
+ 'dsa': {
+ 'required': 1,
+ 'pubrender': 0,
+ 'datatopub': 1,
+ 'transparency': [{
+ 'domain': 'dsa-domain',
+ 'params': [1, 2]
+ }]
+ }
+ }
+ }
+ };
+ let bidderRequest = {
+ 'bidderCode': 'onetag',
+ 'auctionId': '1d1a030790a475',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'timeout': 3000,
+ 'ortb2': dsa
+ }
+ let serverRequest = spec.buildRequests([bannerBid], bidderRequest);
+ const payload = JSON.parse(serverRequest.data);
+ expect(payload.ortb2).to.exist;
+ expect(payload.ortb2).to.exist.and.to.deep.equal(dsa);
+ });
+ it('Should send FLEDGE eligibility flag when FLEDGE is enabled', function () {
+ let bidderRequest = {
+ 'bidderCode': 'onetag',
+ 'auctionId': '1d1a030790a475',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'timeout': 3000,
+ 'fledgeEnabled': true
+ };
+ let serverRequest = spec.buildRequests([bannerBid], bidderRequest);
+ const payload = JSON.parse(serverRequest.data);
+
+ expect(payload.fledgeEnabled).to.exist;
+ expect(payload.fledgeEnabled).to.exist.and.to.equal(bidderRequest.fledgeEnabled);
+ });
+ it('Should send FLEDGE eligibility flag when FLEDGE is not enabled', function () {
+ let bidderRequest = {
+ 'bidderCode': 'onetag',
+ 'auctionId': '1d1a030790a475',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'timeout': 3000,
+ 'fledgeEnabled': false
+ };
+ let serverRequest = spec.buildRequests([bannerBid], bidderRequest);
+ const payload = JSON.parse(serverRequest.data);
+
+ expect(payload.fledgeEnabled).to.exist;
+ expect(payload.fledgeEnabled).to.exist.and.to.equal(bidderRequest.fledgeEnabled);
+ });
+ it('Should send FLEDGE eligibility flag set to false when fledgeEnabled is not defined', function () {
+ let bidderRequest = {
+ 'bidderCode': 'onetag',
+ 'auctionId': '1d1a030790a475',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'timeout': 3000,
+ };
+ let serverRequest = spec.buildRequests([bannerBid], bidderRequest);
+ const payload = JSON.parse(serverRequest.data);
+
+ expect(payload.fledgeEnabled).to.exist;
+ expect(payload.fledgeEnabled).to.exist.and.to.equal(false);
+ });
});
describe('interpretResponse', function () {
const request = getBannerVideoRequest();
const response = getBannerVideoResponse();
+ const fledgeResponse = getFledgeBannerResponse();
const requestData = JSON.parse(request.data);
it('Returns an array of valid server responses if response object is valid', function () {
const interpretedResponse = spec.interpretResponse(response, request);
+ const fledgeInterpretedResponse = spec.interpretResponse(fledgeResponse, request);
expect(interpretedResponse).to.be.an('array').that.is.not.empty;
+ expect(fledgeInterpretedResponse).to.be.an('object');
+ expect(fledgeInterpretedResponse.bids).to.satisfy(function (value) {
+ return value === null || Array.isArray(value);
+ });
+ expect(fledgeInterpretedResponse.fledgeAuctionConfigs).to.be.an('array').that.is.not.empty;
for (let i = 0; i < interpretedResponse.length; i++) {
let dataItem = interpretedResponse[i];
expect(dataItem).to.include.all.keys('requestId', 'cpm', 'width', 'height', 'ttl', 'creativeId', 'netRevenue', 'currency', 'meta', 'dealId');
@@ -423,6 +517,21 @@ describe('onetag', function () {
const serverResponses = spec.interpretResponse('invalid_response', { data: '{}' });
expect(serverResponses).to.be.an('array').that.is.empty;
});
+ it('Returns meta dsa field if dsa field is present in response', function () {
+ const dsaResponseObj = {
+ 'behalf': 'Advertiser',
+ 'paid': 'Advertiser',
+ 'transparency': {
+ 'domain': 'dsp1domain.com',
+ 'params': [1, 2]
+ },
+ 'adrender': 1
+ };
+ const responseWithDsa = {...response};
+ responseWithDsa.body.bids.forEach(bid => bid.dsa = {...dsaResponseObj});
+ const serverResponse = spec.interpretResponse(responseWithDsa, request);
+ serverResponse.forEach(bid => expect(bid.meta.dsa).to.deep.equals(dsaResponseObj));
+ });
});
describe('getUserSyncs', function () {
const sync_endpoint = 'https://onetag-sys.com/usync/';
@@ -586,6 +695,24 @@ function getBannerVideoResponse() {
};
}
+function getFledgeBannerResponse() {
+ const bannerVideoResponse = getBannerVideoResponse();
+ bannerVideoResponse.body.fledgeAuctionConfigs = [
+ {
+ bidId: 'fledge',
+ config: {
+ seller: 'https://onetag-sys.com',
+ decisionLogicUrl:
+ 'https://onetag-sys.com/paapi/decision_logic.js',
+ interestGroupBuyers: [
+ 'https://onetag-sys.com'
+ ],
+ }
+ }
+ ]
+ return bannerVideoResponse;
+}
+
function getBannerVideoRequest() {
return {
data: JSON.stringify({
diff --git a/test/spec/modules/openwebBidAdapter_spec.js b/test/spec/modules/openwebBidAdapter_spec.js
index c515c21690a..5a0264f00b8 100644
--- a/test/spec/modules/openwebBidAdapter_spec.js
+++ b/test/spec/modules/openwebBidAdapter_spec.js
@@ -2,386 +2,624 @@ import { expect } from 'chai';
import { spec } from 'modules/openwebBidAdapter.js';
import { newBidder } from 'src/adapters/bidderFactory.js';
import { config } from 'src/config.js';
+import { BANNER, VIDEO } from '../../../src/mediaTypes.js';
+import * as utils from 'src/utils.js';
-const DEFAULT_ADATPER_REQ = { bidderCode: 'openweb' };
-const DISPLAY_REQUEST = {
- 'bidder': 'openweb',
- 'params': {
- 'aid': 12345
- },
- 'schain': { ver: 1 },
- 'userId': { criteo: 2 },
- 'mediaTypes': { 'banner': { 'sizes': [300, 250] } },
- 'bidderRequestId': '7101db09af0db2',
- 'auctionId': '2e41f65424c87c',
- 'adUnitCode': 'adunit-code',
- 'bidId': '84ab500420319d',
-};
-
-const VIDEO_REQUEST = {
- 'bidder': 'openweb',
- 'mediaTypes': {
- 'video': {
- 'playerSize': [[480, 360], [640, 480]]
- }
- },
- 'params': {
- 'aid': 12345
- },
- 'bidderRequestId': '7101db09af0db2',
- 'auctionId': '2e41f65424c87c',
- 'adUnitCode': 'adunit-code',
- 'bidId': '84ab500420319d'
-};
-
-const ADPOD_REQUEST = {
- 'bidder': 'openweb',
- 'mediaTypes': {
- 'video': {
- 'context': 'adpod',
- 'playerSize': [[640, 480]],
- 'anyField': 10
- }
- },
- 'params': {
- 'aid': 12345
- },
- 'bidderRequestId': '7101db09af0db2',
- 'auctionId': '2e41f65424c87c',
- 'adUnitCode': 'adunit-code',
- 'bidId': '2e41f65424c87c'
-};
-
-const SERVER_VIDEO_RESPONSE = {
- 'source': { 'aid': 12345, 'pubId': 54321 },
- 'bids': [{
- 'vastUrl': 'vastUrl',
- 'requestId': '2e41f65424c87c',
- 'url': '44F2AEB9BFC881B3',
- 'creative_id': 342516,
- 'durationSeconds': 30,
- 'cmpId': 342516,
- 'height': 480,
- 'cur': 'USD',
- 'width': 640,
- 'cpm': 0.9,
- 'adomain': ['a.com']
- }]
-};
-const SERVER_OUSTREAM_VIDEO_RESPONSE = SERVER_VIDEO_RESPONSE;
-const SERVER_DISPLAY_RESPONSE = {
- 'source': { 'aid': 12345, 'pubId': 54321 },
- 'bids': [{
- 'ad': '',
- 'adUrl': 'adUrl',
- 'requestId': '2e41f65424c87c',
- 'creative_id': 342516,
- 'cmpId': 342516,
- 'height': 250,
- 'cur': 'USD',
- 'width': 300,
- 'cpm': 0.9
- }],
- 'cookieURLs': ['link1', 'link2']
-};
-const SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS = {
- 'source': { 'aid': 12345, 'pubId': 54321 },
- 'bids': [{
- 'ad': '',
- 'requestId': '2e41f65424c87c',
- 'creative_id': 342516,
- 'cmpId': 342516,
- 'height': 250,
- 'cur': 'USD',
- 'width': 300,
- 'cpm': 0.9
- }],
- 'cookieURLs': ['link3', 'link4'],
- 'cookieURLSTypes': ['image', 'iframe']
-};
-
-const videoBidderRequest = {
- bidderCode: 'bidderCode',
- bids: [{ mediaTypes: { video: {} }, bidId: '2e41f65424c87c' }]
-};
-
-const displayBidderRequest = {
- bidderCode: 'bidderCode',
- bids: [{ bidId: '2e41f65424c87c' }]
-};
-
-const displayBidderRequestWithConsents = {
- bidderCode: 'bidderCode',
- bids: [{ bidId: '2e41f65424c87c' }],
- gdprConsent: {
- gdprApplies: true,
- consentString: 'test'
- },
- uspConsent: 'iHaveIt'
-};
-
-const videoEqResponse = [{
- vastUrl: 'vastUrl',
- requestId: '2e41f65424c87c',
- creativeId: 342516,
- mediaType: 'video',
- netRevenue: true,
- currency: 'USD',
- height: 480,
- width: 640,
- ttl: 300,
- cpm: 0.9,
- meta: {
- advertiserDomains: ['a.com']
- }
-}];
-
-const displayEqResponse = [{
- requestId: '2e41f65424c87c',
- creativeId: 342516,
- mediaType: 'banner',
- netRevenue: true,
- currency: 'USD',
- ad: '',
- adUrl: 'adUrl',
- height: 250,
- width: 300,
- ttl: 300,
- cpm: 0.9,
- meta: {
- advertiserDomains: []
- }
-
-}];
-
-describe('openwebBidAdapter', () => {
+const ENDPOINT = 'https://hb.openwebmp.com/hb-multi';
+const TEST_ENDPOINT = 'https://hb.openwebmp.com/hb-multi-test';
+const TTL = 360;
+/* eslint no-console: ["error", { allow: ["log", "warn", "error"] }] */
+
+describe('openwebAdapter', function () {
const adapter = newBidder(spec);
- describe('inherited functions', () => {
- it('exists and is a function', () => {
+
+ describe('inherited functions', function () {
+ it('exists and is a function', function () {
expect(adapter.callBids).to.exist.and.to.be.a('function');
});
});
- describe('user syncs', () => {
- describe('as image', () => {
- it('should be returned if pixel enabled', () => {
- const syncs = spec.getUserSyncs({ pixelEnabled: true }, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]);
-
- expect(syncs.map(s => s.url)).to.deep.equal([SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS.cookieURLs[0]]);
- expect(syncs.map(s => s.type)).to.deep.equal(['image']);
- })
- })
+ describe('isBidRequestValid', function () {
+ const bid = {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [['640', '480']],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ }
+ };
+
+ it('should return true when required params are passed', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
- describe('as iframe', () => {
- it('should be returned if iframe enabled', () => {
- const syncs = spec.getUserSyncs({ iframeEnabled: true }, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]);
+ it('should return false when required params are not found', function () {
+ const newBid = Object.assign({}, bid);
+ delete newBid.params;
+ newBid.params = {
+ 'org': null
+ };
+ expect(spec.isBidRequestValid(newBid)).to.equal(false);
+ });
+ });
- expect(syncs.map(s => s.url)).to.deep.equal([SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS.cookieURLs[1]]);
- expect(syncs.map(s => s.type)).to.deep.equal(['iframe']);
- })
- })
+ describe('buildRequests', function () {
+ const bidRequests = [
+ {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[640, 480]],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ },
+ 'bidId': '299ffc8cca0b87',
+ 'loop': 1,
+ 'bidderRequestId': '1144f487e563f9',
+ 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d',
+ 'mediaTypes': {
+ 'video': {
+ 'playerSize': [[640, 480]],
+ 'context': 'instream',
+ 'plcmt': 1
+ }
+ },
+ 'vastXml': '"
... "'
+ },
+ {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[300, 250]],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ },
+ 'bidId': '299ffc8cca0b87',
+ 'loop': 1,
+ 'bidderRequestId': '1144f487e563f9',
+ 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d',
+ 'mediaTypes': {
+ 'banner': {
+ }
+ },
+ 'ad': '"
"'
+ }
+ ];
+
+ const testModeBidRequests = [
+ {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[640, 480]],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001',
+ 'testMode': true
+ },
+ 'bidId': '299ffc8cca0b87',
+ 'loop': 2,
+ 'bidderRequestId': '1144f487e563f9',
+ 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d',
+ }
+ ];
+
+ const bidderRequest = {
+ bidderCode: 'openweb',
+ }
+ const placementId = '12345678';
+ const api = [1, 2];
+ const mimes = ['application/javascript', 'video/mp4', 'video/quicktime'];
+ const protocols = [2, 3, 5, 6];
+
+ it('sends the placementId to ENDPOINT via POST', function () {
+ bidRequests[0].params.placementId = placementId;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].placementId).to.equal(placementId);
+ });
- describe('user sync', () => {
- it('should not be returned if passed syncs where already used', () => {
- const syncs = spec.getUserSyncs({
- iframeEnabled: true,
- pixelEnabled: true
- }, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]);
+ it('sends the plcmt to ENDPOINT via POST', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].plcmt).to.equal(1);
+ });
- expect(syncs).to.deep.equal([]);
- })
+ it('sends the is_wrapper parameter to ENDPOINT via POST', function() {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('is_wrapper');
+ expect(request.data.params.is_wrapper).to.equal(false);
+ });
- it('should not be returned if pixel not set', () => {
- const syncs = spec.getUserSyncs({}, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]);
+ it('sends bid request to ENDPOINT via POST', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.url).to.equal(ENDPOINT);
+ expect(request.method).to.equal('POST');
+ });
- expect(syncs).to.be.empty;
- });
+ it('sends bid request to TEST ENDPOINT via POST', function () {
+ const request = spec.buildRequests(testModeBidRequests, bidderRequest);
+ expect(request.url).to.equal(TEST_ENDPOINT);
+ expect(request.method).to.equal('POST');
});
- describe('user syncs with both types', () => {
- it('should be returned if pixel and iframe enabled', () => {
- const mockedServerResponse = Object.assign({}, SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS, { 'cookieURLs': ['link5', 'link6'] });
- const syncs = spec.getUserSyncs({
- iframeEnabled: true,
- pixelEnabled: true
- }, [{ body: mockedServerResponse }]);
- expect(syncs.map(s => s.url)).to.deep.equal(mockedServerResponse.cookieURLs);
- expect(syncs.map(s => s.type)).to.deep.equal(mockedServerResponse.cookieURLSTypes);
- });
+ it('should send the correct bid Id', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].bidId).to.equal('299ffc8cca0b87');
});
- });
- describe('isBidRequestValid', () => {
- it('should return true when required params found', () => {
- expect(spec.isBidRequestValid(VIDEO_REQUEST)).to.equal(true);
+ it('should send the correct supported api array', function () {
+ bidRequests[0].mediaTypes.video.api = api;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].api).to.be.an('array');
+ expect(request.data.bids[0].api).to.eql([1, 2]);
});
- it('should return false when required params are not passed', () => {
- let bid = Object.assign({}, VIDEO_REQUEST);
- delete bid.params;
- expect(spec.isBidRequestValid(bid)).to.equal(false);
+ it('should send the correct mimes array', function () {
+ bidRequests[1].mediaTypes.banner.mimes = mimes;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[1].mimes).to.be.an('array');
+ expect(request.data.bids[1].mimes).to.eql(['application/javascript', 'video/mp4', 'video/quicktime']);
});
- });
- describe('buildRequests', () => {
- let videoBidRequests = [VIDEO_REQUEST];
- let displayBidRequests = [DISPLAY_REQUEST];
- let videoAndDisplayBidRequests = [DISPLAY_REQUEST, VIDEO_REQUEST];
- const displayRequest = spec.buildRequests(displayBidRequests, DEFAULT_ADATPER_REQ);
- const videoRequest = spec.buildRequests(videoBidRequests, DEFAULT_ADATPER_REQ);
- const videoAndDisplayRequests = spec.buildRequests(videoAndDisplayBidRequests, DEFAULT_ADATPER_REQ);
-
- it('building requests as arrays', () => {
- expect(videoRequest).to.be.a('array');
- expect(displayRequest).to.be.a('array');
- expect(videoAndDisplayRequests).to.be.a('array');
- })
+ it('should send the correct protocols array', function () {
+ bidRequests[0].mediaTypes.video.protocols = protocols;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].protocols).to.be.an('array');
+ expect(request.data.bids[0].protocols).to.eql([2, 3, 5, 6]);
+ });
- it('sending as POST', () => {
- const postActionMethod = 'POST'
- const comparator = br => br.method === postActionMethod;
- expect(videoRequest.every(comparator)).to.be.true;
- expect(displayRequest.every(comparator)).to.be.true;
- expect(videoAndDisplayRequests.every(comparator)).to.be.true;
- });
- it('forms correct ADPOD request', () => {
- const pbBidReqData = spec.buildRequests([ADPOD_REQUEST], DEFAULT_ADATPER_REQ)[0].data;
- const impRequest = pbBidReqData.BidRequests[0]
- expect(impRequest.AdType).to.be.equal('video');
- expect(impRequest.Adpod).to.be.a('object');
- expect(impRequest.Adpod.anyField).to.be.equal(10);
- })
- it('sends correct video bid parameters', () => {
- const data = videoRequest[0].data;
-
- const eq = {
- CallbackId: '84ab500420319d',
- AdType: 'video',
- Aid: 12345,
- Sizes: '480x360,640x480',
- PlacementId: 'adunit-code'
- };
- expect(data.BidRequests[0]).to.deep.equal(eq);
+ it('should send the correct sizes array', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].sizes).to.be.an('array');
+ expect(request.data.bids[0].sizes).to.equal(bidRequests[0].sizes)
+ expect(request.data.bids[1].sizes).to.be.an('array');
+ expect(request.data.bids[1].sizes).to.equal(bidRequests[1].sizes)
});
- it('sends correct display bid parameters', () => {
- const data = displayRequest[0].data;
+ it('should send the correct media type', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].mediaType).to.equal(VIDEO)
+ expect(request.data.bids[1].mediaType).to.equal(BANNER)
+ });
- const eq = {
- CallbackId: '84ab500420319d',
- AdType: 'display',
- Aid: 12345,
- Sizes: '300x250',
- PlacementId: 'adunit-code'
+ it('should send the correct currency in bid request', function () {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.params = {
+ 'currency': 'EUR'
};
+ const expectedCurrency = bid.params.currency;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0].currency).to.equal(expectedCurrency);
+ });
- expect(data.BidRequests[0]).to.deep.equal(eq);
- });
-
- it('sends correct video and display bid parameters', () => {
- const bidRequests = videoAndDisplayRequests[0].data;
- const expectedBidReqs = [{
- CallbackId: '84ab500420319d',
- AdType: 'display',
- Aid: 12345,
- Sizes: '300x250',
- PlacementId: 'adunit-code'
- }, {
- CallbackId: '84ab500420319d',
- AdType: 'video',
- Aid: 12345,
- Sizes: '480x360,640x480',
- PlacementId: 'adunit-code'
- }]
+ it('should respect syncEnabled option', function() {
+ config.setConfig({
+ userSync: {
+ syncEnabled: false,
+ filterSettings: {
+ all: {
+ bidders: '*',
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('cs_method');
+ });
- expect(bidRequests.BidRequests).to.deep.equal(expectedBidReqs);
+ it('should respect "iframe" filter settings', function () {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ iframe: {
+ bidders: [spec.code],
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'iframe');
});
- describe('publisher environment', () => {
- const sandbox = sinon.sandbox.create();
- sandbox.stub(config, 'getConfig').callsFake((key) => {
- const config = {
- 'coppa': true
- };
- return config[key];
+ it('should respect "all" filter settings', function () {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ all: {
+ bidders: [spec.code],
+ filter: 'include'
+ }
+ }
+ }
});
- const bidRequestWithPubSettingsData = spec.buildRequests([DISPLAY_REQUEST], displayBidderRequestWithConsents)[0].data;
- sandbox.restore();
- it('sets GDPR', () => {
- expect(bidRequestWithPubSettingsData.GDPR).to.be.equal(1);
- expect(bidRequestWithPubSettingsData.GDPRConsent).to.be.equal(displayBidderRequestWithConsents.gdprConsent.consentString);
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'iframe');
+ });
+
+ it('should send the pixel user sync param if userSync is enabled and no "iframe" or "all" configs are present', function () {
+ config.resetConfig();
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ }
});
- it('sets USP', () => {
- expect(bidRequestWithPubSettingsData.USP).to.be.equal(displayBidderRequestWithConsents.uspConsent);
- })
- it('sets Coppa', () => {
- expect(bidRequestWithPubSettingsData.Coppa).to.be.equal(1);
- })
- it('sets Schain', () => {
- expect(bidRequestWithPubSettingsData.Schain).to.be.deep.equal(DISPLAY_REQUEST.schain);
- })
- it('sets UserId\'s', () => {
- expect(bidRequestWithPubSettingsData.UserIds).to.be.deep.equal(DISPLAY_REQUEST.userId);
- })
- })
- });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'pixel');
+ });
- describe('interpretResponse', () => {
- let serverResponse;
- let adapterRequest;
- let eqResponse;
+ it('should respect total exclusion', function() {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ image: {
+ bidders: [spec.code],
+ filter: 'exclude'
+ },
+ iframe: {
+ bidders: [spec.code],
+ filter: 'exclude'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('cs_method');
+ });
- afterEach(() => {
- serverResponse = null;
- adapterRequest = null;
- eqResponse = null;
+ it('should have us_privacy param if usPrivacy is available in the bidRequest', function () {
+ const bidderRequestWithUSP = Object.assign({uspConsent: '1YNN'}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithUSP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('us_privacy', '1YNN');
});
- it('should get correct video bid response', () => {
- serverResponse = SERVER_VIDEO_RESPONSE;
- adapterRequest = videoBidderRequest;
- eqResponse = videoEqResponse;
+ it('should have an empty us_privacy param if usPrivacy is missing in the bidRequest', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('us_privacy');
+ });
- bidServerResponseCheck();
+ it('should not send the gdpr param if gdprApplies is false in the bidRequest', function () {
+ const bidderRequestWithGDPR = Object.assign({gdprConsent: {gdprApplies: false}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('gdpr');
+ expect(request.data.params).to.not.have.property('gdpr_consent');
});
- it('should get correct display bid response', () => {
- serverResponse = SERVER_DISPLAY_RESPONSE;
- adapterRequest = displayBidderRequest;
- eqResponse = displayEqResponse;
+ it('should send the gdpr param if gdprApplies is true in the bidRequest', function () {
+ const bidderRequestWithGDPR = Object.assign({gdprConsent: {gdprApplies: true, consentString: 'test-consent-string'}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('gdpr', true);
+ expect(request.data.params).to.have.property('gdpr_consent', 'test-consent-string');
+ });
- bidServerResponseCheck();
+ it('should not send the gpp param if gppConsent is false in the bidRequest', function () {
+ const bidderRequestWithGPP = Object.assign({gppConsent: false}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGPP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('gpp');
+ expect(request.data.params).to.not.have.property('gpp_sid');
});
- function bidServerResponseCheck() {
- const result = spec.interpretResponse({ body: serverResponse }, { adapterRequest });
+ it('should send the gpp param if gppConsent is true in the bidRequest', function () {
+ const bidderRequestWithGPP = Object.assign({gppConsent: {gppString: 'test-consent-string', applicableSections: [7]}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGPP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('gpp', 'test-consent-string');
+ expect(request.data.params.gpp_sid[0]).to.be.equal(7);
+ });
- expect(result).to.deep.equal(eqResponse);
- }
+ it('should have schain param if it is available in the bidRequest', () => {
+ const schain = {
+ ver: '1.0',
+ complete: 1,
+ nodes: [{ asi: 'indirectseller.com', sid: '00001', hp: 1 }],
+ };
+ bidRequests[0].schain = schain;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('schain', '1.0,1!indirectseller.com,00001,1,,,');
+ });
+
+ it('should set flooPrice to getFloor.floor value if it is greater than params.floorPrice', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.getFloor = () => {
+ return {
+ currency: 'USD',
+ floor: 3.32
+ }
+ }
+ bid.params.floorPrice = 0.64;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0]).to.be.an('object');
+ expect(request.data.bids[0]).to.have.property('floorPrice', 3.32);
+ });
- function nobidServerResponseCheck() {
- const noBidServerResponse = { bids: [] };
- const noBidResult = spec.interpretResponse({ body: noBidServerResponse }, { adapterRequest });
+ it('should set floorPrice to params.floorPrice value if it is greater than getFloor.floor', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.getFloor = () => {
+ return {
+ currency: 'USD',
+ floor: 0.8
+ }
+ }
+ bid.params.floorPrice = 1.5;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0]).to.be.an('object');
+ expect(request.data.bids[0]).to.have.property('floorPrice', 1.5);
+ });
- expect(noBidResult.length).to.equal(0);
- }
+ it('should check sua param in bid request', function() {
+ const sua = {
+ 'platform': {
+ 'brand': 'macOS',
+ 'version': ['12', '4', '0']
+ },
+ 'browsers': [
+ {
+ 'brand': 'Chromium',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Google Chrome',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Not;A=Brand',
+ 'version': [ '99', '0', '0', '0' ]
+ }
+ ],
+ 'mobile': 0,
+ 'model': '',
+ 'bitness': '64',
+ 'architecture': 'x86'
+ }
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.ortb2 = {
+ 'device': {
+ 'sua': {
+ 'platform': {
+ 'brand': 'macOS',
+ 'version': [ '12', '4', '0' ]
+ },
+ 'browsers': [
+ {
+ 'brand': 'Chromium',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Google Chrome',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Not;A=Brand',
+ 'version': [ '99', '0', '0', '0' ]
+ }
+ ],
+ 'mobile': 0,
+ 'model': '',
+ 'bitness': '64',
+ 'architecture': 'x86'
+ }
+ }
+ }
+ const requestWithSua = spec.buildRequests([bid], bidderRequest);
+ const data = requestWithSua.data;
+ expect(data.bids[0].sua).to.exist;
+ expect(data.bids[0].sua).to.deep.equal(sua);
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].sua).to.not.exist;
+ });
+
+ describe('COPPA Param', function() {
+ it('should set coppa equal 0 in bid request if coppa is set to false', function() {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].coppa).to.be.equal(0);
+ });
+
+ it('should set coppa equal 1 in bid request if coppa is set to true', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.ortb2 = {
+ 'regs': {
+ 'coppa': true,
+ }
+ };
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0].coppa).to.be.equal(1);
+ });
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const response = {
+ params: {
+ currency: 'USD',
+ netRevenue: true,
+ },
+ bids: [{
+ cpm: 12.5,
+ vastXml: '
',
+ width: 640,
+ height: 480,
+ requestId: '21e12606d47ba7',
+ adomain: ['abc.com'],
+ mediaType: VIDEO
+ },
+ {
+ cpm: 12.5,
+ ad: '"
"',
+ width: 300,
+ height: 250,
+ requestId: '21e12606d47ba7',
+ adomain: ['abc.com'],
+ mediaType: BANNER
+ }]
+ };
+
+ const expectedVideoResponse = {
+ requestId: '21e12606d47ba7',
+ cpm: 12.5,
+ currency: 'USD',
+ width: 640,
+ height: 480,
+ ttl: TTL,
+ creativeId: '21e12606d47ba7',
+ netRevenue: true,
+ nurl: 'http://example.com/win/1234',
+ mediaType: VIDEO,
+ meta: {
+ mediaType: VIDEO,
+ advertiserDomains: ['abc.com']
+ },
+ vastXml: '
',
+ };
+
+ const expectedBannerResponse = {
+ requestId: '21e12606d47ba7',
+ cpm: 12.5,
+ currency: 'USD',
+ width: 640,
+ height: 480,
+ ttl: TTL,
+ creativeId: '21e12606d47ba7',
+ netRevenue: true,
+ nurl: 'http://example.com/win/1234',
+ mediaType: BANNER,
+ meta: {
+ mediaType: BANNER,
+ advertiserDomains: ['abc.com']
+ },
+ ad: '"
"'
+ };
+
+ it('should get correct bid response', function () {
+ const result = spec.interpretResponse({ body: response });
+ expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedVideoResponse));
+ expect(Object.keys(result[1])).to.deep.equal(Object.keys(expectedBannerResponse));
+ });
+
+ it('video type should have vastXml key', function () {
+ const result = spec.interpretResponse({ body: response });
+ expect(result[0].vastXml).to.equal(expectedVideoResponse.vastXml)
+ });
+
+ it('banner type should have ad key', function () {
+ const result = spec.interpretResponse({ body: response });
+ expect(result[1].ad).to.equal(expectedBannerResponse.ad)
+ });
+ })
+
+ describe('getUserSyncs', function() {
+ const imageSyncResponse = {
+ body: {
+ params: {
+ userSyncPixels: [
+ 'https://image-sync-url.test/1',
+ 'https://image-sync-url.test/2',
+ 'https://image-sync-url.test/3'
+ ]
+ }
+ }
+ };
+
+ const iframeSyncResponse = {
+ body: {
+ params: {
+ userSyncURL: 'https://iframe-sync-url.test'
+ }
+ }
+ };
+
+ it('should register all img urls from the response', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: true }, [imageSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/1'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/2'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/3'
+ }
+ ]);
+ });
- it('handles video nobid responses', () => {
- adapterRequest = videoBidderRequest;
+ it('should register the iframe url from the response', function() {
+ const syncs = spec.getUserSyncs({ iframeEnabled: true }, [iframeSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'iframe',
+ url: 'https://iframe-sync-url.test'
+ }
+ ]);
+ });
- nobidServerResponseCheck();
+ it('should register both image and iframe urls from the responses', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: true, iframeEnabled: true }, [iframeSyncResponse, imageSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'iframe',
+ url: 'https://iframe-sync-url.test'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/1'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/2'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/3'
+ }
+ ]);
});
- it('handles display nobid responses', () => {
- adapterRequest = displayBidderRequest;
+ it('should handle an empty response', function() {
+ const syncs = spec.getUserSyncs({ iframeEnabled: true }, []);
+ expect(syncs).to.deep.equal([]);
+ });
- nobidServerResponseCheck();
+ it('should handle when user syncs are disabled', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: false }, [imageSyncResponse]);
+ expect(syncs).to.deep.equal([]);
});
+ })
- it('forms correct ADPOD response', () => {
- const videoBids = spec.interpretResponse({ body: SERVER_VIDEO_RESPONSE }, { adapterRequest: { bids: [ADPOD_REQUEST] } });
- expect(videoBids[0].video.durationSeconds).to.be.equal(30);
- expect(videoBids[0].video.context).to.be.equal('adpod');
+ describe('onBidWon', function() {
+ beforeEach(function() {
+ sinon.stub(utils, 'triggerPixel');
+ });
+ afterEach(function() {
+ utils.triggerPixel.restore();
+ });
+
+ it('Should trigger pixel if bid nurl', function() {
+ const bid = {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [['640', '480']],
+ 'nurl': 'http://example.com/win/1234',
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ }
+ };
+
+ spec.onBidWon(bid);
+ expect(utils.triggerPixel.callCount).to.equal(1)
})
- });
+ })
});
diff --git a/test/spec/modules/openxBidAdapter_spec.js b/test/spec/modules/openxBidAdapter_spec.js
index f2cff7f470c..7c504bca50b 100644
--- a/test/spec/modules/openxBidAdapter_spec.js
+++ b/test/spec/modules/openxBidAdapter_spec.js
@@ -14,6 +14,7 @@ import 'modules/consentManagement.js';
import 'modules/consentManagementUsp.js';
import 'modules/schain.js';
import {deepClone} from 'src/utils.js';
+import {version} from 'package.json';
import {syncAddFPDToBidderRequest} from '../../helpers/fpd.js';
import {hook} from '../../../src/hook.js';
@@ -316,6 +317,7 @@ describe('OpenxRtbAdapter', function () {
const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
expect(request[0].url).to.equal(REQUEST_URL);
expect(request[0].method).to.equal('POST');
+ expect(request[0].data.ext.pv).to.equal(version);
});
it('should send delivery domain, if available', function () {
@@ -1506,6 +1508,25 @@ describe('OpenxRtbAdapter', function () {
expect(response.fledgeAuctionConfigs.length).to.equal(1);
expect(response.fledgeAuctionConfigs[0].bidId).to.equal('test-bid-id');
});
+
+ it('should inject ortb2Imp in auctionSignals', function () {
+ const auctionConfig = response.fledgeAuctionConfigs[0].config;
+ expect(auctionConfig).to.deep.include({
+ auctionSignals: {
+ ortb2Imp: {
+ id: 'test-bid-id',
+ tagid: '12345678',
+ banner: {
+ topframe: 0,
+ format: bidRequestConfigs[0].mediaTypes.banner.sizes.map(([w, h]) => ({w, h}))
+ },
+ ext: {
+ divid: 'adunit-code',
+ }
+ }
+ }
+ });
+ })
});
});
diff --git a/test/spec/modules/operaadsBidAdapter_spec.js b/test/spec/modules/operaadsBidAdapter_spec.js
index 37d4a2c7bc0..9a8981235d5 100644
--- a/test/spec/modules/operaadsBidAdapter_spec.js
+++ b/test/spec/modules/operaadsBidAdapter_spec.js
@@ -266,6 +266,95 @@ describe('Opera Ads Bid Adapter', function () {
}
});
+ describe('test fulfilling inventory information', function () {
+ const bidRequest = {
+ adUnitCode: 'test-div',
+ auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917',
+ bidId: '22c4871113f461',
+ bidder: 'operaads',
+ bidderRequestId: '15246a574e859f',
+ mediaTypes: {
+ banner: {sizes: [[300, 250]]}
+ },
+ params: {
+ placementId: 's12345678',
+ publisherId: 'pub12345678',
+ endpointId: 'ep12345678'
+ }
+ }
+
+ const getRequest = function () {
+ let reqs;
+ expect(function () {
+ reqs = spec.buildRequests([bidRequest], bidderRequest);
+ }).to.not.throw();
+ return JSON.parse(reqs[0].data);
+ }
+
+ it('test default case', function () {
+ let requestData = getRequest();
+ expect(requestData.site).to.be.an('object');
+ expect(requestData.site.id).to.equal(bidRequest.params.publisherId);
+ expect(requestData.site.domain).to.not.be.empty;
+ expect(requestData.site.page).to.equal(bidderRequest.refererInfo.page);
+ });
+
+ it('test a case with site information specified', function () {
+ bidRequest.params = {
+ placementId: 's12345678',
+ publisherId: 'pub12345678',
+ endpointId: 'ep12345678',
+ site: {
+ name: 'test-site-1',
+ domain: 'www.test.com'
+ }
+ }
+ let requestData = getRequest();
+ expect(requestData.site).to.be.an('object');
+ expect(requestData.site.id).to.equal(bidRequest.params.publisherId);
+ expect(requestData.site.name).to.equal('test-site-1');
+ expect(requestData.site.domain).to.equal('www.test.com');
+ expect(requestData.site.page).to.equal(bidderRequest.refererInfo.page);
+ });
+
+ it('test a case with app information specified', function () {
+ bidRequest.params = {
+ placementId: 's12345678',
+ publisherId: 'pub12345678',
+ endpointId: 'ep12345678',
+ app: {
+ name: 'test-app-1'
+ }
+ }
+ let requestData = getRequest();
+ expect(requestData.app).to.be.an('object');
+ expect(requestData.app.id).to.equal(bidRequest.params.publisherId);
+ expect(requestData.app.name).to.equal('test-app-1');
+ expect(requestData.app.domain).to.not.be.empty;
+ });
+
+ it('test a case with both site and app information specified', function () {
+ bidRequest.params = {
+ placementId: 's12345678',
+ publisherId: 'pub12345678',
+ endpointId: 'ep12345678',
+ site: {
+ name: 'test-site-2',
+ page: 'test-page'
+ },
+ app: {
+ name: 'test-app-1'
+ }
+ }
+ let requestData = getRequest();
+ expect(requestData.site).to.be.an('object');
+ expect(requestData.site.id).to.equal(bidRequest.params.publisherId);
+ expect(requestData.site.name).to.equal('test-site-2');
+ expect(requestData.site.page).to.equal('test-page');
+ expect(requestData.site.domain).to.not.be.empty;
+ });
+ });
+
it('test getBidFloor', function() {
const bidRequests = [
{
diff --git a/test/spec/modules/opscoBidAdapter_spec.js b/test/spec/modules/opscoBidAdapter_spec.js
new file mode 100644
index 00000000000..38cacff8f82
--- /dev/null
+++ b/test/spec/modules/opscoBidAdapter_spec.js
@@ -0,0 +1,260 @@
+import {expect} from 'chai';
+import {spec} from 'modules/opscoBidAdapter';
+import {newBidder} from 'src/adapters/bidderFactory.js';
+
+describe('opscoBidAdapter', function () {
+ const adapter = newBidder(spec);
+
+ describe('inherited functions', () => {
+ it('exists and is a function', () => {
+ expect(adapter.callBids).to.exist.and.to.be.a('function')
+ })
+ })
+
+ describe('isBidRequestValid', function () {
+ const validBid = {
+ bidder: 'opsco',
+ params: {
+ placementId: '123',
+ publisherId: '456'
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250]]
+ }
+ }
+ };
+
+ it('should return true when required params are present', function () {
+ expect(spec.isBidRequestValid(validBid)).to.be.true;
+ });
+
+ it('should return false when placementId is missing', function () {
+ const invalidBid = {...validBid};
+ delete invalidBid.params.placementId;
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+
+ it('should return false when publisherId is missing', function () {
+ const invalidBid = {...validBid};
+ delete invalidBid.params.publisherId;
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+
+ it('should return false when mediaTypes.banner.sizes is missing', function () {
+ const invalidBid = {...validBid};
+ delete invalidBid.mediaTypes.banner.sizes;
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+
+ it('should return false when mediaTypes.banner is missing', function () {
+ const invalidBid = {...validBid};
+ delete invalidBid.mediaTypes.banner;
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+
+ it('should return false when bid params are missing', function () {
+ const invalidBid = {bidder: 'opsco'};
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+
+ it('should return false when bid params are empty', function () {
+ const invalidBid = {bidder: 'opsco', params: {}};
+ expect(spec.isBidRequestValid(invalidBid)).to.be.false;
+ });
+ });
+
+ describe('buildRequests', function () {
+ let validBid, bidderRequest;
+
+ beforeEach(function () {
+ validBid = {
+ bidder: 'opsco',
+ params: {
+ placementId: '123',
+ publisherId: '456'
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250]]
+ }
+ }
+ };
+
+ bidderRequest = {
+ bidderRequestId: 'bid123',
+ refererInfo: {
+ domain: 'example.com',
+ page: 'https://example.com/page',
+ ref: 'https://referrer.com'
+ },
+ gdprConsent: {
+ consentString: 'GDPR_CONSENT_STRING',
+ gdprApplies: true
+ },
+ };
+ });
+
+ it('should return true when banner sizes are defined', function () {
+ expect(spec.isBidRequestValid(validBid)).to.be.true;
+ });
+
+ it('should return false when banner sizes are invalid', function () {
+ const invalidSizes = [
+ '2:1',
+ undefined,
+ 123,
+ 'undefined'
+ ];
+
+ invalidSizes.forEach((sizes) => {
+ validBid.mediaTypes.banner.sizes = sizes;
+ expect(spec.isBidRequestValid(validBid)).to.be.false;
+ });
+ });
+
+ it('should send GDPR consent in the payload if present', function () {
+ const request = spec.buildRequests([validBid], bidderRequest);
+ expect(JSON.parse(request.data).user.ext.consent).to.deep.equal('GDPR_CONSENT_STRING');
+ });
+
+ it('should send CCPA in the payload if present', function () {
+ const ccpa = '1YYY';
+ bidderRequest.uspConsent = ccpa;
+ const request = spec.buildRequests([validBid], bidderRequest);
+ expect(JSON.parse(request.data).regs.ext.us_privacy).to.equal(ccpa);
+ });
+
+ it('should send eids in the payload if present', function () {
+ const eids = {data: [{source: 'test', uids: [{id: '123', ext: {}}]}]};
+ validBid.userIdAsEids = eids;
+ const request = spec.buildRequests([validBid], bidderRequest);
+ expect(JSON.parse(request.data).user.ext.eids).to.deep.equal(eids);
+ });
+
+ it('should send schain in the payload if present', function () {
+ const schain = {'ver': '1.0', 'complete': 1, 'nodes': [{'asi': 'exchange1.com', 'sid': '1234', 'hp': 1}]};
+ validBid.schain = schain;
+ const request = spec.buildRequests([validBid], bidderRequest);
+ expect(JSON.parse(request.data).source.ext.schain).to.deep.equal(schain);
+ });
+
+ it('should correctly identify test mode', function () {
+ validBid.params.test = true;
+ const request = spec.buildRequests([validBid], bidderRequest);
+ expect(JSON.parse(request.data).test).to.equal(1);
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const validResponse = {
+ body: {
+ seatbid: [
+ {
+ bid: [
+ {
+ impid: 'bid1',
+ price: 1.5,
+ w: 300,
+ h: 250,
+ crid: 'creative1',
+ currency: 'USD',
+ netRevenue: true,
+ ttl: 300,
+ adm: '
Ad content
',
+ mtype: 1
+ },
+ {
+ impid: 'bid2',
+ price: 2.0,
+ w: 728,
+ h: 90,
+ crid: 'creative2',
+ currency: 'USD',
+ netRevenue: true,
+ ttl: 300,
+ adm: '
Ad content
',
+ mtype: 1
+ }
+ ]
+ }
+ ]
+ }
+ };
+
+ const emptyResponse = {
+ body: {
+ seatbid: []
+ }
+ };
+
+ it('should return an array of bid objects with valid response', function () {
+ const interpretedBids = spec.interpretResponse(validResponse);
+ const expectedBids = validResponse.body.seatbid[0].bid;
+ expect(interpretedBids).to.have.lengthOf(expectedBids.length);
+ expectedBids.forEach((expectedBid, index) => {
+ expect(interpretedBids[index]).to.have.property('requestId', expectedBid.impid);
+ expect(interpretedBids[index]).to.have.property('cpm', expectedBid.price);
+ expect(interpretedBids[index]).to.have.property('width', expectedBid.w);
+ expect(interpretedBids[index]).to.have.property('height', expectedBid.h);
+ expect(interpretedBids[index]).to.have.property('creativeId', expectedBid.crid);
+ expect(interpretedBids[index]).to.have.property('currency', expectedBid.currency);
+ expect(interpretedBids[index]).to.have.property('netRevenue', expectedBid.netRevenue);
+ expect(interpretedBids[index]).to.have.property('ttl', expectedBid.ttl);
+ expect(interpretedBids[index]).to.have.property('ad', expectedBid.adm);
+ expect(interpretedBids[index]).to.have.property('mediaType', expectedBid.mtype);
+ });
+ });
+
+ it('should return an empty array with empty response', function () {
+ const interpretedBids = spec.interpretResponse(emptyResponse);
+ expect(interpretedBids).to.be.an('array').that.is.empty;
+ });
+ });
+
+ describe('getUserSyncs', function () {
+ const RESPONSE = {
+ body: {
+ ext: {
+ usersync: {
+ sovrn: {
+ syncs: [{type: 'iframe', url: 'https://sovrn.com/iframe_sync'}]
+ },
+ appnexus: {
+ syncs: [{type: 'image', url: 'https://appnexus.com/image_sync'}]
+ }
+ }
+ }
+ }
+ };
+
+ it('should return empty array if no options are provided', function () {
+ const opts = spec.getUserSyncs({});
+ expect(opts).to.be.an('array').that.is.empty;
+ });
+
+ it('should return empty array if neither iframe nor pixel is enabled', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: false});
+ expect(opts).to.be.an('array').that.is.empty;
+ });
+
+ it('should return syncs only for iframe sync type', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: false}, [RESPONSE]);
+ expect(opts.length).to.equal(1);
+ expect(opts[0].type).to.equal('iframe');
+ expect(opts[0].url).to.equal(RESPONSE.body.ext.usersync.sovrn.syncs[0].url);
+ });
+
+ it('should return syncs only for pixel sync types', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, [RESPONSE]);
+ expect(opts.length).to.equal(1);
+ expect(opts[0].type).to.equal('image');
+ expect(opts[0].url).to.equal(RESPONSE.body.ext.usersync.appnexus.syncs[0].url);
+ });
+
+ it('should return syncs when both iframe and pixel are enabled', function () {
+ const opts = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [RESPONSE]);
+ expect(opts.length).to.equal(2);
+ });
+ });
+});
diff --git a/test/spec/modules/orbidderBidAdapter_spec.js b/test/spec/modules/orbidderBidAdapter_spec.js
index 5af5a4d710f..cf58d35e636 100644
--- a/test/spec/modules/orbidderBidAdapter_spec.js
+++ b/test/spec/modules/orbidderBidAdapter_spec.js
@@ -9,39 +9,57 @@ describe('orbidderBidAdapter', () => {
const defaultBidRequestBanner = {
bidId: 'd66fa86787e0b0ca900a96eacfd5f0bb',
auctionId: 'ccc4c7cdfe11cfbd74065e6dd28413d8',
- ortb2Imp: {
- ext: {
- tid: 'd58851660c0c4461e4aa06344fc9c0c6',
- }
- },
+ transactionId: 'd58851660c0c4461e4aa06344fc9c0c6',
bidRequestCount: 1,
adUnitCode: 'adunit-code',
sizes: [[300, 250], [300, 600]],
params: {
'accountId': 'string1',
- 'placementId': 'string2'
+ 'placementId': 'string2',
+ 'bidfloor': 1.23
},
mediaTypes: {
banner: {
- sizes: [[300, 250], [300, 600]],
+ sizes: [[300, 250], [300, 600]]
}
- }
+ },
+ userId: {
+ 'id5id': {
+ 'uid': 'ID5*XXXXXXXXXXXXX',
+ 'ext': {
+ 'linkType': 2,
+ 'pba': 'XXXXXXXXXXXX=='
+ }
+ }
+ },
+ userIdAsEids: [
+ {
+ 'source': 'id5-sync.com',
+ 'uids': [
+ {
+ 'id': 'ID5*XXXXXXXXXXXXX',
+ 'atype': 1,
+ 'ext': {
+ 'linkType': 2,
+ 'pba': 'XXXXXXXXXXXX=='
+ }
+ }
+ ]
+ }
+ ]
};
const defaultBidRequestNative = {
bidId: 'd66fa86787e0b0ca900a96eacfd5f0bc',
auctionId: 'ccc4c7cdfe11cfbd74065e6dd28413d9',
- ortb2Imp: {
- ext: {
- tid: 'd58851660c0c4461e4aa06344fc9c0c7',
- }
- },
+ transactionId: 'd58851660c0c4461e4aa06344fc9c0c6',
bidRequestCount: 1,
adUnitCode: 'adunit-code-native',
sizes: [],
params: {
'accountId': 'string3',
- 'placementId': 'string4'
+ 'placementId': 'string4',
+ 'bidfloor': 2.34
},
mediaTypes: {
native: {
@@ -56,7 +74,31 @@ describe('orbidderBidAdapter', () => {
required: true
}
}
- }
+ },
+ userId: {
+ 'id5id': {
+ 'uid': 'ID5*YYYYYYYYYYYYYYY',
+ 'ext': {
+ 'linkType': 2,
+ 'pba': 'YYYYYYYYYYYYY=='
+ }
+ }
+ },
+ userIdAsEids: [
+ {
+ 'source': 'id5-sync.com',
+ 'uids': [
+ {
+ 'id': 'ID5*YYYYYYYYYYYYYYY',
+ 'atype': 1,
+ 'ext': {
+ 'linkType': 2,
+ 'pba': 'YYYYYYYYYYYYY=='
+ }
+ }
+ ]
+ }
+ ]
};
const deepClone = function(val) {
@@ -179,34 +221,20 @@ describe('orbidderBidAdapter', () => {
// we add two, because we add pageUrl and version from bidderRequest object
expect(Object.keys(request.data).length).to.equal(Object.keys(defaultBidRequestBanner).length + 2);
- expect(request.data.bidId).to.equal(defaultBidRequestBanner.bidId);
- expect(request.data.auctionId).to.equal(defaultBidRequestBanner.auctionId);
- expect(request.data.transactionId).to.equal(defaultBidRequestBanner.ortb2Imp.ext.tid);
- expect(request.data.bidRequestCount).to.equal(defaultBidRequestBanner.bidRequestCount);
- expect(request.data.adUnitCode).to.equal(defaultBidRequestBanner.adUnitCode);
- expect(request.data.pageUrl).to.equal('https://localhost:9876/');
- expect(request.data.v).to.equal($$PREBID_GLOBAL$$.version);
- expect(request.data.sizes).to.equal(defaultBidRequestBanner.sizes);
-
- expect(_.isEqual(request.data.params, defaultBidRequestBanner.params)).to.be.true;
- expect(_.isEqual(request.data.mediaTypes, defaultBidRequestBanner.mediaTypes)).to.be.true;
+ const expectedBidRequest = deepClone(defaultBidRequestBanner);
+ expectedBidRequest.pageUrl = 'https://localhost:9876/';
+ expectedBidRequest.v = $$PREBID_GLOBAL$$.version;
+ expect(request.data).to.deep.equal(expectedBidRequest);
});
it('native: sends correct bid parameters', () => {
// we add two, because we add pageUrl and version from bidderRequest object
expect(Object.keys(nativeRequest.data).length).to.equal(Object.keys(defaultBidRequestNative).length + 2);
- expect(nativeRequest.data.bidId).to.equal(defaultBidRequestNative.bidId);
- expect(nativeRequest.data.auctionId).to.equal(defaultBidRequestNative.auctionId);
- expect(nativeRequest.data.transactionId).to.equal(defaultBidRequestNative.ortb2Imp.ext.tid);
- expect(nativeRequest.data.bidRequestCount).to.equal(defaultBidRequestNative.bidRequestCount);
- expect(nativeRequest.data.adUnitCode).to.equal(defaultBidRequestNative.adUnitCode);
- expect(nativeRequest.data.pageUrl).to.equal('https://localhost:9876/');
- expect(nativeRequest.data.v).to.equal($$PREBID_GLOBAL$$.version);
- expect(nativeRequest.data.sizes).to.be.empty;
-
- expect(_.isEqual(nativeRequest.data.params, defaultBidRequestNative.params)).to.be.true;
- expect(_.isEqual(nativeRequest.data.mediaTypes, defaultBidRequestNative.mediaTypes)).to.be.true;
+ const expectedBidRequest = deepClone(defaultBidRequestNative);
+ expectedBidRequest.pageUrl = 'https://localhost:9876/';
+ expectedBidRequest.v = $$PREBID_GLOBAL$$.version;
+ expect(nativeRequest.data).to.deep.equal(expectedBidRequest);
});
it('banner: handles empty gdpr object', () => {
diff --git a/test/spec/modules/outbrainBidAdapter_spec.js b/test/spec/modules/outbrainBidAdapter_spec.js
index d8690aeb6a5..e6abb5e9caa 100644
--- a/test/spec/modules/outbrainBidAdapter_spec.js
+++ b/test/spec/modules/outbrainBidAdapter_spec.js
@@ -1,5 +1,5 @@
import { expect } from 'chai';
-import { spec } from 'modules/outbrainBidAdapter.js';
+import { spec, storage } from 'modules/outbrainBidAdapter.js';
import { config } from 'src/config.js';
import { server } from 'test/mocks/xhr';
@@ -213,15 +213,18 @@ describe('Outbrain Adapter', function () {
})
describe('buildRequests', function () {
+ let getDataFromLocalStorageStub;
+
before(() => {
+ getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage')
config.setConfig({
outbrain: {
bidderUrl: 'https://bidder-url.com',
}
- }
- )
+ })
})
after(() => {
+ getDataFromLocalStorageStub.restore()
config.resetConfig()
})
@@ -424,7 +427,7 @@ describe('Outbrain Adapter', function () {
expect(resData.badv).to.deep.equal(['bad-advertiser'])
});
- it('first party data', function () {
+ it('should pass first party data', function () {
const bidRequest = {
...commonBidRequest,
...nativeBidRequestParams,
@@ -505,6 +508,28 @@ describe('Outbrain Adapter', function () {
config.resetConfig()
});
+ it('should pass gpp information', function () {
+ const bidRequest = {
+ ...commonBidRequest,
+ ...nativeBidRequestParams,
+ };
+ const bidderRequest = {
+ ...commonBidderRequest,
+ 'gppConsent': {
+ 'gppString': 'abc12345',
+ 'applicableSections': [8]
+ }
+ }
+
+ const res = spec.buildRequests([bidRequest], bidderRequest);
+ const resData = JSON.parse(res.data);
+
+ expect(resData.regs.ext.gpp).to.exist;
+ expect(resData.regs.ext.gpp_sid).to.exist;
+ expect(resData.regs.ext.gpp).to.equal('abc12345');
+ expect(resData.regs.ext.gpp_sid).to.deep.equal([8]);
+ });
+
it('should pass extended ids', function () {
let bidRequest = {
bidId: 'bidId',
@@ -522,6 +547,22 @@ describe('Outbrain Adapter', function () {
]);
});
+ it('should pass OB user token', function () {
+ getDataFromLocalStorageStub.returns('12345');
+
+ let bidRequest = {
+ bidId: 'bidId',
+ params: {},
+ ...commonBidRequest,
+ };
+
+ let res = spec.buildRequests([bidRequest], commonBidderRequest);
+ const resData = JSON.parse(res.data)
+ expect(resData.user.ext.obusertoken).to.equal('12345')
+ expect(getDataFromLocalStorageStub.called).to.be.true;
+ sinon.assert.calledWith(getDataFromLocalStorageStub, 'OB-USER-TOKEN');
+ });
+
it('should pass bidfloor', function () {
const bidRequest = {
...commonBidRequest,
@@ -842,6 +883,12 @@ describe('Outbrain Adapter', function () {
type: 'image', url: `${usersyncUrl}?gdpr=1&gdpr_consent=foo&us_privacy=1NYN`
}]);
});
+
+ it('should pass gpp consent', function () {
+ expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined, '', { gppString: 'abc12345', applicableSections: [1, 2] })).to.deep.equal([{
+ type: 'image', url: `${usersyncUrl}?gpp=abc12345&gpp_sid=1%2C2`
+ }]);
+ });
})
describe('onBidWon', function () {
diff --git a/test/spec/modules/oxxionAnalyticsAdapter_spec.js b/test/spec/modules/oxxionAnalyticsAdapter_spec.js
index 13dc395968a..9d06be24f68 100644
--- a/test/spec/modules/oxxionAnalyticsAdapter_spec.js
+++ b/test/spec/modules/oxxionAnalyticsAdapter_spec.js
@@ -86,20 +86,21 @@ describe('Oxxion Analytics', function () {
}
},
'adUnitCode': 'tag_200124_banner',
- 'transactionId': 'de664ccb-e18b-4436-aeb0-362382eb1b40',
+ 'transactionId': '8b2a8629-d1ea-4bb1-aff0-e335b96dd002',
'sizes': [
[
300,
600
]
],
- 'bidId': '34a63e5d5378a3',
+ 'bidId': '2bd3e8ff8a113f',
'bidderRequestId': '11dc6ff6378de7',
'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b',
'src': 'client',
'bidRequestsCount': 1,
'bidderRequestsCount': 1,
- 'bidderWinsCount': 0
+ 'bidderWinsCount': 0,
+ 'ova': 'cleared'
}
],
'auctionStart': 1647424261187,
@@ -149,12 +150,12 @@ describe('Oxxion Analytics', function () {
'bidsReceived': [
{
'bidderCode': 'appnexus',
- 'width': 300,
- 'height': 600,
+ 'width': 970,
+ 'height': 250,
'statusMessage': 'Bid available',
- 'adId': '7a4ced80f33d33',
- 'requestId': '34a63e5d5378a3',
- 'transactionId': 'de664ccb-e18b-4436-aeb0-362382eb1b40',
+ 'adId': '65d16ef039a97a',
+ 'requestId': '2bd3e8ff8a113f',
+ 'transactionId': '8b2a8629-d1ea-4bb1-aff0-e335b96dd002',
'auctionId': '1e8b993d-8f0a-4232-83eb-3639ddf3a44b',
'mediaType': 'video',
'source': 'client',
@@ -187,7 +188,7 @@ describe('Oxxion Analytics', function () {
'size': '300x600',
'adserverTargeting': {
'hb_bidder': 'appnexus',
- 'hb_adid': '7a4ced80f33d33',
+ 'hb_adid': '65d16ef039a97a',
'hb_pb': '20.000000',
'hb_size': '300x600',
'hb_source': 'client',
@@ -342,7 +343,7 @@ describe('Oxxion Analytics', function () {
expect(message).to.have.property('adId')
expect(message).to.have.property('cpmIncrement').and.to.equal(27.4276);
expect(message).to.have.property('oxxionMode').and.to.have.property('abtest').and.to.equal(true);
- // sinon.assert.callCount(oxxionAnalytics.track, 1);
+ expect(message).to.have.property('ova').and.to.equal('cleared');
});
});
});
diff --git a/test/spec/modules/ozoneBidAdapter_spec.js b/test/spec/modules/ozoneBidAdapter_spec.js
index 64b345c5d9c..73df2fba8fd 100644
--- a/test/spec/modules/ozoneBidAdapter_spec.js
+++ b/test/spec/modules/ozoneBidAdapter_spec.js
@@ -2069,6 +2069,19 @@ describe('ozone Adapter', function () {
expect(request.length).to.equal(3);
config.resetConfig();
});
+ it('should not batch into 10s if config is set to false and singleRequest is true', function () {
+ config.setConfig({ozone: {'batchRequests': false, 'singleRequest': true}});
+ var specMock = utils.deepClone(spec);
+ let arrReq = [];
+ for (let i = 0; i < 15; i++) {
+ let b = validBidRequests[0];
+ b.adUnitCode += i;
+ arrReq.push(b);
+ }
+ const request = specMock.buildRequests(arrReq, validBidderRequest);
+ expect(request.method).to.equal('POST');
+ config.resetConfig();
+ });
it('should use GET values auction=dev & cookiesync=dev if set', function() {
var specMock = utils.deepClone(spec);
specMock.getGetParametersAsObject = function() {
diff --git a/test/spec/modules/paapi_spec.js b/test/spec/modules/paapi_spec.js
new file mode 100644
index 00000000000..3d264e87e51
--- /dev/null
+++ b/test/spec/modules/paapi_spec.js
@@ -0,0 +1,628 @@
+import {expect} from 'chai';
+import {config} from '../../../src/config.js';
+import adapterManager from '../../../src/adapterManager.js';
+import * as utils from '../../../src/utils.js';
+import {hook} from '../../../src/hook.js';
+import 'modules/appnexusBidAdapter.js';
+import 'modules/rubiconBidAdapter.js';
+import {
+ addComponentAuctionHook,
+ getPAAPIConfig,
+ parseExtPrebidFledge,
+ registerSubmodule,
+ setImpExtAe,
+ setResponseFledgeConfigs,
+ reset
+} from 'modules/paapi.js';
+import * as events from 'src/events.js';
+import CONSTANTS from 'src/constants.json';
+import {getGlobal} from '../../../src/prebidGlobal.js';
+import {auctionManager} from '../../../src/auctionManager.js';
+import {stubAuctionIndex} from '../../helpers/indexStub.js';
+import {AuctionIndex} from '../../../src/auctionIndex.js';
+
+describe('paapi module', () => {
+ let sandbox;
+ before(reset);
+ beforeEach(() => {
+ sandbox = sinon.sandbox.create();
+ });
+ afterEach(() => {
+ sandbox.restore();
+ reset();
+ });
+
+ [
+ 'fledgeForGpt',
+ 'paapi'
+ ].forEach(configNS => {
+ describe(`using ${configNS} for configuration`, () => {
+ describe('getPAAPIConfig', function () {
+ let nextFnSpy, fledgeAuctionConfig;
+ before(() => {
+ config.setConfig({[configNS]: {enabled: true}});
+ });
+ beforeEach(() => {
+ fledgeAuctionConfig = {
+ seller: 'bidder',
+ mock: 'config'
+ };
+ nextFnSpy = sinon.spy();
+ });
+
+ describe('on a single auction', function () {
+ const auctionId = 'aid';
+ beforeEach(function () {
+ sandbox.stub(auctionManager, 'index').value(stubAuctionIndex({auctionId}));
+ });
+
+ it('should call next()', function () {
+ const request = {auctionId, adUnitCode: 'auc'};
+ addComponentAuctionHook(nextFnSpy, request, fledgeAuctionConfig);
+ sinon.assert.calledWith(nextFnSpy, request, fledgeAuctionConfig);
+ });
+
+ describe('should collect auction configs', () => {
+ let cf1, cf2;
+ beforeEach(() => {
+ cf1 = {...fledgeAuctionConfig, id: 1, seller: 'b1'};
+ cf2 = {...fledgeAuctionConfig, id: 2, seller: 'b2'};
+ addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au1'}, cf1);
+ addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au2'}, cf2);
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au1', 'au2', 'au3']});
+ });
+
+ it('and make them available at end of auction', () => {
+ sinon.assert.match(getPAAPIConfig({auctionId}), {
+ au1: {
+ componentAuctions: [cf1]
+ },
+ au2: {
+ componentAuctions: [cf2]
+ }
+ });
+ });
+
+ it('and filter them by ad unit', () => {
+ const cfg = getPAAPIConfig({auctionId, adUnitCode: 'au1'});
+ expect(Object.keys(cfg)).to.have.members(['au1']);
+ sinon.assert.match(cfg.au1, {
+ componentAuctions: [cf1]
+ });
+ });
+
+ it('and not return them again', () => {
+ getPAAPIConfig();
+ const cfg = getPAAPIConfig();
+ expect(cfg).to.eql({});
+ });
+
+ describe('includeBlanks = true', () => {
+ it('includes all ad units', () => {
+ const cfg = getPAAPIConfig({}, true);
+ expect(Object.keys(cfg)).to.have.members(['au1', 'au2', 'au3']);
+ expect(cfg.au3).to.eql(null);
+ })
+ it('includes the targeted adUnit', () => {
+ expect(getPAAPIConfig({adUnitCode: 'au3'}, true)).to.eql({
+ au3: null
+ })
+ });
+ it('includes the targeted auction', () => {
+ const cfg = getPAAPIConfig({auctionId}, true);
+ expect(Object.keys(cfg)).to.have.members(['au1', 'au2', 'au3']);
+ expect(cfg.au3).to.eql(null);
+ });
+ it('does not include non-existing ad units', () => {
+ expect(getPAAPIConfig({adUnitCode: 'other'})).to.eql({});
+ });
+ it('does not include non-existing auctions', () => {
+ expect(getPAAPIConfig({auctionId: 'other'})).to.eql({});
+ })
+ });
+ });
+
+ it('should drop auction configs after end of auction', () => {
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId});
+ addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au'}, fledgeAuctionConfig);
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId});
+ expect(getPAAPIConfig({auctionId})).to.eql({});
+ });
+
+ it('should augment auctionSignals with FPD', () => {
+ addComponentAuctionHook(nextFnSpy, {
+ auctionId,
+ adUnitCode: 'au1',
+ ortb2: {fpd: 1},
+ ortb2Imp: {fpd: 2}
+ }, fledgeAuctionConfig);
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId});
+ sinon.assert.match(getPAAPIConfig({auctionId}), {
+ au1: {
+ componentAuctions: [{
+ ...fledgeAuctionConfig,
+ auctionSignals: {
+ prebid: {
+ ortb2: {fpd: 1},
+ ortb2Imp: {fpd: 2}
+ }
+ }
+ }]
+ }
+ });
+ });
+
+ describe('submodules', () => {
+ let submods;
+ beforeEach(() => {
+ submods = [1, 2].map(i => ({
+ name: `test${i}`,
+ onAuctionConfig: sinon.stub()
+ }));
+ submods.forEach(registerSubmodule);
+ });
+
+ describe('onAuctionConfig', () => {
+ const auctionId = 'aid';
+ it('is invoked with null configs when there\'s no config', () => {
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au']});
+ submods.forEach(submod => sinon.assert.calledWith(submod.onAuctionConfig, auctionId, {au: null}));
+ });
+ it('is invoked with relevant configs', () => {
+ addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au1'}, fledgeAuctionConfig);
+ addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au2'}, fledgeAuctionConfig);
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au1', 'au2', 'au3']});
+ submods.forEach(submod => {
+ sinon.assert.calledWith(submod.onAuctionConfig, auctionId, {
+ au1: {componentAuctions: [fledgeAuctionConfig]},
+ au2: {componentAuctions: [fledgeAuctionConfig]},
+ au3: null
+ })
+ });
+ });
+ it('removes configs from getPAAPIConfig if the module calls markAsUsed', () => {
+ submods[0].onAuctionConfig.callsFake((auctionId, configs, markAsUsed) => {
+ markAsUsed('au1');
+ });
+ addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au1'}, fledgeAuctionConfig);
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au1']});
+ expect(getPAAPIConfig()).to.eql({});
+ });
+ it('keeps them available if they do not', () => {
+ addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au1'}, fledgeAuctionConfig);
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId, adUnitCodes: ['au1']});
+ expect(getPAAPIConfig()).to.not.be.empty;
+ })
+ });
+ });
+
+ describe('floor signal', () => {
+ before(() => {
+ if (!getGlobal().convertCurrency) {
+ getGlobal().convertCurrency = () => null;
+ getGlobal().convertCurrency.mock = true;
+ }
+ });
+ after(() => {
+ if (getGlobal().convertCurrency.mock) {
+ delete getGlobal().convertCurrency;
+ }
+ });
+
+ beforeEach(() => {
+ sandbox.stub(getGlobal(), 'convertCurrency').callsFake((amount, from, to) => {
+ if (from === to) return amount;
+ if (from === 'USD' && to === 'JPY') return amount * 100;
+ if (from === 'JPY' && to === 'USD') return amount / 100;
+ throw new Error('unexpected currency conversion');
+ });
+ });
+
+ Object.entries({
+ 'bids': (payload, values) => {
+ payload.bidsReceived = values
+ .map((val) => ({adUnitCode: 'au', cpm: val.amount, currency: val.cur}))
+ .concat([{adUnitCode: 'other', cpm: 10000, currency: 'EUR'}]);
+ },
+ 'no bids': (payload, values) => {
+ payload.bidderRequests = values
+ .map((val) => ({
+ bids: [{
+ adUnitCode: 'au',
+ getFloor: () => ({floor: val.amount, currency: val.cur})
+ }]
+ }))
+ .concat([{bids: {adUnitCode: 'other', getFloor: () => ({floor: -10000, currency: 'EUR'})}}]);
+ }
+ }).forEach(([tcase, setup]) => {
+ describe(`when auction has ${tcase}`, () => {
+ Object.entries({
+ 'no currencies': {
+ values: [{amount: 1}, {amount: 100}, {amount: 10}, {amount: 100}],
+ 'bids': {
+ bidfloor: 100,
+ bidfloorcur: undefined
+ },
+ 'no bids': {
+ bidfloor: 1,
+ bidfloorcur: undefined,
+ }
+ },
+ 'only zero values': {
+ values: [{amount: 0, cur: 'USD'}, {amount: 0, cur: 'JPY'}],
+ 'bids': {
+ bidfloor: undefined,
+ bidfloorcur: undefined,
+ },
+ 'no bids': {
+ bidfloor: undefined,
+ bidfloorcur: undefined,
+ }
+ },
+ 'matching currencies': {
+ values: [{amount: 10, cur: 'JPY'}, {amount: 100, cur: 'JPY'}],
+ 'bids': {
+ bidfloor: 100,
+ bidfloorcur: 'JPY',
+ },
+ 'no bids': {
+ bidfloor: 10,
+ bidfloorcur: 'JPY',
+ }
+ },
+ 'mixed currencies': {
+ values: [{amount: 10, cur: 'USD'}, {amount: 10, cur: 'JPY'}],
+ 'bids': {
+ bidfloor: 10,
+ bidfloorcur: 'USD'
+ },
+ 'no bids': {
+ bidfloor: 10,
+ bidfloorcur: 'JPY',
+ }
+ }
+ }).forEach(([t, testConfig]) => {
+ const values = testConfig.values;
+ const {bidfloor, bidfloorcur} = testConfig[tcase];
+
+ describe(`with ${t}`, () => {
+ let payload;
+ beforeEach(() => {
+ payload = {auctionId};
+ setup(payload, values);
+ });
+
+ it('should populate bidfloor/bidfloorcur', () => {
+ addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode: 'au'}, fledgeAuctionConfig);
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, payload);
+ const signals = getPAAPIConfig({auctionId}).au.componentAuctions[0].auctionSignals;
+ expect(signals.prebid?.bidfloor).to.eql(bidfloor);
+ expect(signals.prebid?.bidfloorcur).to.eql(bidfloorcur);
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+
+ describe('with multiple auctions', () => {
+ const AUCTION1 = 'auction1';
+ const AUCTION2 = 'auction2';
+
+ function mockAuction(auctionId) {
+ return {
+ getAuctionId() {
+ return auctionId;
+ }
+ };
+ }
+
+ function expectAdUnitsFromAuctions(actualConfig, auToAuctionMap) {
+ expect(Object.keys(actualConfig)).to.have.members(Object.keys(auToAuctionMap));
+ Object.entries(actualConfig).forEach(([au, cfg]) => {
+ cfg.componentAuctions.forEach(cmp => expect(cmp.auctionId).to.eql(auToAuctionMap[au]));
+ });
+ }
+
+ let configs;
+ beforeEach(() => {
+ const mockAuctions = [mockAuction(AUCTION1), mockAuction(AUCTION2)];
+ sandbox.stub(auctionManager, 'index').value(new AuctionIndex(() => mockAuctions));
+ configs = {[AUCTION1]: {}, [AUCTION2]: {}};
+ Object.entries({
+ [AUCTION1]: [['au1', 'au2'], ['missing-1']],
+ [AUCTION2]: [['au2', 'au3'], []],
+ }).forEach(([auctionId, [adUnitCodes, noConfigAdUnitCodes]]) => {
+ adUnitCodes.forEach(adUnitCode => {
+ const cfg = {...fledgeAuctionConfig, auctionId, adUnitCode};
+ configs[auctionId][adUnitCode] = cfg;
+ addComponentAuctionHook(nextFnSpy, {auctionId, adUnitCode}, cfg);
+ });
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, {auctionId, adUnitCodes: adUnitCodes.concat(noConfigAdUnitCodes)});
+ });
+ });
+
+ it('should filter by auction', () => {
+ expectAdUnitsFromAuctions(getPAAPIConfig({auctionId: AUCTION1}), {au1: AUCTION1, au2: AUCTION1});
+ expectAdUnitsFromAuctions(getPAAPIConfig({auctionId: AUCTION2}), {au2: AUCTION2, au3: AUCTION2});
+ });
+
+ it('should filter by auction and ad unit', () => {
+ expectAdUnitsFromAuctions(getPAAPIConfig({auctionId: AUCTION1, adUnitCode: 'au2'}), {au2: AUCTION1});
+ expectAdUnitsFromAuctions(getPAAPIConfig({auctionId: AUCTION2, adUnitCode: 'au2'}), {au2: AUCTION2});
+ });
+
+ it('should use last auction for each ad unit', () => {
+ expectAdUnitsFromAuctions(getPAAPIConfig(), {au1: AUCTION1, au2: AUCTION2, au3: AUCTION2});
+ });
+
+ it('should filter by ad unit and use latest auction', () => {
+ expectAdUnitsFromAuctions(getPAAPIConfig({adUnitCode: 'au2'}), {au2: AUCTION2});
+ });
+
+ it('should keep track of which configs were returned', () => {
+ expectAdUnitsFromAuctions(getPAAPIConfig({auctionId: AUCTION1}), {au1: AUCTION1, au2: AUCTION1});
+ expect(getPAAPIConfig({auctionId: AUCTION1})).to.eql({});
+ expectAdUnitsFromAuctions(getPAAPIConfig(), {au2: AUCTION2, au3: AUCTION2});
+ });
+
+ describe('includeBlanks = true', () => {
+ Object.entries({
+ 'auction with blanks': {
+ filters: {auctionId: AUCTION1},
+ expected: {au1: true, au2: true, 'missing-1': false}
+ },
+ 'blank adUnit in an auction': {
+ filters: {auctionId: AUCTION1, adUnitCode: 'missing-1'},
+ expected: {'missing-1': false}
+ },
+ 'non-existing auction': {
+ filters: {auctionId: 'other'},
+ expected: {}
+ },
+ 'non-existing adUnit in an auction': {
+ filters: {auctionId: AUCTION2, adUnitCode: 'other'},
+ expected: {}
+ },
+ 'non-existing ad unit': {
+ filters: {adUnitCode: 'other'},
+ expected: {},
+ },
+ 'non existing ad unit in a non-existing auction': {
+ filters: {adUnitCode: 'other', auctionId: 'other'},
+ expected: {}
+ },
+ 'all ad units': {
+ filters: {},
+ expected: {'au1': true, 'au2': true, 'missing-1': false, 'au3': true}
+ }
+ }).forEach(([t, {filters, expected}]) => {
+ it(t, () => {
+ const cfg = getPAAPIConfig(filters, true);
+ expect(Object.keys(cfg)).to.have.members(Object.keys(expected));
+ Object.entries(expected).forEach(([au, shouldBeFilled]) => {
+ if (shouldBeFilled) {
+ expect(cfg[au]).to.not.be.null;
+ } else {
+ expect(cfg[au]).to.be.null;
+ }
+ })
+ })
+ })
+ });
+ });
+ });
+
+ describe('markForFledge', function () {
+ const navProps = Object.fromEntries(['runAdAuction', 'joinAdInterestGroup'].map(p => [p, navigator[p]]));
+
+ before(function () {
+ // navigator.runAdAuction & co may not exist, so we can't stub it normally with
+ // sinon.stub(navigator, 'runAdAuction') or something
+ Object.keys(navProps).forEach(p => {
+ navigator[p] = sinon.stub();
+ });
+ hook.ready();
+ config.resetConfig();
+ });
+
+ after(function () {
+ Object.entries(navProps).forEach(([p, orig]) => navigator[p] = orig);
+ });
+
+ afterEach(function () {
+ config.resetConfig();
+ });
+
+ const adUnits = [{
+ 'code': '/19968336/header-bid-tag1',
+ 'mediaTypes': {
+ 'banner': {
+ 'sizes': [[728, 90]]
+ },
+ },
+ 'bids': [
+ {
+ 'bidder': 'appnexus',
+ },
+ {
+ 'bidder': 'rubicon',
+ },
+ ]
+ }];
+
+ function expectFledgeFlags(...enableFlags) {
+ const bidRequests = Object.fromEntries(
+ adapterManager.makeBidRequests(
+ adUnits,
+ Date.now(),
+ utils.getUniqueIdentifierStr(),
+ function callback() {
+ },
+ []
+ ).map(b => [b.bidderCode, b])
+ );
+
+ expect(bidRequests.appnexus.fledgeEnabled).to.eql(enableFlags[0].enabled);
+ bidRequests.appnexus.bids.forEach(bid => expect(bid.ortb2Imp.ext.ae).to.eql(enableFlags[0].ae));
+
+ expect(bidRequests.rubicon.fledgeEnabled).to.eql(enableFlags[1].enabled);
+ bidRequests.rubicon.bids.forEach(bid => expect(bid.ortb2Imp?.ext?.ae).to.eql(enableFlags[1].ae));
+ }
+
+ describe('with setBidderConfig()', () => {
+ it('should set fledgeEnabled correctly per bidder', function () {
+ config.setBidderConfig({
+ bidders: ['appnexus'],
+ config: {
+ defaultForSlots: 1,
+ fledgeEnabled: true
+ }
+ });
+ expectFledgeFlags({enabled: true, ae: 1}, {enabled: void 0, ae: void 0});
+ });
+ });
+
+ describe('with setConfig()', () => {
+ it('should set fledgeEnabled correctly per bidder', function () {
+ config.setConfig({
+ bidderSequence: 'fixed',
+ [configNS]: {
+ enabled: true,
+ bidders: ['appnexus'],
+ defaultForSlots: 1,
+ }
+ });
+ expectFledgeFlags({enabled: true, ae: 1}, {enabled: false, ae: undefined});
+ });
+
+ it('should set fledgeEnabled correctly for all bidders', function () {
+ config.setConfig({
+ bidderSequence: 'fixed',
+ [configNS]: {
+ enabled: true,
+ defaultForSlots: 1,
+ }
+ });
+ expectFledgeFlags({enabled: true, ae: 1}, {enabled: true, ae: 1});
+ });
+
+ it('should not override pub-defined ext.ae', () => {
+ config.setConfig({
+ bidderSequence: 'fixed',
+ [configNS]: {
+ enabled: true,
+ defaultForSlots: 1,
+ }
+ });
+ Object.assign(adUnits[0], {ortb2Imp: {ext: {ae: 0}}});
+ expectFledgeFlags({enabled: true, ae: 0}, {enabled: true, ae: 0});
+ });
+ });
+ });
+ });
+ });
+
+ describe('ortb processors for fledge', () => {
+ it('imp.ext.ae should be removed if fledge is not enabled', () => {
+ const imp = {ext: {ae: 1}};
+ setImpExtAe(imp, {}, {bidderRequest: {}});
+ expect(imp.ext.ae).to.not.exist;
+ });
+ it('imp.ext.ae should be left intact if fledge is enabled', () => {
+ const imp = {ext: {ae: 2}};
+ setImpExtAe(imp, {}, {bidderRequest: {fledgeEnabled: true}});
+ expect(imp.ext.ae).to.equal(2);
+ });
+ describe('parseExtPrebidFledge', () => {
+ function packageConfigs(configs) {
+ return {
+ ext: {
+ prebid: {
+ fledge: {
+ auctionconfigs: configs
+ }
+ }
+ }
+ };
+ }
+
+ function generateImpCtx(fledgeFlags) {
+ return Object.fromEntries(Object.entries(fledgeFlags).map(([impid, fledgeEnabled]) => [impid, {imp: {ext: {ae: fledgeEnabled}}}]));
+ }
+
+ function generateCfg(impid, ...ids) {
+ return ids.map((id) => ({impid, config: {id}}));
+ }
+
+ function extractResult(ctx) {
+ return Object.fromEntries(
+ Object.entries(ctx)
+ .map(([impid, ctx]) => [impid, ctx.fledgeConfigs?.map(cfg => cfg.config.id)])
+ .filter(([_, val]) => val != null)
+ );
+ }
+
+ it('should collect fledge configs by imp', () => {
+ const ctx = {
+ impContext: generateImpCtx({e1: 1, e2: 1, d1: 0})
+ };
+ const resp = packageConfigs(
+ generateCfg('e1', 1, 2, 3)
+ .concat(generateCfg('e2', 4)
+ .concat(generateCfg('d1', 5, 6)))
+ );
+ parseExtPrebidFledge({}, resp, ctx);
+ expect(extractResult(ctx.impContext)).to.eql({
+ e1: [1, 2, 3],
+ e2: [4],
+ });
+ });
+ it('should not choke if fledge config references unknown imp', () => {
+ const ctx = {impContext: generateImpCtx({i: 1})};
+ const resp = packageConfigs(generateCfg('unknown', 1));
+ parseExtPrebidFledge({}, resp, ctx);
+ expect(extractResult(ctx.impContext)).to.eql({});
+ });
+ });
+ describe('setResponseFledgeConfigs', () => {
+ it('should set fledgeAuctionConfigs paired with their corresponding bid id', () => {
+ const ctx = {
+ impContext: {
+ 1: {
+ bidRequest: {bidId: 'bid1'},
+ fledgeConfigs: [{config: {id: 1}}, {config: {id: 2}}]
+ },
+ 2: {
+ bidRequest: {bidId: 'bid2'},
+ fledgeConfigs: [{config: {id: 3}}]
+ },
+ 3: {
+ bidRequest: {bidId: 'bid3'}
+ }
+ }
+ };
+ const resp = {};
+ setResponseFledgeConfigs(resp, {}, ctx);
+ expect(resp.fledgeAuctionConfigs).to.eql([
+ {bidId: 'bid1', config: {id: 1}},
+ {bidId: 'bid1', config: {id: 2}},
+ {bidId: 'bid2', config: {id: 3}},
+ ]);
+ });
+ it('should not set fledgeAuctionConfigs if none exist', () => {
+ const resp = {};
+ setResponseFledgeConfigs(resp, {}, {
+ impContext: {
+ 1: {
+ fledgeConfigs: []
+ },
+ 2: {}
+ }
+ });
+ expect(resp).to.eql({});
+ });
+ });
+ });
+});
diff --git a/test/spec/modules/pangleBidAdapter_spec.js b/test/spec/modules/pangleBidAdapter_spec.js
index 79cbc30b4ec..f2504a810c4 100644
--- a/test/spec/modules/pangleBidAdapter_spec.js
+++ b/test/spec/modules/pangleBidAdapter_spec.js
@@ -45,6 +45,7 @@ const REQUEST = [{
appid: 111,
},
}];
+
const DEFAULT_OPTIONS = {
userId: {
britepoolid: 'pangle-britepool',
@@ -82,6 +83,7 @@ const RESPONSE = {
'cat': [],
'w': 300,
'h': 250,
+ 'mtype': 1,
'ext': {
'prebid': {
'type': 'banner'
@@ -125,11 +127,15 @@ describe('pangle bid adapter', function () {
describe('buildRequests', function () {
it('creates request data', function () {
- let request = spec.buildRequests(REQUEST, DEFAULT_OPTIONS)[0];
- expect(request).to.exist.and.to.be.a('object');
- const payload = request.data;
- expect(payload.imp[0]).to.have.property('id', REQUEST[0].bidId);
- expect(payload.imp[1]).to.have.property('id', REQUEST[1].bidId);
+ let request1 = spec.buildRequests(REQUEST, DEFAULT_OPTIONS)[0];
+ expect(request1).to.exist.and.to.be.a('object');
+ const payload1 = request1.data;
+ expect(payload1.imp[0]).to.have.property('id', REQUEST[0].bidId);
+
+ let request2 = spec.buildRequests(REQUEST, DEFAULT_OPTIONS)[1];
+ expect(request2).to.exist.and.to.be.a('object');
+ const payload2 = request2.data;
+ expect(payload2.imp[0]).to.have.property('id', REQUEST[1].bidId);
});
});
@@ -185,3 +191,201 @@ describe('pangle bid adapter', function () {
});
});
});
+
+describe('Pangle Adapter with video', function() {
+ const videoBidRequest = [
+ {
+ bidId: '2820132fe18114',
+ mediaTypes: { video: { context: 'outstream', playerSize: [[300, 250]] } },
+ params: { token: 'test-token' }
+ }
+ ];
+ const bidderRequest = {
+ refererInfo: {
+ referer: 'https://example.com'
+ }
+ };
+ const serverResponse = {
+ 'headers': null,
+ 'body': {
+ 'id': '233f1693-68d1-470a-ad85-c156c3faaf6f',
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'id': '2820132fe18114',
+ 'impid': '2820132fe18114',
+ 'price': 0.03294,
+ 'nurl': 'https://api16-event-sg2.pangle.io/api/ad/union/openrtb/win/?req_id=233f1693-68d1-470a-ad85-c156c3faaf6fu1450&ttdsp_adx_index=256&rit=980589944&extra=oqveoB%2Bg4%2ByNz9L8wwu%2Fy%2FwKxQsGaKsJHuB4NMK77uqZ9%2FJKpnsVZculJX8%2FxrRBAtaktU1DRN%2Fy6TKAqibCbj%2FM3%2BZ6biAKQG%2BCyt4eIV0KVvri9jCCnaajbkN7YNJWJJw2lW6cJ6Va3SuJG9H7a%2FAJd2PMbhK7fXWhoW72TwgOcKHKBgjM6sNDISBKbWlZyY3L1PhKSX%2FM8LOvL6qahsb%2FDpEObIx24vhQLNWp28XY1L4UqeibuRjam3eCvN7nXoQq74KkJ45QQsTgvV4j6I6EbLOdjOi%2FURhWMDjUD1VCMpqUT%2B6L8ZROgrX9Tp53eJ3bFOczmSTOmDSazKMHa%2B3uZZ7JHcSx32eoY4hfYc99NOJmYBKXNKCmoXyJvS3PCM3PlAz97hKrDMGnVv1wAQ7QGDCbittF0vZwtsRAvvx2mWINNIB3%2FUB2PjhxFsoDA%2BWE2urVZwEdyu%2FJrCznJsMwenXjcbMD5jmUF5vDkkLS%2B7TMDIEawJPJKZ62pK35enrwGxCs6ePXi21rJJkA0bF8tgAdl4mU1illBIVO4kCL%2ByRASskHPjgg%2FcdFe9HP%2Fi8byjAprH%2BhRerN%2FRKFxC3xv8b75x2pb1g7dY%2FTj9IjT0evsBSPVwFNqtKmPId35IcY%2FSXiqPHh%2FrAHZzr5BPsTT19P49SlNMR9UZYTzViX1iJpcCL1UFjuDdrdff%2BhHCviXxo%2FkRmufEF3umHZwxbdDOPAghuZ0DtRCY6S1rnb%2FK9BbpsVKSndOtgfCwMHFwiPmdw1XjEXGc1eOWXY6qfSp90PIfL6WS7Neh3ba2qMv6WxG3HSOBYvrcCqVTsNxk4UdVm3qb1J0CMVByweTMo45usSkCTdvX3JuEB7tVA6%2BrEk57b3XJd5Phf2AN8hon%2F7lmcXE41kwMQuXq89ViwQmW0G247UFWOQx4t1cmBqFiP6qNA%2F%2BunkZDno1pmAsGnTv7Mz9xtpOaIqKl8BKrVQSTopZ9WcUVzdBUutF19mn1f43BvyA9gIEhcDJHOj&win_price=${AUCTION_PRICE}&auction_mwb=${AUCTION_BID_TO_WIN}&use_pb=1',
+ 'lurl': 'https://api16-event-sg2.pangle.io/api/ad/union/openrtb/loss/?req_id=233f1693-68d1-470a-ad85-c156c3faaf6fu1450&ttdsp_adx_index=256&rit=980589944&extra=oqveoB%2Bg4%2ByNz9L8wwu%2Fy%2FwKxQsGaKsJHuB4NMK77uqZ9%2FJKpnsVZculJX8%2FxrRBAtaktU1DRN%2Fy6TKAqibCbj%2FM3%2BZ6biAKQG%2BCyt4eIV0KVvri9jCCnaajbkN7YNJWJJw2lW6cJ6Va3SuJG9H7a%2FAJd2PMbhK7fXWhoW72TwgOcKHKBgjM6sNDISBKbWlZyY3L1PhKSX%2FM8LOvL6qahsb%2FDpEObIx24vhQLNWp28XY1L4UqeibuRjam3eCvN7nXoQq74KkJ45QQsTgvV4j6I6EbLOdjOi%2FURhWMDjUD1VCMpqUT%2B6L8ZROgrX9Tp53eJ3bFOczmSTOmDSazKMHa%2B3uZZ7JHcSx32eoY4hfYc99NOJmYBKXNKCmoXyJvS3PCM3PlAz97hKrDMGnVv1wAQ7QGDCbittF0vZwtsRAvvx2mWINNIB3%2FUB2PjhxFsoDA%2BWE2urVZwEdyu%2FJrCznJsMwenXjcbMD5jmUF5vDkkLS%2B7TMDIEawJPJKZ62pK35enrwGxCs6ePXi21rJJkA0bF8tgAdl4mU1illBIVO4kCL%2ByRASskHPjgg%2FcdFe9HP%2Fi8byjAprH%2BhRerN%2FRKFxC3xv8b75x2pb1g7dY%2FTj9IjT0evsBSPVwFNqtKmPId35IcY%2FSXiqPHh%2FrAHZzr5BPsTT19P49SlNMR9UZYTzViX1iJpcCL1UFjuDdrdff%2BhHCviXxo%2FkRmufEF3umHZwxbdDOPAghuZ0DtRCY6S1rnb%2FK9BbpsVKSndOtgfCwMHFwiPmdw1XjEXGc1eOWXY6qfSp90PIfL6WS7Neh3ba2qMv6WxG3HSOBYvrcCqVTsNxk4UdVm3qb1J0CMVByweTMo45usSkCTdvX3JuEB7tVA6%2BrEk57b3XJd5Phf2AN8hon%2F7lmcXE41kwMQuXq89ViwQmW0G247UFWOQx4t1cmBqFiP6qNA%2F%2BunkZDno1pmAsGnTv7Mz9xtpOaIqKl8BKrVQSTopZ9WcUVzdBUutF19mn1f43BvyA9gIEhcDJHOj&reason=${AUCTION_LOSS}&ad_slot_type=8&auction_mwb=${AUCTION_PRICE}&use_pb=1',
+ 'adm': '
',
+ 'adid': '1780626232977441',
+ 'adomain': [
+ 'swi.esxcmnb.com'
+ ],
+ 'iurl': 'https://p16-ttam-va.ibyteimg.com/origin/ad-site-i18n-sg/202310245d0d598b3ff5993c4f129a8b',
+ 'cid': '1780626232977441',
+ 'crid': '1780626232977441',
+ 'attr': [
+ 4
+ ],
+ 'w': 640,
+ 'h': 640,
+ 'mtype': 1,
+ 'ext': {
+ 'pangle': {
+ 'adtype': 8
+ },
+ 'event_notification_token': {
+ 'payload': '980589944:8:1450:7492'
+ }
+ }
+ }
+ ],
+ 'seat': 'pangle'
+ }
+ ]
+ }
+ };
+
+ describe('Video: buildRequests', function() {
+ it('should create a POST request for video bid', function() {
+ const requests = spec.buildRequests(videoBidRequest, bidderRequest);
+ expect(requests[0].method).to.equal('POST');
+ });
+
+ it('should have a valid URL and payload for an out-stream video bid', function () {
+ const requests = spec.buildRequests(videoBidRequest, bidderRequest);
+ expect(requests[0].url).to.equal('https://pangle.pangleglobal.com/api/ad/union/web_js/common/get_ads');
+ expect(requests[0].data).to.exist;
+ });
+ });
+
+ describe('interpretResponse: Video', function () {
+ it('should get correct bid response', function () {
+ const request = spec.buildRequests(videoBidRequest, bidderRequest)[0];
+ const interpretedResponse = spec.interpretResponse(serverResponse, request);
+ expect(interpretedResponse).to.be.an('array');
+ const bid = interpretedResponse[0];
+ expect(bid).to.exist;
+ expect(bid.requestId).to.exist;
+ expect(bid.cpm).to.be.above(0);
+ expect(bid.ttl).to.exist;
+ expect(bid.creativeId).to.exist;
+ if (bid.renderer) {
+ expect(bid.renderer.render).to.exist;
+ }
+ });
+ });
+});
+
+describe('pangle multi-format ads', function () {
+ const bidderRequest = {
+ refererInfo: {
+ referer: 'https://example.com'
+ }
+ };
+ const multiRequest = [
+ {
+ bidId: '2820132fe18114',
+ mediaTypes: { banner: { sizes: [[300, 250]] }, video: { context: 'outstream', playerSize: [[300, 250]] } },
+ params: { token: 'test-token' }
+ }
+ ];
+ const videoResponse = {
+ 'headers': null,
+ 'body': {
+ 'id': '233f1693-68d1-470a-ad85-c156c3faaf6f',
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'id': '2820132fe18114',
+ 'impid': '2820132fe18114',
+ 'price': 0.03294,
+ 'nurl': 'https://api16-event-sg2.pangle.io/api/ad/union/openrtb/win/?req_id=233f1693-68d1-470a-ad85-c156c3faaf6fu1450&ttdsp_adx_index=256&rit=980589944&extra=oqveoB%2Bg4%2ByNz9L8wwu%2Fy%2FwKxQsGaKsJHuB4NMK77uqZ9%2FJKpnsVZculJX8%2FxrRBAtaktU1DRN%2Fy6TKAqibCbj%2FM3%2BZ6biAKQG%2BCyt4eIV0KVvri9jCCnaajbkN7YNJWJJw2lW6cJ6Va3SuJG9H7a%2FAJd2PMbhK7fXWhoW72TwgOcKHKBgjM6sNDISBKbWlZyY3L1PhKSX%2FM8LOvL6qahsb%2FDpEObIx24vhQLNWp28XY1L4UqeibuRjam3eCvN7nXoQq74KkJ45QQsTgvV4j6I6EbLOdjOi%2FURhWMDjUD1VCMpqUT%2B6L8ZROgrX9Tp53eJ3bFOczmSTOmDSazKMHa%2B3uZZ7JHcSx32eoY4hfYc99NOJmYBKXNKCmoXyJvS3PCM3PlAz97hKrDMGnVv1wAQ7QGDCbittF0vZwtsRAvvx2mWINNIB3%2FUB2PjhxFsoDA%2BWE2urVZwEdyu%2FJrCznJsMwenXjcbMD5jmUF5vDkkLS%2B7TMDIEawJPJKZ62pK35enrwGxCs6ePXi21rJJkA0bF8tgAdl4mU1illBIVO4kCL%2ByRASskHPjgg%2FcdFe9HP%2Fi8byjAprH%2BhRerN%2FRKFxC3xv8b75x2pb1g7dY%2FTj9IjT0evsBSPVwFNqtKmPId35IcY%2FSXiqPHh%2FrAHZzr5BPsTT19P49SlNMR9UZYTzViX1iJpcCL1UFjuDdrdff%2BhHCviXxo%2FkRmufEF3umHZwxbdDOPAghuZ0DtRCY6S1rnb%2FK9BbpsVKSndOtgfCwMHFwiPmdw1XjEXGc1eOWXY6qfSp90PIfL6WS7Neh3ba2qMv6WxG3HSOBYvrcCqVTsNxk4UdVm3qb1J0CMVByweTMo45usSkCTdvX3JuEB7tVA6%2BrEk57b3XJd5Phf2AN8hon%2F7lmcXE41kwMQuXq89ViwQmW0G247UFWOQx4t1cmBqFiP6qNA%2F%2BunkZDno1pmAsGnTv7Mz9xtpOaIqKl8BKrVQSTopZ9WcUVzdBUutF19mn1f43BvyA9gIEhcDJHOj&win_price=${AUCTION_PRICE}&auction_mwb=${AUCTION_BID_TO_WIN}&use_pb=1',
+ 'lurl': 'https://api16-event-sg2.pangle.io/api/ad/union/openrtb/loss/?req_id=233f1693-68d1-470a-ad85-c156c3faaf6fu1450&ttdsp_adx_index=256&rit=980589944&extra=oqveoB%2Bg4%2ByNz9L8wwu%2Fy%2FwKxQsGaKsJHuB4NMK77uqZ9%2FJKpnsVZculJX8%2FxrRBAtaktU1DRN%2Fy6TKAqibCbj%2FM3%2BZ6biAKQG%2BCyt4eIV0KVvri9jCCnaajbkN7YNJWJJw2lW6cJ6Va3SuJG9H7a%2FAJd2PMbhK7fXWhoW72TwgOcKHKBgjM6sNDISBKbWlZyY3L1PhKSX%2FM8LOvL6qahsb%2FDpEObIx24vhQLNWp28XY1L4UqeibuRjam3eCvN7nXoQq74KkJ45QQsTgvV4j6I6EbLOdjOi%2FURhWMDjUD1VCMpqUT%2B6L8ZROgrX9Tp53eJ3bFOczmSTOmDSazKMHa%2B3uZZ7JHcSx32eoY4hfYc99NOJmYBKXNKCmoXyJvS3PCM3PlAz97hKrDMGnVv1wAQ7QGDCbittF0vZwtsRAvvx2mWINNIB3%2FUB2PjhxFsoDA%2BWE2urVZwEdyu%2FJrCznJsMwenXjcbMD5jmUF5vDkkLS%2B7TMDIEawJPJKZ62pK35enrwGxCs6ePXi21rJJkA0bF8tgAdl4mU1illBIVO4kCL%2ByRASskHPjgg%2FcdFe9HP%2Fi8byjAprH%2BhRerN%2FRKFxC3xv8b75x2pb1g7dY%2FTj9IjT0evsBSPVwFNqtKmPId35IcY%2FSXiqPHh%2FrAHZzr5BPsTT19P49SlNMR9UZYTzViX1iJpcCL1UFjuDdrdff%2BhHCviXxo%2FkRmufEF3umHZwxbdDOPAghuZ0DtRCY6S1rnb%2FK9BbpsVKSndOtgfCwMHFwiPmdw1XjEXGc1eOWXY6qfSp90PIfL6WS7Neh3ba2qMv6WxG3HSOBYvrcCqVTsNxk4UdVm3qb1J0CMVByweTMo45usSkCTdvX3JuEB7tVA6%2BrEk57b3XJd5Phf2AN8hon%2F7lmcXE41kwMQuXq89ViwQmW0G247UFWOQx4t1cmBqFiP6qNA%2F%2BunkZDno1pmAsGnTv7Mz9xtpOaIqKl8BKrVQSTopZ9WcUVzdBUutF19mn1f43BvyA9gIEhcDJHOj&reason=${AUCTION_LOSS}&ad_slot_type=8&auction_mwb=${AUCTION_PRICE}&use_pb=1',
+ 'adm': '
',
+ 'adid': '1780626232977441',
+ 'adomain': [
+ 'swi.esxcmnb.com'
+ ],
+ 'iurl': 'https://p16-ttam-va.ibyteimg.com/origin/ad-site-i18n-sg/202310245d0d598b3ff5993c4f129a8b',
+ 'cid': '1780626232977441',
+ 'crid': '1780626232977441',
+ 'attr': [
+ 4
+ ],
+ 'w': 640,
+ 'h': 640,
+ 'mtype': 2,
+ 'ext': {
+ 'pangle': {
+ 'adtype': 8
+ },
+ 'event_notification_token': {
+ 'payload': '980589944:8:1450:7492'
+ }
+ }
+ }
+ ],
+ 'seat': 'pangle'
+ }
+ ]
+ }
+ };
+ const bannerResponse = {
+ 'headers': null,
+ 'body': {
+ 'id': '233f1693-68d1-470a-ad85-c156c3faaf6f',
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'id': '2820132fe18114',
+ 'impid': '2820132fe18114',
+ 'price': 0.03294,
+ 'nurl': 'https://api16-event-sg2.pangle.io/api/ad/union/openrtb/win/?req_id=233f1693-68d1-470a-ad85-c156c3faaf6fu1450&ttdsp_adx_index=256&rit=980589944&extra=oqveoB%2Bg4%2ByNz9L8wwu%2Fy%2FwKxQsGaKsJHuB4NMK77uqZ9%2FJKpnsVZculJX8%2FxrRBAtaktU1DRN%2Fy6TKAqibCbj%2FM3%2BZ6biAKQG%2BCyt4eIV0KVvri9jCCnaajbkN7YNJWJJw2lW6cJ6Va3SuJG9H7a%2FAJd2PMbhK7fXWhoW72TwgOcKHKBgjM6sNDISBKbWlZyY3L1PhKSX%2FM8LOvL6qahsb%2FDpEObIx24vhQLNWp28XY1L4UqeibuRjam3eCvN7nXoQq74KkJ45QQsTgvV4j6I6EbLOdjOi%2FURhWMDjUD1VCMpqUT%2B6L8ZROgrX9Tp53eJ3bFOczmSTOmDSazKMHa%2B3uZZ7JHcSx32eoY4hfYc99NOJmYBKXNKCmoXyJvS3PCM3PlAz97hKrDMGnVv1wAQ7QGDCbittF0vZwtsRAvvx2mWINNIB3%2FUB2PjhxFsoDA%2BWE2urVZwEdyu%2FJrCznJsMwenXjcbMD5jmUF5vDkkLS%2B7TMDIEawJPJKZ62pK35enrwGxCs6ePXi21rJJkA0bF8tgAdl4mU1illBIVO4kCL%2ByRASskHPjgg%2FcdFe9HP%2Fi8byjAprH%2BhRerN%2FRKFxC3xv8b75x2pb1g7dY%2FTj9IjT0evsBSPVwFNqtKmPId35IcY%2FSXiqPHh%2FrAHZzr5BPsTT19P49SlNMR9UZYTzViX1iJpcCL1UFjuDdrdff%2BhHCviXxo%2FkRmufEF3umHZwxbdDOPAghuZ0DtRCY6S1rnb%2FK9BbpsVKSndOtgfCwMHFwiPmdw1XjEXGc1eOWXY6qfSp90PIfL6WS7Neh3ba2qMv6WxG3HSOBYvrcCqVTsNxk4UdVm3qb1J0CMVByweTMo45usSkCTdvX3JuEB7tVA6%2BrEk57b3XJd5Phf2AN8hon%2F7lmcXE41kwMQuXq89ViwQmW0G247UFWOQx4t1cmBqFiP6qNA%2F%2BunkZDno1pmAsGnTv7Mz9xtpOaIqKl8BKrVQSTopZ9WcUVzdBUutF19mn1f43BvyA9gIEhcDJHOj&win_price=${AUCTION_PRICE}&auction_mwb=${AUCTION_BID_TO_WIN}&use_pb=1',
+ 'lurl': 'https://api16-event-sg2.pangle.io/api/ad/union/openrtb/loss/?req_id=233f1693-68d1-470a-ad85-c156c3faaf6fu1450&ttdsp_adx_index=256&rit=980589944&extra=oqveoB%2Bg4%2ByNz9L8wwu%2Fy%2FwKxQsGaKsJHuB4NMK77uqZ9%2FJKpnsVZculJX8%2FxrRBAtaktU1DRN%2Fy6TKAqibCbj%2FM3%2BZ6biAKQG%2BCyt4eIV0KVvri9jCCnaajbkN7YNJWJJw2lW6cJ6Va3SuJG9H7a%2FAJd2PMbhK7fXWhoW72TwgOcKHKBgjM6sNDISBKbWlZyY3L1PhKSX%2FM8LOvL6qahsb%2FDpEObIx24vhQLNWp28XY1L4UqeibuRjam3eCvN7nXoQq74KkJ45QQsTgvV4j6I6EbLOdjOi%2FURhWMDjUD1VCMpqUT%2B6L8ZROgrX9Tp53eJ3bFOczmSTOmDSazKMHa%2B3uZZ7JHcSx32eoY4hfYc99NOJmYBKXNKCmoXyJvS3PCM3PlAz97hKrDMGnVv1wAQ7QGDCbittF0vZwtsRAvvx2mWINNIB3%2FUB2PjhxFsoDA%2BWE2urVZwEdyu%2FJrCznJsMwenXjcbMD5jmUF5vDkkLS%2B7TMDIEawJPJKZ62pK35enrwGxCs6ePXi21rJJkA0bF8tgAdl4mU1illBIVO4kCL%2ByRASskHPjgg%2FcdFe9HP%2Fi8byjAprH%2BhRerN%2FRKFxC3xv8b75x2pb1g7dY%2FTj9IjT0evsBSPVwFNqtKmPId35IcY%2FSXiqPHh%2FrAHZzr5BPsTT19P49SlNMR9UZYTzViX1iJpcCL1UFjuDdrdff%2BhHCviXxo%2FkRmufEF3umHZwxbdDOPAghuZ0DtRCY6S1rnb%2FK9BbpsVKSndOtgfCwMHFwiPmdw1XjEXGc1eOWXY6qfSp90PIfL6WS7Neh3ba2qMv6WxG3HSOBYvrcCqVTsNxk4UdVm3qb1J0CMVByweTMo45usSkCTdvX3JuEB7tVA6%2BrEk57b3XJd5Phf2AN8hon%2F7lmcXE41kwMQuXq89ViwQmW0G247UFWOQx4t1cmBqFiP6qNA%2F%2BunkZDno1pmAsGnTv7Mz9xtpOaIqKl8BKrVQSTopZ9WcUVzdBUutF19mn1f43BvyA9gIEhcDJHOj&reason=${AUCTION_LOSS}&ad_slot_type=8&auction_mwb=${AUCTION_PRICE}&use_pb=1',
+ 'adm': '
',
+ 'adid': '1780626232977441',
+ 'adomain': [
+ 'swi.esxcmnb.com'
+ ],
+ 'iurl': 'https://p16-ttam-va.ibyteimg.com/origin/ad-site-i18n-sg/202310245d0d598b3ff5993c4f129a8b',
+ 'cid': '1780626232977441',
+ 'crid': '1780626232977441',
+ 'attr': [
+ 4
+ ],
+ 'w': 640,
+ 'h': 640,
+ 'mtype': 1,
+ 'ext': {
+ 'pangle': {
+ 'adtype': 8
+ },
+ 'event_notification_token': {
+ 'payload': '980589944:8:1450:7492'
+ }
+ }
+ }
+ ],
+ 'seat': 'pangle'
+ }
+ ]
+ }
+ };
+ it('should set mediaType to banner', function() {
+ const request = spec.buildRequests(multiRequest, bidderRequest)[0];
+ const interpretedResponse = spec.interpretResponse(bannerResponse, request);
+ const bid = interpretedResponse[0];
+ expect(bid.mediaType).to.equal('banner');
+ })
+ it('should set mediaType to video', function() {
+ const request = spec.buildRequests(multiRequest, bidderRequest)[0];
+ const interpretedResponse = spec.interpretResponse(videoResponse, request);
+ const bid = interpretedResponse[0];
+ expect(bid.mediaType).to.equal('video');
+ })
+});
diff --git a/test/spec/modules/pgamsspBidAdapter_spec.js b/test/spec/modules/pgamsspBidAdapter_spec.js
index 7e2323d4b81..0766219eda8 100644
--- a/test/spec/modules/pgamsspBidAdapter_spec.js
+++ b/test/spec/modules/pgamsspBidAdapter_spec.js
@@ -145,6 +145,7 @@ describe('PGAMBidAdapter', function () {
expect(placement.schain).to.be.an('object');
expect(placement.bidfloor).to.exist.and.to.equal(0);
expect(placement.type).to.exist.and.to.equal('publisher');
+ expect(placement.eids).to.exist.and.to.be.an('array');
if (placement.adFormat === BANNER) {
expect(placement.sizes).to.be.an('array');
diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js
index ecace22f97f..2bab144dae7 100644
--- a/test/spec/modules/prebidServerBidAdapter_spec.js
+++ b/test/spec/modules/prebidServerBidAdapter_spec.js
@@ -14,7 +14,6 @@ import {config} from 'src/config.js';
import * as events from 'src/events.js';
import CONSTANTS from 'src/constants.json';
import {server} from 'test/mocks/xhr.js';
-import {createEidsArray} from 'modules/userId/eids.js';
import 'modules/appnexusBidAdapter.js'; // appnexus alias test
import 'modules/rubiconBidAdapter.js'; // rubicon alias test
import 'src/prebid.js'; // $$PREBID_GLOBAL$$.aliasBidder test
@@ -34,11 +33,9 @@ import {auctionManager} from '../../../src/auctionManager.js';
import {stubAuctionIndex} from '../../helpers/indexStub.js';
import {addComponentAuction, registerBidder} from 'src/adapters/bidderFactory.js';
import {getGlobal} from '../../../src/prebidGlobal.js';
-import {syncAddFPDEnrichments, syncAddFPDToBidderRequest} from '../../helpers/fpd.js';
+import {syncAddFPDToBidderRequest} from '../../helpers/fpd.js';
import {deepSetValue} from '../../../src/utils.js';
-import {sandbox} from 'sinon';
import {ACTIVITY_TRANSMIT_UFPD} from '../../../src/activities/activities.js';
-import {activityParams} from '../../../src/activities/activityParams.js';
import {MODULE_TYPE_PREBID} from '../../../src/activities/modules.js';
let CONFIG = {
@@ -94,6 +91,7 @@ const REQUEST = {
}
},
'transactionId': '4ef956ad-fd83-406d-bd35-e4bb786ab86c',
+ 'adUnitId': 'au-id-1',
'bids': [
{
'bid_id': '123',
@@ -2054,7 +2052,7 @@ describe('S2S Adapter', function () {
const bidRequests = utils.deepClone(BID_REQUESTS);
adapter.callBids(REQUEST, bidRequests, addBidResponse, done, ajax);
- const parsedRequestBody = JSON.parse(server.requests[1].requestBody);
+ const parsedRequestBody = JSON.parse(server.requests.find(req => req.method === 'POST').requestBody);
expect(parsedRequestBody.cur).to.deep.equal(['NZ']);
});
@@ -2885,6 +2883,32 @@ describe('S2S Adapter', function () {
})
})
+ describe('calls done', () => {
+ let success, error;
+ beforeEach(() => {
+ const mockAjax = function (_, callback) {
+ ({success, error} = callback);
+ }
+ config.setConfig({ s2sConfig: CONFIG });
+ adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, mockAjax);
+ })
+
+ it('passing timedOut = false on succcess', () => {
+ success({});
+ sinon.assert.calledWith(done, false);
+ });
+
+ Object.entries({
+ 'timeouts': true,
+ 'other errors': false
+ }).forEach(([t, timedOut]) => {
+ it(`passing timedOut = ${timedOut} on ${t}`, () => {
+ error('', {timedOut});
+ sinon.assert.calledWith(done, timedOut);
+ })
+ })
+ })
+
// TODO: test dependent on pbjs_api_spec. Needs to be isolated
it('does not call addBidResponse and calls done when ad unit not set', function () {
config.setConfig({ s2sConfig: CONFIG });
@@ -3425,29 +3449,6 @@ describe('S2S Adapter', function () {
});
});
describe('when the response contains ext.prebid.fledge', () => {
- let fledgeStub, request, bidderRequests;
-
- function fledgeHook(next, ...args) {
- fledgeStub(...args);
- }
-
- before(() => {
- addComponentAuction.before(fledgeHook);
- });
-
- after(() => {
- addComponentAuction.getHooks({hook: fledgeHook}).remove();
- })
-
- beforeEach(function () {
- fledgeStub = sinon.stub();
- config.setConfig({CONFIG});
- request = deepClone(REQUEST);
- request.ad_units.forEach(au => deepSetValue(au, 'ortb2Imp.ext.ae', 1));
- bidderRequests = deepClone(BID_REQUESTS);
- bidderRequests.forEach(req => req.fledgeEnabled = true);
- });
-
const AU = 'div-gpt-ad-1460505748561-0';
const FLEDGE_RESP = {
ext: {
@@ -3456,12 +3457,14 @@ describe('S2S Adapter', function () {
auctionconfigs: [
{
impid: AU,
+ bidder: 'appnexus',
config: {
id: 1
}
},
{
impid: AU,
+ bidder: 'other',
config: {
id: 2
}
@@ -3472,20 +3475,62 @@ describe('S2S Adapter', function () {
}
}
+ let fledgeStub, request, bidderRequests;
+
+ function fledgeHook(next, ...args) {
+ fledgeStub(...args);
+ }
+
+ before(() => {
+ addComponentAuction.before(fledgeHook);
+ });
+
+ after(() => {
+ addComponentAuction.getHooks({hook: fledgeHook}).remove();
+ })
+
+ beforeEach(function () {
+ fledgeStub = sinon.stub();
+ config.setConfig({CONFIG});
+ bidderRequests = deepClone(BID_REQUESTS);
+ AU
+ bidderRequests.forEach(req => {
+ Object.assign(req, {
+ fledgeEnabled: true,
+ ortb2: {
+ fpd: 1
+ }
+ })
+ req.bids.forEach(bid => {
+ Object.assign(bid, {
+ ortb2Imp: {
+ fpd: 2
+ }
+ })
+ })
+ });
+ request = deepClone(REQUEST);
+ request.ad_units.forEach(au => deepSetValue(au, 'ortb2Imp.ext.ae', 1));
+ });
+
+ function expectFledgeCalls() {
+ const auctionId = bidderRequests[0].auctionId;
+ sinon.assert.calledWith(fledgeStub, sinon.match({auctionId, adUnitCode: AU, ortb2: bidderRequests[0].ortb2, ortb2Imp: bidderRequests[0].bids[0].ortb2Imp}), {id: 1})
+ sinon.assert.calledWith(fledgeStub, sinon.match({auctionId, adUnitCode: AU, ortb2: undefined, ortb2Imp: undefined}), {id: 2})
+ }
+
it('calls addComponentAuction alongside addBidResponse', function () {
adapter.callBids(request, bidderRequests, addBidResponse, done, ajax);
server.requests[0].respond(200, {}, JSON.stringify(mergeDeep({}, RESPONSE_OPENRTB, FLEDGE_RESP)));
expect(addBidResponse.called).to.be.true;
- sinon.assert.calledWith(fledgeStub, bidderRequests[0].auctionId, AU, {id: 1});
- sinon.assert.calledWith(fledgeStub, bidderRequests[0].auctionId, AU, {id: 2});
+ expectFledgeCalls();
});
it('calls addComponentAuction when there is no bid in the response', () => {
adapter.callBids(request, bidderRequests, addBidResponse, done, ajax);
server.requests[0].respond(200, {}, JSON.stringify(FLEDGE_RESP));
expect(addBidResponse.called).to.be.false;
- sinon.assert.calledWith(fledgeStub, bidderRequests[0].auctionId, AU, {id: 1});
- sinon.assert.calledWith(fledgeStub, bidderRequests[0].auctionId, AU, {id: 2});
+ expectFledgeCalls();
})
});
});
@@ -3743,6 +3788,74 @@ describe('S2S Adapter', function () {
})
});
+ it('should configure the s2sConfig object with openwrap vendor defaults unless specified by user', function () {
+ const options = {
+ accountId: '1234',
+ bidders: ['pubmatic'],
+ defaultVendor: 'openwrap'
+ };
+
+ config.setConfig({ s2sConfig: options });
+ sinon.assert.notCalled(logErrorSpy);
+
+ let vendorConfig = config.getConfig('s2sConfig');
+ expect(vendorConfig).to.have.property('accountId', '1234');
+ expect(vendorConfig).to.have.property('adapter', 'prebidServer');
+ expect(vendorConfig.bidders).to.deep.equal(['pubmatic']);
+ expect(vendorConfig.enabled).to.be.true;
+ expect(vendorConfig.endpoint).to.deep.equal({
+ p1Consent: 'https://ow.pubmatic.com/openrtb2/auction?source=pbjs',
+ noP1Consent: 'https://ow.pubmatic.com/openrtb2/auction?source=pbjs'
+ });
+ expect(vendorConfig).to.have.property('timeout', 500);
+ });
+
+ it('should return proper defaults', function () {
+ const options = {
+ accountId: '1234',
+ bidders: ['pubmatic'],
+ defaultVendor: 'openwrap',
+ timeout: 500
+ };
+
+ config.setConfig({ s2sConfig: options });
+ expect(config.getConfig('s2sConfig')).to.deep.equal({
+ 'accountId': '1234',
+ 'adapter': 'prebidServer',
+ 'bidders': ['pubmatic'],
+ 'defaultVendor': 'openwrap',
+ 'enabled': true,
+ 'endpoint': {
+ p1Consent: 'https://ow.pubmatic.com/openrtb2/auction?source=pbjs',
+ noP1Consent: 'https://ow.pubmatic.com/openrtb2/auction?source=pbjs'
+ },
+ 'timeout': 500
+ })
+ });
+
+ it('should return default adapterOptions if not set', function () {
+ config.setConfig({
+ s2sConfig: {
+ accountId: '1234',
+ bidders: ['pubmatic'],
+ defaultVendor: 'openwrap',
+ timeout: 500
+ }
+ });
+ expect(config.getConfig('s2sConfig')).to.deep.equal({
+ enabled: true,
+ timeout: 500,
+ adapter: 'prebidServer',
+ accountId: '1234',
+ bidders: ['pubmatic'],
+ defaultVendor: 'openwrap',
+ endpoint: {
+ p1Consent: 'https://ow.pubmatic.com/openrtb2/auction?source=pbjs',
+ noP1Consent: 'https://ow.pubmatic.com/openrtb2/auction?source=pbjs'
+ },
+ })
+ });
+
it('should set adapterOptions', function () {
config.setConfig({
s2sConfig: {
diff --git a/test/spec/modules/precisoBidAdapter_spec.js b/test/spec/modules/precisoBidAdapter_spec.js
index 1a7e24d64cb..78a1615a02e 100644
--- a/test/spec/modules/precisoBidAdapter_spec.js
+++ b/test/spec/modules/precisoBidAdapter_spec.js
@@ -22,10 +22,15 @@ describe('PrecisoAdapter', function () {
sourceid: '0',
publisherId: '0',
mediaType: 'banner',
-
region: 'prebid-eu'
- }
+ },
+ userId: {
+ pubcid: '12355454test'
+
+ },
+ geo: 'NA',
+ city: 'Asia,delhi'
};
describe('isBidRequestValid', function () {
@@ -54,7 +59,7 @@ describe('PrecisoAdapter', function () {
});
it('Returns valid data if array of bids is valid', function () {
let data = serverRequest.data;
- expect(data).to.be.an('object');
+ // expect(data).to.be.an('object');
// expect(data).to.have.all.keys('bidId', 'imp', 'site', 'deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements', 'coppa');
@@ -62,15 +67,20 @@ describe('PrecisoAdapter', function () {
expect(data.deviceHeight).to.be.a('number');
expect(data.coppa).to.be.a('number');
expect(data.language).to.be.a('string');
- expect(data.secure).to.be.within(0, 1);
+ // expect(data.secure).to.be.within(0, 1);
expect(data.host).to.be.a('string');
expect(data.page).to.be.a('string');
+
+ expect(data.city).to.be.a('string');
+ expect(data.geo).to.be.a('object');
+ // expect(data.userId).to.be.a('string');
+ // expect(data.imp).to.be.a('object');
});
- it('Returns empty data if no valid requests are passed', function () {
- serverRequest = spec.buildRequests([]);
- let data = serverRequest.data;
- expect(data.imp).to.be.an('array').that.is.empty;
- });
+ // it('Returns empty data if no valid requests are passed', function () {
+ /// serverRequest = spec.buildRequests([]);
+ // let data = serverRequest.data;
+ // expect(data.imp).to.be.an('array').that.is.empty;
+ // });
});
describe('with COPPA', function () {
@@ -135,7 +145,7 @@ describe('PrecisoAdapter', function () {
})
})
describe('getUserSyncs', function () {
- const syncUrl = 'https://ck.2trk.info/rtb/user/usersync.aspx?id=preciso_srl&gdpr=0&gdpr_consent=&us_privacy=&t=4';
+ const syncUrl = 'https://ck.2trk.info/rtb/user/usersync.aspx?id=NA&gdpr=0&gdpr_consent=&us_privacy=&t=4';
const syncOptions = {
iframeEnabled: true
};
diff --git a/test/spec/modules/priceFloors_spec.js b/test/spec/modules/priceFloors_spec.js
index 950e039491d..7ea7722b12a 100644
--- a/test/spec/modules/priceFloors_spec.js
+++ b/test/spec/modules/priceFloors_spec.js
@@ -12,7 +12,7 @@ import {
isFloorsDataValid,
addBidResponseHook,
fieldMatchingFunctions,
- allowedFields, parseFloorData, normalizeDefault, getFloorDataFromAdUnits
+ allowedFields, parseFloorData, normalizeDefault, getFloorDataFromAdUnits, updateAdUnitsForAuction, createFloorsDataForAuction
} from 'modules/priceFloors.js';
import * as events from 'src/events.js';
import * as mockGpt from '../integration/faker/googletag.js';
@@ -116,7 +116,8 @@ describe('the price floors module', function () {
bidder: 'rubicon',
adUnitCode: 'test_div_1',
auctionId: '1234-56-789',
- transactionId: 'tr_test_div_1'
+ transactionId: 'tr_test_div_1',
+ adUnitId: 'tr_test_div_1',
};
function getAdUnitMock(code = 'adUnit-code') {
@@ -618,8 +619,8 @@ describe('the price floors module', function () {
});
});
it('picks the gptSlot from the adUnit and does not call the slotMatching', function () {
- const newBidRequest1 = { ...basicBidRequest, transactionId: 'au1' };
- adUnits = [{code: newBidRequest1.code, transactionId: 'au1'}];
+ const newBidRequest1 = { ...basicBidRequest, adUnitId: 'au1' };
+ adUnits = [{code: newBidRequest1.adUnitCode, adUnitId: 'au1'}];
utils.deepSetValue(adUnits[0], 'ortb2Imp.ext.data.adserver', {
name: 'gam',
adslot: '/12345/news/politics'
@@ -632,8 +633,8 @@ describe('the price floors module', function () {
matchingRule: '/12345/news/politics'
});
- const newBidRequest2 = { ...basicBidRequest, adUnitCode: 'test_div_2', transactionId: 'au2' };
- adUnits = [{code: newBidRequest2.adUnitCode, transactionId: newBidRequest2.transactionId}];
+ const newBidRequest2 = { ...basicBidRequest, adUnitCode: 'test_div_2', adUnitId: 'au2' };
+ adUnits = [{code: newBidRequest2.adUnitCode, adUnitId: newBidRequest2.adUnitId}];
utils.deepSetValue(adUnits[0], 'ortb2Imp.ext.data.adserver', {
name: 'gam',
adslot: '/12345/news/weather'
@@ -648,6 +649,107 @@ describe('the price floors module', function () {
});
});
});
+
+ describe('updateAdUnitsForAuction', function() {
+ let inputFloorData;
+ let adUnits;
+
+ beforeEach(function() {
+ adUnits = [getAdUnitMock()];
+ inputFloorData = utils.deepClone(minFloorConfigLow);
+ inputFloorData.skipRate = 0.5;
+ });
+
+ it('should set the skipRate to the skipRate from the data property before using the skipRate from floorData directly', function() {
+ utils.deepSetValue(inputFloorData, 'data', {
+ skipRate: 0.7
+ });
+ updateAdUnitsForAuction(adUnits, inputFloorData, 'id');
+
+ const skipRate = utils.deepAccess(adUnits, '0.bids.0.floorData.skipRate');
+ expect(skipRate).to.equal(0.7);
+ });
+
+ it('should set the skipRate to the skipRate from floorData directly if it does not exist in the data property of floorData', function() {
+ updateAdUnitsForAuction(adUnits, inputFloorData, 'id');
+
+ const skipRate = utils.deepAccess(adUnits, '0.bids.0.floorData.skipRate');
+ expect(skipRate).to.equal(0.5);
+ });
+
+ it('should set the skipRate in the bid floorData to undefined if both skipRate and skipRate in the data property are undefined', function() {
+ inputFloorData.skipRate = undefined;
+ utils.deepSetValue(inputFloorData, 'data', {
+ skipRate: undefined,
+ });
+ updateAdUnitsForAuction(adUnits, inputFloorData, 'id');
+
+ const skipRate = utils.deepAccess(adUnits, '0.bids.0.floorData.skipRate');
+ expect(skipRate).to.equal(undefined);
+ });
+ });
+
+ describe('createFloorsDataForAuction', function() {
+ let adUnits;
+ let floorConfig;
+
+ beforeEach(function() {
+ adUnits = [getAdUnitMock()];
+ floorConfig = utils.deepClone(basicFloorConfig);
+ });
+
+ it('should return skipRate as 0 if both skipRate and skipRate in the data property are undefined', function() {
+ floorConfig.skipRate = undefined;
+ floorConfig.data.skipRate = undefined;
+ handleSetFloorsConfig(floorConfig);
+
+ const floorData = createFloorsDataForAuction(adUnits, 'id');
+
+ expect(floorData.skipRate).to.equal(0);
+ expect(floorData.skipped).to.equal(false);
+ });
+
+ it('should properly set skipRate if it is available in the data property', function() {
+ // this will force skipped to be true
+ floorConfig.skipRate = 101;
+ floorConfig.data.skipRate = 201;
+ handleSetFloorsConfig(floorConfig);
+
+ const floorData = createFloorsDataForAuction(adUnits, 'id');
+
+ expect(floorData.data.skipRate).to.equal(201);
+ expect(floorData.skipped).to.equal(true);
+ });
+
+ it('should should use the skipRate if its not available in the data property ', function() {
+ // this will force skipped to be true
+ floorConfig.skipRate = 101;
+ handleSetFloorsConfig(floorConfig);
+
+ const floorData = createFloorsDataForAuction(adUnits, 'id');
+
+ expect(floorData.skipRate).to.equal(101);
+ expect(floorData.skipped).to.equal(true);
+ });
+
+ it('should have skippedReason set to "not_found" if there is no valid floor data', function() {
+ floorConfig.data = {}
+ handleSetFloorsConfig(floorConfig);
+
+ const floorData = createFloorsDataForAuction(adUnits, 'id');
+ expect(floorData.skippedReason).to.equal(CONSTANTS.FLOOR_SKIPPED_REASON.NOT_FOUND);
+ });
+
+ it('should have skippedReason set to "random" if there is floor data and skipped is true', function() {
+ // this will force skipped to be true
+ floorConfig.skipRate = 101;
+ handleSetFloorsConfig(floorConfig);
+
+ const floorData = createFloorsDataForAuction(adUnits, 'id');
+ expect(floorData.skippedReason).to.equal(CONSTANTS.FLOOR_SKIPPED_REASON.RANDOM);
+ });
+ });
+
describe('pre-auction tests', function () {
let exposedAdUnits;
const validateBidRequests = (getFloorExpected, FloorDataExpected) => {
@@ -689,6 +791,124 @@ describe('the price floors module', function () {
floorProvider: undefined
});
});
+ it('should not do floor stuff if floors.data is defined by noFloorSignalBidders[]', function() {
+ handleSetFloorsConfig({
+ ...basicFloorConfig,
+ data: {
+ ...basicFloorDataLow,
+ noFloorSignalBidders: ['someBidder', 'someOtherBidder']
+ }});
+ runStandardAuction();
+ validateBidRequests(false, {
+ skipped: false,
+ floorMin: undefined,
+ modelVersion: 'basic model',
+ modelWeight: 10,
+ modelTimestamp: undefined,
+ location: 'setConfig',
+ skipRate: 0,
+ fetchStatus: undefined,
+ floorProvider: undefined,
+ noFloorSignaled: true
+ })
+ });
+ it('should not do floor stuff if floors.enforcement is defined by noFloorSignalBidders[]', function() {
+ handleSetFloorsConfig({ ...basicFloorConfig,
+ enforcement: {
+ enforceJS: true,
+ noFloorSignalBidders: ['someBidder', 'someOtherBidder']
+ },
+ data: basicFloorDataLow
+ });
+ runStandardAuction();
+ validateBidRequests(false, {
+ skipped: false,
+ floorMin: undefined,
+ modelVersion: 'basic model',
+ modelWeight: 10,
+ modelTimestamp: undefined,
+ location: 'setConfig',
+ skipRate: 0,
+ fetchStatus: undefined,
+ floorProvider: undefined,
+ noFloorSignaled: true
+ })
+ });
+ it('should not do floor stuff and use first floors.data.noFloorSignalBidders if its defined betwen enforcement.noFloorSignalBidders', function() {
+ handleSetFloorsConfig({ ...basicFloorConfig,
+ enforcement: {
+ enforceJS: true,
+ noFloorSignalBidders: ['someBidder']
+ },
+ data: {
+ ...basicFloorDataLow,
+ noFloorSignalBidders: ['someBidder', 'someOtherBidder']
+ }
+ });
+ runStandardAuction();
+ validateBidRequests(false, {
+ skipped: false,
+ floorMin: undefined,
+ modelVersion: 'basic model',
+ modelWeight: 10,
+ modelTimestamp: undefined,
+ location: 'setConfig',
+ skipRate: 0,
+ fetchStatus: undefined,
+ floorProvider: undefined,
+ noFloorSignaled: true
+ })
+ });
+ it('it shouldn`t return floor stuff for bidder in the noFloorSignalBidders list', function() {
+ handleSetFloorsConfig({ ...basicFloorConfig,
+ enforcement: {
+ enforceJS: true,
+ },
+ data: {
+ ...basicFloorDataLow,
+ noFloorSignalBidders: ['someBidder']
+ }
+ });
+ runStandardAuction()
+ const bidRequestData = exposedAdUnits[0].bids.find(bid => bid.bidder === 'someBidder');
+ expect(bidRequestData.hasOwnProperty('getFloor')).to.equal(false);
+ sinon.assert.match(bidRequestData.floorData, {
+ skipped: false,
+ floorMin: undefined,
+ modelVersion: 'basic model',
+ modelWeight: 10,
+ modelTimestamp: undefined,
+ location: 'setConfig',
+ skipRate: 0,
+ fetchStatus: undefined,
+ floorProvider: undefined,
+ noFloorSignaled: true
+ });
+ })
+ it('it should return floor stuff if we defined wrong bidder name in data.noFloorSignalBidders', function() {
+ handleSetFloorsConfig({ ...basicFloorConfig,
+ enforcement: {
+ enforceJS: true,
+ },
+ data: {
+ ...basicFloorDataLow,
+ noFloorSignalBidders: ['randomBiider']
+ }
+ });
+ runStandardAuction();
+ validateBidRequests(true, {
+ skipped: false,
+ floorMin: undefined,
+ modelVersion: 'basic model',
+ modelWeight: 10,
+ modelTimestamp: undefined,
+ location: 'setConfig',
+ skipRate: 0,
+ fetchStatus: undefined,
+ floorProvider: undefined,
+ noFloorSignaled: false
+ })
+ });
it('should use adUnit level data if not setConfig or fetch has occured', function () {
handleSetFloorsConfig({
...basicFloorConfig,
@@ -2011,6 +2231,12 @@ describe('the price floors module', function () {
expect(returnedBidResponse).to.not.haveOwnProperty('floorData');
expect(logWarnSpy.calledOnce).to.equal(true);
});
+ it('if it finds a rule with a floor price of zero it should not call log warn', function () {
+ _floorDataForAuction[AUCTION_ID] = utils.deepClone(basicFloorConfig);
+ _floorDataForAuction[AUCTION_ID].data.values = { '*': 0 };
+ runBidResponse();
+ expect(logWarnSpy.calledOnce).to.equal(false);
+ });
it('if it finds a rule and floors should update the bid accordingly', function () {
_floorDataForAuction[AUCTION_ID] = utils.deepClone(basicFloorConfig);
_floorDataForAuction[AUCTION_ID].data.values = { 'banner': 1.0 };
@@ -2137,7 +2363,7 @@ describe('the price floors module', function () {
}
const resp = {
- transactionId: req.transactionId,
+ adUnitId: req.adUnitId,
size: [100, 100],
mediaType: 'banner',
}
@@ -2148,7 +2374,7 @@ describe('the price floors module', function () {
adUnits: [
{
code: req.adUnitCode,
- transactionId: req.transactionId,
+ adUnitId: req.adUnitId,
ortb2Imp: {ext: {data: {adserver: {name: 'gam', adslot: 'slot'}}}}
}
]
diff --git a/test/spec/modules/programmaticaBidAdapter_spec.js b/test/spec/modules/programmaticaBidAdapter_spec.js
new file mode 100644
index 00000000000..247d20752c3
--- /dev/null
+++ b/test/spec/modules/programmaticaBidAdapter_spec.js
@@ -0,0 +1,263 @@
+import { expect } from 'chai';
+import { spec } from 'modules/programmaticaBidAdapter.js';
+import { deepClone } from 'src/utils.js';
+
+describe('programmaticaBidAdapterTests', function () {
+ let bidRequestData = {
+ bids: [
+ {
+ bidId: 'testbid',
+ bidder: 'programmatica',
+ params: {
+ siteId: 'testsite',
+ placementId: 'testplacement',
+ },
+ sizes: [[300, 250]]
+ }
+ ]
+ };
+ let request = [];
+
+ it('validate_pub_params', function () {
+ expect(
+ spec.isBidRequestValid({
+ bidder: 'programmatica',
+ params: {
+ siteId: 'testsite',
+ placementId: 'testplacement',
+ }
+ })
+ ).to.equal(true);
+ });
+
+ it('validate_generated_url', function () {
+ const request = spec.buildRequests(deepClone(bidRequestData.bids), { timeout: 1234 });
+ let req_url = request[0].url;
+
+ expect(req_url).to.equal('https://asr.programmatica.com/get');
+ });
+
+ it('validate_response_params', function () {
+ let serverResponse = {
+ body: {
+ 'id': 'crid',
+ 'type': {
+ 'format': 'Image',
+ 'source': 'passback',
+ 'dspId': '',
+ 'dspCreativeId': ''
+ },
+ 'content': {
+ 'data': 'test ad',
+ 'imps': null,
+ 'click': {
+ 'url': '',
+ 'track': null
+ }
+ },
+ 'size': '300x250',
+ 'matching': '',
+ 'cpm': 10,
+ 'currency': 'USD'
+ }
+ };
+
+ const bidRequest = deepClone(bidRequestData.bids)
+ bidRequest[0].mediaTypes = {
+ banner: {}
+ }
+
+ const request = spec.buildRequests(bidRequest);
+ let bids = spec.interpretResponse(serverResponse, request[0]);
+ expect(bids).to.have.lengthOf(1);
+
+ let bid = bids[0];
+ expect(bid.ad).to.equal('test ad');
+ expect(bid.cpm).to.equal(10);
+ expect(bid.currency).to.equal('USD');
+ expect(bid.width).to.equal(300);
+ expect(bid.height).to.equal(250);
+ expect(bid.creativeId).to.equal('crid');
+ expect(bid.meta.advertiserDomains).to.deep.equal(['programmatica.com']);
+ });
+
+ it('validate_response_params_imps', function () {
+ let serverResponse = {
+ body: {
+ 'id': 'crid',
+ 'type': {
+ 'format': 'Image',
+ 'source': 'passback',
+ 'dspId': '',
+ 'dspCreativeId': ''
+ },
+ 'content': {
+ 'data': 'test ad',
+ 'imps': [
+ 'testImp'
+ ],
+ 'click': {
+ 'url': '',
+ 'track': null
+ }
+ },
+ 'size': '300x250',
+ 'matching': '',
+ 'cpm': 10,
+ 'currency': 'USD'
+ }
+ };
+
+ const bidRequest = deepClone(bidRequestData.bids)
+ bidRequest[0].mediaTypes = {
+ banner: {}
+ }
+
+ const request = spec.buildRequests(bidRequest);
+ let bids = spec.interpretResponse(serverResponse, request[0]);
+ expect(bids).to.have.lengthOf(1);
+
+ let bid = bids[0];
+ expect(bid.ad).to.equal('test ad');
+ expect(bid.cpm).to.equal(10);
+ expect(bid.currency).to.equal('USD');
+ expect(bid.width).to.equal(300);
+ expect(bid.height).to.equal(250);
+ expect(bid.creativeId).to.equal('crid');
+ expect(bid.meta.advertiserDomains).to.deep.equal(['programmatica.com']);
+ })
+
+ it('validate_invalid_response', function () {
+ let serverResponse = {
+ body: {}
+ };
+
+ const bidRequest = deepClone(bidRequestData.bids)
+ bidRequest[0].mediaTypes = {
+ banner: {}
+ }
+
+ const request = spec.buildRequests(bidRequest);
+ let bids = spec.interpretResponse(serverResponse, request[0]);
+ expect(bids).to.have.lengthOf(0);
+ })
+
+ it('video_bid', function () {
+ const bidRequest = deepClone(bidRequestData.bids);
+ bidRequest[0].mediaTypes = {
+ video: {
+ playerSize: [234, 765]
+ }
+ };
+
+ const request = spec.buildRequests(bidRequest, { timeout: 1234 });
+ const vastXml = '
';
+ let serverResponse = {
+ body: {
+ 'id': 'cki2n3n6snkuulqutpf0',
+ 'type': {
+ 'format': '',
+ 'source': 'rtb',
+ 'dspId': '1'
+ },
+ 'content': {
+ 'data': vastXml,
+ 'imps': [
+ 'https://asr.dev.programmatica.com/track/imp'
+ ],
+ 'click': {
+ 'url': '',
+ 'track': null
+ }
+ },
+ 'size': '',
+ 'matching': '',
+ 'cpm': 70,
+ 'currency': 'RUB'
+ }
+ };
+
+ let bids = spec.interpretResponse(serverResponse, request[0]);
+ expect(bids).to.have.lengthOf(1);
+
+ let bid = bids[0];
+ expect(bid.mediaType).to.equal('video');
+ expect(bid.vastXml).to.equal(vastXml);
+ expect(bid.width).to.equal(234);
+ expect(bid.height).to.equal(765);
+ });
+});
+
+describe('getUserSyncs', function() {
+ it('returns empty sync array', function() {
+ const syncOptions = {};
+
+ expect(spec.getUserSyncs(syncOptions)).to.deep.equal([]);
+ });
+
+ it('Should return array of objects with proper sync config , include CCPA', function() {
+ const syncData = spec.getUserSyncs({
+ pixelEnabled: true,
+ }, {}, {}, '1---');
+ expect(syncData).to.be.an('array').which.is.not.empty;
+ expect(syncData[0]).to.be.an('object')
+ expect(syncData[0].type).to.be.a('string')
+ expect(syncData[0].type).to.equal('image')
+ expect(syncData[0].url).to.be.a('string')
+ expect(syncData[0].url).to.equal('//sync.programmatica.com/match/sp?usp=1---&consent=')
+ });
+
+ it('Should return array of objects with proper sync config , include GDPR', function() {
+ const syncData = spec.getUserSyncs({
+ iframeEnabled: true,
+ }, {}, {
+ gdprApplies: true,
+ consentString: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw',
+ vendorData: {
+ purpose: {
+ consents: {
+ 1: true
+ },
+ },
+ }
+ }, '');
+ expect(syncData).to.be.an('array').which.is.not.empty;
+ expect(syncData[0]).to.be.an('object')
+ expect(syncData[0].type).to.be.a('string')
+ expect(syncData[0].type).to.equal('iframe')
+ expect(syncData[0].url).to.be.a('string')
+ expect(syncData[0].url).to.equal('//sync.programmatica.com/match/sp.ifr?usp=&consent=COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&gdpr=1')
+ });
+
+ it('Should return array of objects with proper sync config , include GDPR, no purpose', function() {
+ const syncData = spec.getUserSyncs({
+ iframeEnabled: true,
+ }, {}, {
+ gdprApplies: true,
+ consentString: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw',
+ vendorData: {
+ purpose: {
+ consents: {
+ 1: false
+ },
+ },
+ }
+ }, '');
+ expect(syncData).is.empty;
+ });
+
+ it('Should return array of objects with proper sync config , GDPR not applies', function() {
+ const syncData = spec.getUserSyncs({
+ iframeEnabled: true,
+ }, {}, {
+ gdprApplies: false,
+ consentString: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw',
+ }, '');
+ expect(syncData).to.be.an('array').which.is.not.empty;
+ expect(syncData[0]).to.be.an('object')
+ expect(syncData[0].type).to.be.a('string')
+ expect(syncData[0].type).to.equal('iframe')
+ expect(syncData[0].url).to.be.a('string')
+ expect(syncData[0].url).to.equal('//sync.programmatica.com/match/sp.ifr?usp=&consent=COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw&gdpr=0')
+ });
+})
diff --git a/test/spec/modules/pstudioBidAdapter_spec.js b/test/spec/modules/pstudioBidAdapter_spec.js
new file mode 100644
index 00000000000..52ecb820ed3
--- /dev/null
+++ b/test/spec/modules/pstudioBidAdapter_spec.js
@@ -0,0 +1,514 @@
+import { assert } from 'chai';
+import sinon from 'sinon';
+import { spec, storage } from 'modules/pstudioBidAdapter.js';
+import { deepClone } from '../../../src/utils.js';
+
+describe('PStudioAdapter', function () {
+ let sandbox;
+
+ beforeEach(function () {
+ sandbox = sinon.createSandbox();
+ });
+
+ afterEach(function () {
+ sandbox.restore();
+ });
+
+ const bannerBid = {
+ bidder: 'pstudio',
+ params: {
+ pubid: '258c2a8d-d2ad-4c31-a2a5-e63001186456',
+ floorPrice: 1.15,
+ },
+ adUnitCode: 'test-div-1',
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [300, 250],
+ [300, 600],
+ ],
+ pos: 0,
+ name: 'some-name',
+ },
+ },
+ bidId: '30b31c1838de1e',
+ };
+
+ const videoBid = {
+ bidder: 'pstudio',
+ params: {
+ pubid: '258c2a8d-d2ad-4c31-a2a5-e63001186456',
+ floorPrice: 1.15,
+ },
+ adUnitCode: 'test-div-1',
+ mediaTypes: {
+ video: {
+ playerSize: [[300, 250]],
+ mimes: ['video/mp4'],
+ minduration: 5,
+ maxduration: 30,
+ protocols: [2, 3],
+ startdelay: 5,
+ placement: 2,
+ skip: 1,
+ skipafter: 1,
+ minbitrate: 10,
+ maxbitrate: 10,
+ delivery: 1,
+ playbackmethod: [1, 3],
+ api: [2],
+ linearity: 1,
+ },
+ },
+ bidId: '30b31c1838de1e',
+ };
+
+ const bidWithOptionalParams = deepClone(bannerBid);
+ bidWithOptionalParams.params['bcat'] = ['IAB17-18', 'IAB7-42'];
+ bidWithOptionalParams.params['badv'] = ['ford.com'];
+ bidWithOptionalParams.params['bapp'] = ['com.foo.mygame'];
+ bidWithOptionalParams.params['regs'] = {
+ coppa: 1,
+ };
+
+ bidWithOptionalParams.userId = {
+ uid2: {
+ id: '7505e78e-4a9b-4011-8901-0e00c3f55ea9',
+ },
+ };
+
+ const emptyOrtb2BidderRequest = { ortb2: {} };
+
+ const baseBidderRequest = {
+ ortb2: {
+ device: {
+ w: 1680,
+ h: 342,
+ },
+ },
+ };
+
+ const extendedBidderRequest = deepClone(baseBidderRequest);
+ extendedBidderRequest.ortb2['device'] = {
+ dnt: 0,
+ ua: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',
+ lmt: 0,
+ ip: '192.0.0.1',
+ ipv6: '2001:0000:130F:0000:0000:09C0:876A:130B',
+ devicetype: 2,
+ make: 'some_producer',
+ model: 'some_model',
+ os: 'some_os',
+ osv: 'some_version',
+ js: 1,
+ language: 'en',
+ carrier: 'WiFi',
+ connectiontype: 0,
+ ifa: 'some_ifa',
+ geo: {
+ lat: 50.4,
+ lon: 40.2,
+ country: 'some_country_code',
+ region: 'some_region_code',
+ regionfips104: 'some_fips_code',
+ metro: 'metro_code',
+ city: 'city_code',
+ zip: 'zip_code',
+ type: 2,
+ },
+ ext: {
+ ifatype: 'dpid',
+ },
+ };
+ extendedBidderRequest.ortb2['site'] = {
+ id: 'some_id',
+ name: 'example',
+ domain: 'page.example.com',
+ cat: ['IAB2'],
+ sectioncat: ['IAB2-2'],
+ pagecat: ['IAB2-2'],
+ page: 'https://page.example.com/here.html',
+ ref: 'https://ref.example.com',
+ publisher: {
+ name: 'some_name',
+ cat: ['IAB2'],
+ domain: 'https://page.example.com/here.html',
+ },
+ content: {
+ id: 'some_id',
+ episode: 22,
+ title: 'New episode.',
+ series: 'New series.',
+ artist: 'New artist',
+ genre: 'some genre',
+ album: 'New album',
+ isrc: 'AA-6Q7-20-00047',
+ season: 'New season',
+ },
+ mobile: 0,
+ };
+ extendedBidderRequest.ortb2['app'] = {
+ id: 'some_id',
+ name: 'example',
+ bundle: 'some_bundle',
+ domain: 'page.example.com',
+ storeurl: 'https://store.example.com',
+ cat: ['IAB2'],
+ sectioncat: ['IAB2-2'],
+ pagecat: ['IAB2-2'],
+ ver: 'some_version',
+ privacypolicy: 0,
+ paid: 0,
+ keywords: 'some, example, keywords',
+ publisher: {
+ name: 'some_name',
+ cat: ['IAB2'],
+ domain: 'https://page.example.com/here.html',
+ },
+ content: {
+ id: 'some_id',
+ episode: 22,
+ title: 'New episode.',
+ series: 'New series.',
+ artist: 'New artist',
+ genre: 'some genre',
+ album: 'New album',
+ isrc: 'AA-6Q7-20-00047',
+ season: 'New season',
+ },
+ };
+ extendedBidderRequest.ortb2['user'] = {
+ yob: 1992,
+ gender: 'M',
+ };
+ extendedBidderRequest.ortb2['regs'] = {
+ coppa: 0,
+ };
+
+ describe('isBidRequestValid', function () {
+ it('should return true when publisher id found', function () {
+ expect(spec.isBidRequestValid(bannerBid)).to.equal(true);
+ });
+
+ it('should return true for video bid', () => {
+ expect(spec.isBidRequestValid(videoBid)).to.equal(true);
+ });
+
+ it('should return false when publisher id not found', function () {
+ const localBid = deepClone(bannerBid);
+ delete localBid.params.pubid;
+ delete localBid.params.floorPrice;
+
+ expect(spec.isBidRequestValid(localBid)).to.equal(false);
+ });
+
+ it('should return false when playerSize in video not found', () => {
+ const localBid = deepClone(videoBid);
+ delete localBid.mediaTypes.video.playerSize;
+
+ expect(spec.isBidRequestValid(localBid)).to.equal(false);
+ });
+
+ it('should return false when mimes in video not found', () => {
+ const localBid = deepClone(videoBid);
+ delete localBid.mediaTypes.video.mimes;
+
+ expect(spec.isBidRequestValid(localBid)).to.equal(false);
+ });
+
+ it('should return false when protocols in video not found', () => {
+ const localBid = deepClone(videoBid);
+ delete localBid.mediaTypes.video.protocols;
+
+ expect(spec.isBidRequestValid(localBid)).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', function () {
+ const bannerRequest = spec.buildRequests([bannerBid], baseBidderRequest);
+ const bannerPayload = JSON.parse(bannerRequest[0].data);
+ const videoRequest = spec.buildRequests([videoBid], baseBidderRequest);
+ const videoPayload = JSON.parse(videoRequest[0].data);
+
+ it('should properly map ids in request payload', function () {
+ expect(bannerPayload.id).to.equal(bannerBid.bidId);
+ expect(bannerPayload.adtagid).to.equal(bannerBid.adUnitCode);
+ });
+
+ it('should properly map banner mediaType in request payload', function () {
+ expect(bannerPayload.banner_properties).to.deep.equal({
+ name: bannerBid.mediaTypes.banner.name,
+ sizes: bannerBid.mediaTypes.banner.sizes,
+ pos: bannerBid.mediaTypes.banner.pos,
+ });
+ });
+
+ it('should properly map video mediaType in request payload', () => {
+ expect(videoPayload.video_properties).to.deep.equal({
+ w: videoBid.mediaTypes.video.playerSize[0][0],
+ h: videoBid.mediaTypes.video.playerSize[0][1],
+ mimes: videoBid.mediaTypes.video.mimes,
+ minduration: videoBid.mediaTypes.video.minduration,
+ maxduration: videoBid.mediaTypes.video.maxduration,
+ protocols: videoBid.mediaTypes.video.protocols,
+ startdelay: videoBid.mediaTypes.video.startdelay,
+ placement: videoBid.mediaTypes.video.placement,
+ skip: videoBid.mediaTypes.video.skip,
+ skipafter: videoBid.mediaTypes.video.skipafter,
+ minbitrate: videoBid.mediaTypes.video.minbitrate,
+ maxbitrate: videoBid.mediaTypes.video.maxbitrate,
+ delivery: videoBid.mediaTypes.video.delivery,
+ playbackmethod: videoBid.mediaTypes.video.playbackmethod,
+ api: videoBid.mediaTypes.video.api,
+ linearity: videoBid.mediaTypes.video.linearity,
+ });
+ });
+
+ it('should properly set required bidder params in request payload', function () {
+ expect(bannerPayload.pubid).to.equal(bannerBid.params.pubid);
+ expect(bannerPayload.floor_price).to.equal(bannerBid.params.floorPrice);
+ });
+
+ it('should omit optional bidder params or first-party data from bid request if they are not provided', function () {
+ assert.isUndefined(bannerPayload.bcat);
+ assert.isUndefined(bannerPayload.badv);
+ assert.isUndefined(bannerPayload.bapp);
+ assert.isUndefined(bannerPayload.user);
+ assert.isUndefined(bannerPayload.device);
+ assert.isUndefined(bannerPayload.site);
+ assert.isUndefined(bannerPayload.app);
+ assert.isUndefined(bannerPayload.user_ids);
+ assert.isUndefined(bannerPayload.regs);
+ });
+
+ it('should properly set optional bidder parameters', function () {
+ const request = spec.buildRequests(
+ [bidWithOptionalParams],
+ baseBidderRequest
+ );
+ const payload = JSON.parse(request[0].data);
+
+ expect(payload.bcat).to.deep.equal(['IAB17-18', 'IAB7-42']);
+ expect(payload.badv).to.deep.equal(['ford.com']);
+ expect(payload.bapp).to.deep.equal(['com.foo.mygame']);
+ });
+
+ it('should properly set optional user_ids', function () {
+ const request = spec.buildRequests(
+ [bidWithOptionalParams],
+ baseBidderRequest
+ );
+ const {
+ user: { uid2_token },
+ } = JSON.parse(request[0].data);
+ const expectedUID = '7505e78e-4a9b-4011-8901-0e00c3f55ea9';
+
+ expect(uid2_token).to.equal(expectedUID);
+ });
+
+ it('should properly set optional user_ids when no first party data is provided', function () {
+ const request = spec.buildRequests(
+ [bidWithOptionalParams],
+ emptyOrtb2BidderRequest
+ );
+ const {
+ user: { uid2_token },
+ } = JSON.parse(request[0].data);
+ const expectedUID = '7505e78e-4a9b-4011-8901-0e00c3f55ea9';
+
+ expect(uid2_token).to.equal(expectedUID);
+ });
+
+ it('should properly handle first-party data', function () {
+ const request = spec.buildRequests([bannerBid], extendedBidderRequest);
+ const payload = JSON.parse(request[0].data);
+
+ expect(payload.user).to.deep.equal(extendedBidderRequest.ortb2.user);
+ expect(payload.device).to.deep.equal(extendedBidderRequest.ortb2.device);
+ expect(payload.site).to.deep.equal(extendedBidderRequest.ortb2.site);
+ expect(payload.app).to.deep.equal(extendedBidderRequest.ortb2.app);
+ expect(payload.regs).to.deep.equal(extendedBidderRequest.ortb2.regs);
+ });
+
+ it('should not set first-party data if nothing is provided in ORTB2 param', function () {
+ const request = spec.buildRequests([bannerBid], emptyOrtb2BidderRequest);
+ const payload = JSON.parse(request[0].data);
+
+ expect(payload).not.to.haveOwnProperty('user');
+ expect(payload).not.to.haveOwnProperty('device');
+ expect(payload).not.to.haveOwnProperty('site');
+ expect(payload).not.to.haveOwnProperty('app');
+ expect(payload).not.to.haveOwnProperty('regs');
+ });
+
+ it('should set user id if proper cookie is present', function () {
+ const cookie = '157bc918-b961-4216-ac72-29fc6363edcb';
+ sandbox.stub(storage, 'getCookie').returns(cookie);
+
+ const request = spec.buildRequests([bannerBid], emptyOrtb2BidderRequest);
+ const payload = JSON.parse(request[0].data);
+
+ expect(payload.user.id).to.equal(cookie);
+ });
+
+ it('should not set user id if proper cookie not present', function () {
+ const request = spec.buildRequests([bannerBid], emptyOrtb2BidderRequest);
+ const payload = JSON.parse(request[0].data);
+
+ expect(payload).not.to.haveOwnProperty('user');
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const serverResponse = {
+ body: {
+ id: '123141241231',
+ bids: [
+ {
+ cpm: 1.02,
+ width: 300,
+ height: 600,
+ currency: 'USD',
+ ad: '
Hello ad ',
+ creative_id: 'crid12345',
+ net_revenue: true,
+ meta: {
+ advertiser_domains: ['https://advertiser.com'],
+ },
+ },
+ ],
+ },
+ };
+
+ const serverVideoResponse = {
+ body: {
+ id: '123141241231',
+ bids: [
+ {
+ vast_url: 'https://v.a/st.xml',
+ cpm: 5,
+ width: 640,
+ height: 480,
+ currency: 'USD',
+ creative_id: 'crid12345',
+ net_revenue: true,
+ meta: {
+ advertiser_domains: ['https://advertiser.com'],
+ },
+ },
+ ],
+ },
+ };
+
+ const bidRequest = {
+ method: 'POST',
+ url: 'test-url',
+ data: JSON.stringify({
+ id: '12345',
+ pubid: 'somepubid',
+ }),
+ };
+
+ it('should properly parse response from server', function () {
+ const expectedResponse = {
+ requestId: JSON.parse(bidRequest.data).id,
+ cpm: serverResponse.body.bids[0].cpm,
+ width: serverResponse.body.bids[0].width,
+ height: serverResponse.body.bids[0].height,
+ ad: serverResponse.body.bids[0].ad,
+ currency: serverResponse.body.bids[0].currency,
+ creativeId: serverResponse.body.bids[0].creative_id,
+ netRevenue: serverResponse.body.bids[0].net_revenue,
+ meta: {
+ advertiserDomains:
+ serverResponse.body.bids[0].meta.advertiser_domains,
+ },
+ ttl: 300,
+ };
+ const parsedResponse = spec.interpretResponse(serverResponse, bidRequest);
+
+ expect(parsedResponse[0]).to.deep.equal(expectedResponse);
+ });
+
+ it('should properly parse video response from server', function () {
+ const expectedResponse = {
+ requestId: JSON.parse(bidRequest.data).id,
+ cpm: serverVideoResponse.body.bids[0].cpm,
+ width: serverVideoResponse.body.bids[0].width,
+ height: serverVideoResponse.body.bids[0].height,
+ currency: serverVideoResponse.body.bids[0].currency,
+ creativeId: serverVideoResponse.body.bids[0].creative_id,
+ netRevenue: serverVideoResponse.body.bids[0].net_revenue,
+ mediaType: 'video',
+ vastUrl: serverVideoResponse.body.bids[0].vast_url,
+ vastXml: undefined,
+ meta: {
+ advertiserDomains:
+ serverVideoResponse.body.bids[0].meta.advertiser_domains,
+ },
+ ttl: 300,
+ };
+ const parsedResponse = spec.interpretResponse(
+ serverVideoResponse,
+ bidRequest
+ );
+
+ expect(parsedResponse[0]).to.deep.equal(expectedResponse);
+ });
+
+ it('should return empty array if no bids are returned', function () {
+ const emptyResponse = deepClone(serverResponse);
+ emptyResponse.body.bids = undefined;
+
+ const parsedResponse = spec.interpretResponse(emptyResponse, bidRequest);
+
+ expect(parsedResponse).to.deep.equal([]);
+ });
+ });
+
+ describe('getUserSyncs', function () {
+ it('should return sync object with correctly injected user id', function () {
+ sandbox.stub(storage, 'getCookie').returns('testid');
+
+ const result = spec.getUserSyncs({}, {}, {}, {});
+
+ expect(result).to.deep.equal([
+ {
+ type: 'image',
+ url: 'https://match.adsrvr.org/track/cmf/generic?ttd_pid=k1on5ig&ttd_tpi=1&ttd_puid=testid&dsp=ttd',
+ },
+ {
+ type: 'image',
+ url: 'https://dsp.myads.telkomsel.com/api/v1/pixel?uid=testid',
+ },
+ ]);
+ });
+
+ it('should generate user id and put the same uuid it into sync object', function () {
+ sandbox.stub(storage, 'getCookie').returns(undefined);
+
+ const result = spec.getUserSyncs({}, {}, {}, {});
+ const url1 = result[0].url;
+ const url2 = result[1].url;
+
+ const expectedUID1 = extractValueFromURL(url1, 'ttd_puid');
+ const expectedUID2 = extractValueFromURL(url2, 'uid');
+
+ expect(expectedUID1).to.equal(expectedUID2);
+
+ expect(result[0]).deep.equal({
+ type: 'image',
+ url: `https://match.adsrvr.org/track/cmf/generic?ttd_pid=k1on5ig&ttd_tpi=1&ttd_puid=${expectedUID1}&dsp=ttd`,
+ });
+ expect(result[1]).deep.equal({
+ type: 'image',
+ url: `https://dsp.myads.telkomsel.com/api/v1/pixel?uid=${expectedUID2}`,
+ });
+ // Helper function to extract UUID from URL
+ function extractValueFromURL(url, key) {
+ const match = url.match(new RegExp(`[?&]${key}=([^&]*)`));
+ return match ? match[1] : null;
+ }
+ });
+ });
+});
diff --git a/test/spec/modules/publinkIdSystem_spec.js b/test/spec/modules/publinkIdSystem_spec.js
index f35a7453403..5ad58ea1a37 100644
--- a/test/spec/modules/publinkIdSystem_spec.js
+++ b/test/spec/modules/publinkIdSystem_spec.js
@@ -72,11 +72,6 @@ describe('PublinkIdSystem', () => {
expect(result.callback).to.be.a('function');
});
- it('Use local copy', () => {
- const result = publinkIdSubmodule.getId({}, undefined, TEST_COOKIE_VALUE);
- expect(result).to.be.undefined;
- });
-
describe('callout for id', () => {
let callbackSpy = sinon.spy();
@@ -84,6 +79,44 @@ describe('PublinkIdSystem', () => {
callbackSpy.resetHistory();
});
+ it('Has cached id', () => {
+ const config = {storage: {type: 'cookie'}};
+ let submoduleCallback = publinkIdSubmodule.getId(config, undefined, TEST_COOKIE_VALUE).callback;
+ submoduleCallback(callbackSpy);
+
+ const request = server.requests[0];
+ const parsed = parseUrl(request.url);
+
+ expect(parsed.hostname).to.equal('proc.ad.cpe.dotomi.com');
+ expect(parsed.pathname).to.equal('/cvx/client/sync/publink/refresh');
+ expect(parsed.search.mpn).to.equal('Prebid.js');
+ expect(parsed.search.mpv).to.equal('$prebid.version$');
+ expect(parsed.search.publink).to.equal(TEST_COOKIE_VALUE);
+
+ request.respond(200, {}, JSON.stringify(serverResponse));
+ expect(callbackSpy.calledOnce).to.be.true;
+ expect(callbackSpy.lastCall.lastArg).to.equal(serverResponse.publink);
+ });
+
+ it('Request path has priority', () => {
+ const config = {storage: {type: 'cookie'}, params: {e: 'ca11c0ca7', site_id: '102030'}};
+ let submoduleCallback = publinkIdSubmodule.getId(config, undefined, TEST_COOKIE_VALUE).callback;
+ submoduleCallback(callbackSpy);
+
+ const request = server.requests[0];
+ const parsed = parseUrl(request.url);
+
+ expect(parsed.hostname).to.equal('proc.ad.cpe.dotomi.com');
+ expect(parsed.pathname).to.equal('/cvx/client/sync/publink');
+ expect(parsed.search.mpn).to.equal('Prebid.js');
+ expect(parsed.search.mpv).to.equal('$prebid.version$');
+ expect(parsed.search.publink).to.equal(TEST_COOKIE_VALUE);
+
+ request.respond(200, {}, JSON.stringify(serverResponse));
+ expect(callbackSpy.calledOnce).to.be.true;
+ expect(callbackSpy.lastCall.lastArg).to.equal(serverResponse.publink);
+ });
+
it('Fetch with consent data', () => {
const config = {storage: {type: 'cookie'}, params: {e: 'ca11c0ca7', site_id: '102030'}};
const consentData = {gdprApplies: 1, consentString: 'myconsentstring'};
diff --git a/test/spec/modules/publirBidAdapter_spec.js b/test/spec/modules/publirBidAdapter_spec.js
new file mode 100644
index 00000000000..60840b82efb
--- /dev/null
+++ b/test/spec/modules/publirBidAdapter_spec.js
@@ -0,0 +1,488 @@
+import { expect } from 'chai';
+import { spec } from 'modules/publirBidAdapter.js';
+import { newBidder } from 'src/adapters/bidderFactory.js';
+import { config } from 'src/config.js';
+import { BANNER } from '../../../src/mediaTypes.js';
+import * as utils from 'src/utils.js';
+
+const ENDPOINT = 'https://prebid.publir.com/publirPrebidEndPoint';
+const RTB_DOMAIN_TEST = 'prebid.publir.com';
+const TTL = 360;
+
+describe('publirAdapter', function () {
+ const adapter = newBidder(spec);
+
+ describe('inherited functions', function () {
+ it('exists and is a function', function () {
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
+ });
+ });
+
+ describe('bid adapter', function () {
+ it('should have aliases', function () {
+ expect(spec.aliases).to.be.an('array').that.is.not.empty;
+ });
+ });
+
+ describe('isBidRequestValid', function () {
+ const bid = {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [['640', '480']],
+ 'params': {
+ 'pubId': 'jdye8weeyirk00000001'
+ }
+ };
+
+ it('should return true when required params are passed', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+
+ it('should return false when pubId is missing', function () {
+ const bid = {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [['640', '480']],
+ 'params': {}
+ };
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+
+ it('should return false when required params are not found', function () {
+ const newBid = Object.assign({}, bid);
+ delete newBid.params;
+ newBid.params = {
+ 'pubId': null
+ };
+ expect(spec.isBidRequestValid(newBid)).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', function () {
+ const bidRequests = [
+ {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[300, 250]],
+ 'params': {
+ 'pubId': 'jdye8weeyirk00000001'
+ },
+ 'bidId': '299ffc8cca0b87',
+ 'loop': 1,
+ 'bidderRequestId': '1144f487e563f9',
+ 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d',
+ 'mediaTypes': {
+ 'banner': {
+ }
+ },
+ 'ad': '"
"'
+ }
+ ];
+
+ const bidderRequest = {
+ bidderCode: 'publir',
+ }
+
+ it('sends bid request to ENDPOINT via POST', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.url).to.equal(ENDPOINT);
+ expect(request.method).to.equal('POST');
+ });
+
+ it('sends bid request to rtbDomain ENDPOINT via POST', function () {
+ bidRequests[0].params.rtbDomain = RTB_DOMAIN_TEST;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.url).to.equal(ENDPOINT);
+ expect(request.method).to.equal('POST');
+ });
+
+ it('should send the correct bid Id', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].bidId).to.equal('299ffc8cca0b87');
+ });
+
+ it('should respect syncEnabled option', function() {
+ config.setConfig({
+ userSync: {
+ syncEnabled: false,
+ filterSettings: {
+ all: {
+ bidders: '*',
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('cs_method');
+ });
+
+ it('should respect "iframe" filter settings', function () {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ iframe: {
+ bidders: [spec.code],
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'iframe');
+ });
+
+ it('should respect "all" filter settings', function () {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ all: {
+ bidders: [spec.code],
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'iframe');
+ });
+
+ it('should send the pixel user sync param if userSync is enabled and no "iframe" or "all" configs are present', function () {
+ config.resetConfig();
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'pixel');
+ });
+
+ it('should respect total exclusion', function() {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ image: {
+ bidders: [spec.code],
+ filter: 'exclude'
+ },
+ iframe: {
+ bidders: [spec.code],
+ filter: 'exclude'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('cs_method');
+ });
+
+ it('should have us_privacy param if usPrivacy is available in the bidRequest', function () {
+ const bidderRequestWithUSP = Object.assign({uspConsent: '1YNN'}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithUSP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('us_privacy', '1YNN');
+ });
+
+ it('should have an empty us_privacy param if usPrivacy is missing in the bidRequest', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('us_privacy');
+ });
+
+ it('should not send the gdpr param if gdprApplies is false in the bidRequest', function () {
+ const bidderRequestWithGDPR = Object.assign({gdprConsent: {gdprApplies: false}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('gdpr');
+ expect(request.data.params).to.not.have.property('gdpr_consent');
+ });
+
+ it('should send the gdpr param if gdprApplies is true in the bidRequest', function () {
+ const bidderRequestWithGDPR = Object.assign({gdprConsent: {gdprApplies: true, consentString: 'test-consent-string'}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('gdpr', true);
+ expect(request.data.params).to.have.property('gdpr_consent', 'test-consent-string');
+ });
+
+ it('should have schain param if it is available in the bidRequest', () => {
+ const schain = {
+ ver: '1.0',
+ complete: 1,
+ nodes: [{ asi: 'indirectseller.com', sid: '00001', hp: 1 }],
+ };
+ bidRequests[0].schain = schain;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('schain', '1.0,1!indirectseller.com,00001,1,,,');
+ });
+
+ it('should set flooPrice to getFloor.floor value if it is greater than params.floorPrice', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.getFloor = () => {
+ return {
+ currency: 'USD',
+ floor: 3.32
+ }
+ }
+ bid.params.floorPrice = 0.64;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0]).to.be.an('object');
+ expect(request.data.bids[0]).to.have.property('floorPrice', 3.32);
+ });
+
+ it('should set floorPrice to params.floorPrice value if it is greater than getFloor.floor', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.getFloor = () => {
+ return {
+ currency: 'USD',
+ floor: 0.8
+ }
+ }
+ bid.params.floorPrice = 1.5;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0]).to.be.an('object');
+ expect(request.data.bids[0]).to.have.property('floorPrice', 1.5);
+ });
+
+ it('should check sua param in bid request', function() {
+ const sua = {
+ 'platform': {
+ 'brand': 'macOS',
+ 'version': ['12', '4', '0']
+ },
+ 'browsers': [
+ {
+ 'brand': 'Chromium',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Google Chrome',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Not;A=Brand',
+ 'version': [ '99', '0', '0', '0' ]
+ }
+ ],
+ 'mobile': 0,
+ 'model': '',
+ 'bitness': '64',
+ 'architecture': 'x86'
+ }
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.ortb2 = {
+ 'device': {
+ 'sua': {
+ 'platform': {
+ 'brand': 'macOS',
+ 'version': [ '12', '4', '0' ]
+ },
+ 'browsers': [
+ {
+ 'brand': 'Chromium',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Google Chrome',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Not;A=Brand',
+ 'version': [ '99', '0', '0', '0' ]
+ }
+ ],
+ 'mobile': 0,
+ 'model': '',
+ 'bitness': '64',
+ 'architecture': 'x86'
+ }
+ }
+ }
+ const requestWithSua = spec.buildRequests([bid], bidderRequest);
+ const data = requestWithSua.data;
+ expect(data.bids[0].sua).to.exist;
+ expect(data.bids[0].sua).to.deep.equal(sua);
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].sua).to.not.exist;
+ });
+
+ describe('COPPA Param', function() {
+ it('should set coppa equal 0 in bid request if coppa is set to false', function() {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].coppa).to.be.equal(0);
+ });
+
+ it('should set coppa equal 1 in bid request if coppa is set to true', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.ortb2 = {
+ 'regs': {
+ 'coppa': true,
+ }
+ };
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0].coppa).to.be.equal(1);
+ });
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const response = {
+ params: {
+ currency: 'USD',
+ netRevenue: true,
+ },
+ bids: [
+ {
+ cpm: 12.5,
+ ad: '"
"',
+ width: 300,
+ height: 250,
+ requestId: '21e12606d47ba7',
+ adomain: ['abc.com'],
+ mediaType: BANNER,
+ campId: '65902db45721d690ee0bc8c3'
+ }]
+ };
+
+ const expectedBannerResponse = {
+ requestId: '21e12606d47ba7',
+ cpm: 12.5,
+ currency: 'USD',
+ width: 300,
+ height: 250,
+ ttl: TTL,
+ creativeId: '639153ddd0s443',
+ netRevenue: true,
+ nurl: 'http://example.com/win/1234',
+ mediaType: BANNER,
+ meta: {
+ mediaType: BANNER,
+ ad_key: '9b5e00f2-8831-4efa-a933-c4f68710ffc0'
+ },
+ ad: '"
"',
+ campId: '65902db45721d690ee0bc8c3',
+ bidder: 'publir'
+ };
+
+ it('should get correct bid response', function () {
+ const result = spec.interpretResponse({ body: response });
+ expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedBannerResponse));
+ });
+ })
+
+ describe('getUserSyncs', function() {
+ const imageSyncResponse = {
+ body: {
+ params: {
+ userSyncPixels: [
+ 'https://image-sync-url.test/1',
+ 'https://image-sync-url.test/2',
+ 'https://image-sync-url.test/3'
+ ]
+ }
+ }
+ };
+
+ const iframeSyncResponse = {
+ body: {
+ params: {
+ userSyncURL: 'https://iframe-sync-url.test'
+ }
+ }
+ };
+
+ it('should register all img urls from the response', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: true }, [imageSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/1'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/2'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/3'
+ }
+ ]);
+ });
+
+ it('should register the iframe url from the response', function() {
+ const syncs = spec.getUserSyncs({ iframeEnabled: true }, [iframeSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'iframe',
+ url: 'https://iframe-sync-url.test'
+ }
+ ]);
+ });
+
+ it('should register both image and iframe urls from the responses', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: true, iframeEnabled: true }, [iframeSyncResponse, imageSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'iframe',
+ url: 'https://iframe-sync-url.test'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/1'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/2'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/3'
+ }
+ ]);
+ });
+
+ it('should handle an empty response', function() {
+ const syncs = spec.getUserSyncs({ iframeEnabled: true }, []);
+ expect(syncs).to.deep.equal([]);
+ });
+
+ it('should handle when user syncs are disabled', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: false }, [imageSyncResponse]);
+ expect(syncs).to.deep.equal([]);
+ });
+ })
+
+ describe('onBidWon', function() {
+ beforeEach(function() {
+ sinon.stub(utils, 'triggerPixel');
+ });
+ afterEach(function() {
+ utils.triggerPixel.restore();
+ });
+
+ it('Should trigger pixel if bid nurl', function() {
+ const bid = {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [['640', '480']],
+ 'nurl': 'http://example.com/win/1234',
+ 'params': {
+ 'pubId': 'jdye8weeyirk00000001'
+ }
+ };
+
+ spec.onBidWon(bid);
+ expect(utils.triggerPixel.callCount).to.equal(1)
+ })
+ })
+});
diff --git a/test/spec/modules/pubmaticAnalyticsAdapter_spec.js b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js
index 7fce08fc24f..951b5135260 100755
--- a/test/spec/modules/pubmaticAnalyticsAdapter_spec.js
+++ b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js
@@ -1,4 +1,4 @@
-import pubmaticAnalyticsAdapter, {getMetadata} from 'modules/pubmaticAnalyticsAdapter.js';
+import pubmaticAnalyticsAdapter, { getMetadata } from 'modules/pubmaticAnalyticsAdapter.js';
import adapterManager from 'src/adapterManager.js';
import CONSTANTS from 'src/constants.json';
import { config } from 'src/config.js';
@@ -100,7 +100,7 @@ const BID2 = Object.assign({}, BID, {
adserverTargeting: {
'hb_bidder': 'pubmatic',
'hb_adid': '3bd4ebb1c900e2',
- 'hb_pb': '1.500',
+ 'hb_pb': 1.50,
'hb_size': '728x90',
'hb_source': 'server'
},
@@ -316,6 +316,208 @@ describe('pubmatic analytics adapter', function () {
expect(utils.logError.called).to.equal(true);
});
+ describe('OW S2S', function() {
+ this.beforeEach(function() {
+ pubmaticAnalyticsAdapter.enableAnalytics({
+ options: {
+ publisherId: 9999,
+ profileId: 1111,
+ profileVersionId: 20
+ }
+ });
+ config.setConfig({
+ s2sConfig: {
+ accountId: '1234',
+ bidders: ['pubmatic'],
+ defaultVendor: 'openwrap',
+ timeout: 500
+ }
+ });
+ });
+
+ this.afterEach(function() {
+ pubmaticAnalyticsAdapter.disableAnalytics();
+ });
+
+ it('Pubmatic Won: No tracker fired', function() {
+ this.timeout(5000)
+
+ sandbox.stub($$PREBID_GLOBAL$$, 'getHighestCpmBids').callsFake((key) => {
+ return [MOCK.BID_RESPONSE[0], MOCK.BID_RESPONSE[1]]
+ });
+
+ config.setConfig({
+ testGroupId: 15
+ });
+
+ events.emit(AUCTION_INIT, MOCK.AUCTION_INIT);
+ events.emit(BID_REQUESTED, MOCK.BID_REQUESTED);
+ events.emit(BID_RESPONSE, MOCK.BID_RESPONSE[0]);
+ events.emit(BIDDER_DONE, MOCK.BIDDER_DONE);
+ events.emit(AUCTION_END, MOCK.AUCTION_END);
+ events.emit(SET_TARGETING, MOCK.SET_TARGETING);
+ events.emit(BID_WON, MOCK.BID_WON[0]);
+
+ clock.tick(2000 + 1000);
+ expect(requests.length).to.equal(1); // only logger is fired
+ let request = requests[0];
+ expect(request.url).to.equal('https://t.pubmatic.com/wl?pubid=9999');
+ let data = getLoggerJsonFromRequest(request.requestBody);
+ expect(data.pubid).to.equal('9999');
+ expect(data.pid).to.equal('1111');
+ expect(data.pdvid).to.equal('20');
+ });
+
+ it('Non-pubmatic won: logger, tracker fired', function() {
+ const APPNEXUS_BID = Object.assign({}, BID, {
+ 'bidder': 'appnexus',
+ 'adserverTargeting': {
+ 'hb_bidder': 'appnexus',
+ 'hb_adid': '2ecff0db240757',
+ 'hb_pb': 1.20,
+ 'hb_size': '640x480',
+ 'hb_source': 'server'
+ }
+ });
+
+ const MOCK_AUCTION_INIT_APPNEXUS = {
+ 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa',
+ 'timestamp': 1519767010567,
+ 'auctionStatus': 'inProgress',
+ 'adUnits': [ {
+ 'code': '/19968336/header-bid-tag-1',
+ 'sizes': [[640, 480]],
+ 'bids': [ {
+ 'bidder': 'appnexus',
+ 'params': {
+ 'publisherId': '1001'
+ }
+ } ],
+ 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014'
+ }
+ ],
+ 'adUnitCodes': ['/19968336/header-bid-tag-1'],
+ 'bidderRequests': [ {
+ 'bidderCode': 'appnexus',
+ 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa',
+ 'bidderRequestId': '1be65d7958826a',
+ 'bids': [ {
+ 'bidder': 'appnexus',
+ 'params': {
+ 'publisherId': '1001',
+ 'kgpv': 'this-is-a-kgpv'
+ },
+ 'mediaTypes': {
+ 'banner': {
+ 'sizes': [[640, 480]]
+ }
+ },
+ 'adUnitCode': '/19968336/header-bid-tag-1',
+ 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014',
+ 'sizes': [[640, 480]],
+ 'bidId': '2ecff0db240757',
+ 'bidderRequestId': '1be65d7958826a',
+ 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa',
+ 'src': 'client',
+ 'bidRequestsCount': 1
+ }
+ ],
+ 'timeout': 3000,
+ 'refererInfo': {
+ 'topmostLocation': 'http://www.test.com/page.html', 'reachedTop': true, 'numIframes': 0, 'stack': ['http://www.test.com/page.html']
+ }
+ }
+ ],
+ 'bidsReceived': [],
+ 'winningBids': [],
+ 'timeout': 3000
+ };
+
+ const MOCK_BID_REQUESTED_APPNEXUS = {
+ 'bidder': 'appnexus',
+ 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa',
+ 'bidderRequestId': '1be65d7958826a',
+ 'bids': [
+ {
+ 'bidder': 'appnexus',
+ 'adapterCode': 'appnexus',
+ 'bidderCode': 'appnexus',
+ 'params': {
+ 'publisherId': '1001',
+ 'video': {
+ 'minduration': 30,
+ 'skippable': true
+ }
+ },
+ 'mediaType': 'video',
+ 'adUnitCode': '/19968336/header-bid-tag-0',
+ 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014',
+ 'sizes': [[640, 480]],
+ 'bidId': '2ecff0db240757',
+ 'bidderRequestId': '1be65d7958826a',
+ 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa'
+ }
+ ],
+ 'auctionStart': 1519149536560,
+ 'timeout': 5000,
+ 'start': 1519149562216,
+ 'refererInfo': {
+ 'topmostLocation': 'http://www.test.com/page.html', 'reachedTop': true, 'numIframes': 0, 'stack': ['http://www.test.com/page.html']
+ },
+ 'gdprConsent': {
+ 'consentString': 'here-goes-gdpr-consent-string',
+ 'gdprApplies': true
+ }
+ };
+
+ this.timeout(5000)
+
+ sandbox.stub($$PREBID_GLOBAL$$, 'getHighestCpmBids').callsFake((key) => {
+ return [APPNEXUS_BID]
+ });
+
+ events.emit(AUCTION_INIT, MOCK_AUCTION_INIT_APPNEXUS);
+ events.emit(BID_REQUESTED, MOCK_BID_REQUESTED_APPNEXUS);
+ events.emit(BID_RESPONSE, APPNEXUS_BID);
+ events.emit(BIDDER_DONE, {
+ 'bidderCode': 'appnexus',
+ 'bids': [
+ APPNEXUS_BID,
+ Object.assign({}, APPNEXUS_BID, {
+ 'serverResponseTimeMs': 42,
+ })
+ ]
+ });
+ events.emit(AUCTION_END, MOCK.AUCTION_END);
+ events.emit(SET_TARGETING, {
+ [APPNEXUS_BID.adUnitCode]: APPNEXUS_BID.adserverTargeting,
+ });
+ events.emit(BID_WON, Object.assign({}, APPNEXUS_BID, {
+ 'status': 'rendered'
+ }));
+
+ clock.tick(2000 + 1000);
+ expect(requests.length).to.equal(2); // logger as well as tracker is fired
+ let request = requests[1]; // logger is executed late, trackers execute first
+ expect(request.url).to.equal('https://t.pubmatic.com/wl?pubid=9999');
+ let data = getLoggerJsonFromRequest(request.requestBody);
+ expect(data.pubid).to.equal('9999');
+ expect(data.pid).to.equal('1111');
+ expect(data.pdvid).to.equal('20');
+
+ let firstTracker = requests[0].url;
+ expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt');
+ firstTracker.split('?')[1].split('&').map(e => e.split('=')).forEach(e => data[e[0]] = e[1]);
+ expect(data.pubid).to.equal('9999');
+ expect(decodeURIComponent(data.purl)).to.equal('http://www.test.com/page.html');
+
+ expect(data.s).to.be.an('array');
+ expect(data.s.length).to.equal(1);
+ expect(data.s[0].ps[0].pn).to.equal('appnexus');
+ expect(data.s[0].ps[0].bc).to.equal('appnexus');
+ })
+ });
+
describe('when handling events', function() {
beforeEach(function () {
pubmaticAnalyticsAdapter.enableAnalytics({
@@ -374,10 +576,14 @@ describe('pubmatic analytics adapter', function () {
// slot 1
expect(data.s[0].sn).to.equal('/19968336/header-bid-tag-0');
expect(data.s[0].fskp).to.equal(0);
+ expect(data.s[0].sid).not.to.be.undefined;
+ expect(data.s[0].ffs).to.equal(1);
+ expect(data.s[0].fsrc).to.equal(2);
+ expect(data.s[0].fp).to.equal('pubmatic');
expect(data.s[0].sz).to.deep.equal(['640x480']);
expect(data.s[0].ps).to.be.an('array');
- expect(data.s[0].au).to.equal('/19968336/header-bid-tag-0');
- expect(data.s[0].ps.length).to.equal(1);
+ expect(data.s[0].au).to.equal('/19968336/header-bid-tag-0');
+ expect(data.s[0].ps.length).to.equal(1);
expect(data.s[0].ps[0].pn).to.equal('pubmatic');
expect(data.s[0].ps[0].bc).to.equal('pubmatic');
expect(data.s[0].ps[0].bidid).to.equal('2ecff0db240757');
@@ -390,8 +596,8 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[0].ps[0].en).to.equal(1.23);
expect(data.s[0].ps[0].di).to.equal('-1');
expect(data.s[0].ps[0].dc).to.equal('');
- expect(data.s[0].ps[0].l1).to.equal(944);
- expect(data.s[0].ps[0].ol1).to.equal(3214);
+ expect(data.s[0].ps[0].l1).to.equal(944);
+ expect(data.s[0].ps[0].ol1).to.equal(3214);
expect(data.s[0].ps[0].l2).to.equal(0);
expect(data.s[0].ps[0].ss).to.equal(1);
expect(data.s[0].ps[0].t).to.equal(0);
@@ -400,9 +606,14 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[0].ps[0].ocpm).to.equal(1.23);
expect(data.s[0].ps[0].ocry).to.equal('USD');
expect(data.s[0].ps[0].frv).to.equal(1.1);
+ expect(data.s[0].ps[0].pb).to.equal(1.2);
// slot 2
expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1');
expect(data.s[1].fskp).to.equal(0);
+ expect(data.s[1].sid).not.to.be.undefined;
+ expect(data.s[1].ffs).to.equal(1);
+ expect(data.s[1].fsrc).to.equal(2);
+ expect(data.s[1].fp).to.equal('pubmatic');
expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']);
expect(data.s[1].ps).to.be.an('array');
expect(data.s[1].ps.length).to.equal(1);
@@ -421,7 +632,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].mi).to.equal('matched-impression');
expect(data.s[1].ps[0].adv).to.equal('example.com');
expect(data.s[0].ps[0].l1).to.equal(944);
- expect(data.s[0].ps[0].ol1).to.equal(3214);
+ expect(data.s[0].ps[0].ol1).to.equal(3214);
expect(data.s[1].ps[0].l2).to.equal(0);
expect(data.s[1].ps[0].ss).to.equal(1);
expect(data.s[1].ps[0].t).to.equal(0);
@@ -430,6 +641,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].ocpm).to.equal(1.52);
expect(data.s[1].ps[0].ocry).to.equal('USD');
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
// tracker slot1
let firstTracker = requests[0].url;
@@ -459,7 +671,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.af).to.equal('video');
});
- it('Logger: do not log floor fields when prebids floor shows noData in location property', function() {
+ it('Logger : do not log floor fields when prebids floor shows noData in location property', function() {
const BID_REQUESTED_COPY = utils.deepClone(MOCK.BID_REQUESTED);
BID_REQUESTED_COPY['bids'][1]['floorData']['location'] = 'noData';
@@ -583,9 +795,13 @@ describe('pubmatic analytics adapter', function () {
// slot 1
expect(data.s[0].sn).to.equal('/19968336/header-bid-tag-0');
expect(data.s[0].fskp).to.equal(0);
+ expect(data.s[0].sid).not.to.be.undefined;
+ expect(data.s[0].ffs).to.equal(1);
+ expect(data.s[0].fsrc).to.equal(2);
+ expect(data.s[0].fp).to.equal('pubmatic');
expect(data.s[0].sz).to.deep.equal(['640x480']);
expect(data.s[0].ps).to.be.an('array');
- expect(data.s[0].au).to.equal('/19968336/header-bid-tag-0');
+ expect(data.s[0].au).to.equal('/19968336/header-bid-tag-0');
expect(data.s[0].ps.length).to.equal(1);
expect(data.s[0].ps[0].pn).to.equal('pubmatic');
expect(data.s[0].ps[0].bc).to.equal('pubmatic');
@@ -598,6 +814,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[0].ps[0].ocpm).to.equal(1.23);
expect(data.s[0].ps[0].ocry).to.equal('USD');
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
// tracker slot1
let firstTracker = requests[0].url;
expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt');
@@ -659,7 +876,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[0].sz).to.deep.equal(['640x480']);
expect(data.s[0].ps).to.be.an('array');
expect(data.s[0].ps.length).to.equal(1);
- expect(data.s[0].au).to.equal('/19968336/header-bid-tag-0');
+ expect(data.s[0].au).to.equal('/19968336/header-bid-tag-0');
expect(data.s[0].ps[0].pn).to.equal('pubmatic');
expect(data.s[0].ps[0].bc).to.equal('pubmatic');
expect(data.s[0].ps[0].bidid).to.equal('2ecff0db240757');
@@ -702,6 +919,13 @@ describe('pubmatic analytics adapter', function () {
expect(data.tgid).to.equal(0);// test group id should be an INT between 0-15 else set to 0
expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1');
expect(data.s[1].fskp).to.equal(0);
+
+ expect(data.s[1].sid).not.to.be.undefined;
+
+ expect(data.s[1].ffs).to.equal(1);
+ expect(data.s[1].fsrc).to.equal(2);
+ expect(data.s[1].fp).to.equal('pubmatic');
+
expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']);
expect(data.s[1].ps).to.be.an('array');
expect(data.s[1].ps.length).to.equal(1);
@@ -784,6 +1008,10 @@ describe('pubmatic analytics adapter', function () {
let data = getLoggerJsonFromRequest(request.requestBody);
expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1');
expect(data.s[1].fskp).to.equal(0);
+ expect(data.s[1].sid).not.to.be.undefined;
+ expect(data.s[1].ffs).to.equal(1);
+ expect(data.s[1].fsrc).to.equal(2);
+ expect(data.s[1].fp).to.equal('pubmatic');
expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']);
expect(data.s[1].ps).to.be.an('array');
expect(data.s[1].ps.length).to.equal(1);
@@ -800,8 +1028,8 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].dc).to.equal('PMP');
expect(data.s[1].ps[0].mi).to.equal('matched-impression');
expect(data.s[1].ps[0].adv).to.equal('example.com');
- expect(data.s[0].ps[0].l1).to.equal(0);
- expect(data.s[0].ps[0].ol1).to.equal(0);
+ expect(data.s[0].ps[0].l1).to.equal(0);
+ expect(data.s[0].ps[0].ol1).to.equal(0);
expect(data.s[1].ps[0].l2).to.equal(0);
expect(data.s[1].ps[0].ss).to.equal(1);
expect(data.s[1].ps[0].t).to.equal(1);
@@ -810,6 +1038,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].ocpm).to.equal(1.52);
expect(data.s[1].ps[0].ocry).to.equal('USD');
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
});
it('Logger: currency conversion check', function() {
@@ -846,6 +1075,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1');
expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']);
expect(data.s[1].ps).to.be.an('array');
+ expect(data.s[1].sid).not.to.be.undefined;
expect(data.s[1].ps.length).to.equal(1);
expect(data.s[1].ps[0].pn).to.equal('pubmatic');
expect(data.s[1].ps[0].bc).to.equal('pubmatic');
@@ -861,7 +1091,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].mi).to.equal('matched-impression');
expect(data.s[1].ps[0].adv).to.equal('example.com');
expect(data.s[0].ps[0].l1).to.equal(944);
- expect(data.s[0].ps[0].ol1).to.equal(3214);
+ expect(data.s[0].ps[0].ol1).to.equal(3214);
expect(data.s[1].ps[0].l2).to.equal(0);
expect(data.s[1].ps[0].ss).to.equal(1);
expect(data.s[1].ps[0].t).to.equal(0);
@@ -893,6 +1123,10 @@ describe('pubmatic analytics adapter', function () {
let data = getLoggerJsonFromRequest(request.requestBody);
expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1');
expect(data.s[1].fskp).to.equal(0);
+ expect(data.s[1].sid).not.to.be.undefined;
+ expect(data.s[1].ffs).to.equal(1);
+ expect(data.s[1].fsrc).to.equal(2);
+ expect(data.s[1].fp).to.equal('pubmatic');
expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']);
expect(data.s[1].ps).to.be.an('array');
expect(data.s[1].ps.length).to.equal(1);
@@ -910,7 +1144,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].mi).to.equal('matched-impression');
expect(data.s[1].ps[0].adv).to.equal('example.com');
expect(data.s[0].ps[0].l1).to.equal(944);
- expect(data.s[0].ps[0].ol1).to.equal(3214);
+ expect(data.s[0].ps[0].ol1).to.equal(3214);
expect(data.s[1].ps[0].l2).to.equal(0);
expect(data.s[1].ps[0].ss).to.equal(1);
expect(data.s[1].ps[0].t).to.equal(0);
@@ -919,6 +1153,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].ocpm).to.equal(1.52);
expect(data.s[1].ps[0].ocry).to.equal('USD');
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
expect(data.dvc).to.deep.equal({'plt': 2});
// respective tracker slot
let firstTracker = requests[1].url;
@@ -952,6 +1187,7 @@ describe('pubmatic analytics adapter', function () {
let data = getLoggerJsonFromRequest(request.requestBody);
expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1');
expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']);
+ expect(data.s[1].sid).not.to.be.undefined;
expect(data.s[1].ps).to.be.an('array');
expect(data.s[1].ps.length).to.equal(1);
expect(data.s[1].ps[0].pn).to.equal('pubmatic');
@@ -968,7 +1204,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].mi).to.equal('matched-impression');
expect(data.s[1].ps[0].adv).to.equal('example.com');
expect(data.s[0].ps[0].l1).to.equal(944);
- expect(data.s[0].ps[0].ol1).to.equal(3214);
+ expect(data.s[0].ps[0].ol1).to.equal(3214);
expect(data.s[1].ps[0].l2).to.equal(0);
expect(data.s[1].ps[0].ss).to.equal(1);
expect(data.s[1].ps[0].t).to.equal(0);
@@ -978,6 +1214,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].ocry).to.equal('USD');
expect(data.dvc).to.deep.equal({'plt': 1});
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
// respective tracker slot
let firstTracker = requests[1].url;
expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt');
@@ -1006,6 +1243,10 @@ describe('pubmatic analytics adapter', function () {
let data = getLoggerJsonFromRequest(request.requestBody);
expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1');
expect(data.s[1].fskp).to.equal(0);
+ expect(data.s[1].sid).not.to.be.undefined;
+ expect(data.s[1].ffs).to.equal(1);
+ expect(data.s[1].fsrc).to.equal(2);
+ expect(data.s[1].fp).to.equal('pubmatic');
expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']);
expect(data.s[1].ps).to.be.an('array');
expect(data.s[1].ps.length).to.equal(1);
@@ -1023,7 +1264,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].mi).to.equal('matched-impression');
expect(data.s[1].ps[0].adv).to.equal('example.com');
expect(data.s[0].ps[0].l1).to.equal(944);
- expect(data.s[0].ps[0].ol1).to.equal(3214);
+ expect(data.s[0].ps[0].ol1).to.equal(3214);
expect(data.s[1].ps[0].l2).to.equal(0);
expect(data.s[1].ps[0].ss).to.equal(1);
expect(data.s[1].ps[0].t).to.equal(0);
@@ -1032,6 +1273,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].ocpm).to.equal(1.52);
expect(data.s[1].ps[0].ocry).to.equal('USD');
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
// respective tracker slot
let firstTracker = requests[1].url;
expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt');
@@ -1063,6 +1305,7 @@ describe('pubmatic analytics adapter', function () {
let data = getLoggerJsonFromRequest(request.requestBody);
expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1');
expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']);
+ expect(data.s[1].sid).not.to.be.undefined;
expect(data.s[1].ps).to.be.an('array');
expect(data.s[1].ps.length).to.equal(1);
expect(data.s[1].ps[0].pn).to.equal('pubmatic');
@@ -1079,7 +1322,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].mi).to.equal('matched-impression');
expect(data.s[1].ps[0].adv).to.equal('example.com');
expect(data.s[0].ps[0].l1).to.equal(944);
- expect(data.s[0].ps[0].ol1).to.equal(3214);
+ expect(data.s[0].ps[0].ol1).to.equal(3214);
expect(data.s[1].ps[0].l2).to.equal(0);
expect(data.s[1].ps[0].ss).to.equal(1);
expect(data.s[1].ps[0].t).to.equal(0);
@@ -1121,7 +1364,11 @@ describe('pubmatic analytics adapter', function () {
// Testing only for rejected bid as other scenarios will be covered under other TCs
expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1');
expect(data.s[1].fskp).to.equal(0);
+ expect(data.s[1].ffs).to.equal(1);
+ expect(data.s[1].fsrc).to.equal(2);
+ expect(data.s[1].fp).to.equal('pubmatic');
expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']);
+ expect(data.s[1].sid).not.to.be.undefined;
expect(data.s[1].ps).to.be.an('array');
expect(data.s[1].ps.length).to.equal(1);
expect(data.s[1].ps[0].pn).to.equal('pubmatic');
@@ -1139,7 +1386,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].mi).to.equal('matched-impression');
expect(data.s[1].ps[0].adv).to.equal('example.com');
expect(data.s[0].ps[0].l1).to.equal(944);
- expect(data.s[0].ps[0].ol1).to.equal(3214);
+ expect(data.s[0].ps[0].ol1).to.equal(3214);
expect(data.s[1].ps[0].l2).to.equal(0);
expect(data.s[1].ps[0].ss).to.equal(1);
expect(data.s[1].ps[0].t).to.equal(0);
@@ -1148,6 +1395,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].ocpm).to.equal(1.52);
expect(data.s[1].ps[0].ocry).to.equal('USD');
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
});
it('Logger: best case + win tracker in case of Bidder Aliases', function() {
@@ -1196,9 +1444,13 @@ describe('pubmatic analytics adapter', function () {
// slot 1
expect(data.s[0].sn).to.equal('/19968336/header-bid-tag-0');
expect(data.s[0].fskp).to.equal(0);
+ expect(data.s[0].ffs).to.equal(1);
+ expect(data.s[0].fsrc).to.equal(2);
+ expect(data.s[0].fp).to.equal('pubmatic');
expect(data.s[0].sz).to.deep.equal(['640x480']);
+ expect(data.s[0].sid).not.to.be.undefined;
expect(data.s[0].ps).to.be.an('array');
- expect(data.s[0].au).to.equal('/19968336/header-bid-tag-0');
+ expect(data.s[0].au).to.equal('/19968336/header-bid-tag-0');
expect(data.s[0].ps.length).to.equal(1);
expect(data.s[0].ps[0].pn).to.equal('pubmatic');
expect(data.s[0].ps[0].bc).to.equal('pubmatic_alias');
@@ -1213,7 +1465,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[0].ps[0].di).to.equal('-1');
expect(data.s[0].ps[0].dc).to.equal('');
expect(data.s[0].ps[0].l1).to.equal(944);
- expect(data.s[0].ps[0].ol1).to.equal(3214);
+ expect(data.s[0].ps[0].ol1).to.equal(3214);
expect(data.s[0].ps[0].l2).to.equal(0);
expect(data.s[0].ps[0].ss).to.equal(0);
expect(data.s[0].ps[0].t).to.equal(0);
@@ -1222,11 +1474,16 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[0].ps[0].ocpm).to.equal(1.23);
expect(data.s[0].ps[0].ocry).to.equal('USD');
expect(data.s[0].ps[0].frv).to.equal(1.1);
+ expect(data.s[0].ps[0].pb).to.equal(1.2);
// slot 2
expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1');
expect(data.s[1].fskp).to.equal(0);
+ expect(data.s[1].ffs).to.equal(1);
+ expect(data.s[1].fsrc).to.equal(2);
+ expect(data.s[1].fp).to.equal('pubmatic');
expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']);
+ expect(data.s[1].sid).not.to.be.undefined;
expect(data.s[1].ps).to.be.an('array');
expect(data.s[1].ps.length).to.equal(1);
expect(data.s[1].ps[0].pn).to.equal('pubmatic');
@@ -1243,8 +1500,8 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].dc).to.equal('PMP');
expect(data.s[1].ps[0].mi).to.equal('matched-impression');
expect(data.s[1].ps[0].adv).to.equal('example.com');
- expect(data.s[0].ps[0].l1).to.equal(944);
- expect(data.s[0].ps[0].ol1).to.equal(3214);
+ expect(data.s[0].ps[0].l1).to.equal(944);
+ expect(data.s[0].ps[0].ol1).to.equal(3214);
expect(data.s[1].ps[0].l2).to.equal(0);
expect(data.s[1].ps[0].ss).to.equal(1);
expect(data.s[1].ps[0].t).to.equal(0);
@@ -1253,6 +1510,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].ocpm).to.equal(1.52);
expect(data.s[1].ps[0].ocry).to.equal('USD');
expect(data.s[1].ps[0].frv).to.equal(1.1);
+ expect(data.s[1].ps[0].pb).to.equal(1.50);
// tracker slot1
let firstTracker = requests[0].url;
@@ -1318,9 +1576,13 @@ describe('pubmatic analytics adapter', function () {
// slot 1
expect(data.s[0].sn).to.equal('/19968336/header-bid-tag-0');
expect(data.s[0].fskp).to.equal(0);
+ expect(data.s[0].ffs).to.equal(1);
+ expect(data.s[0].fsrc).to.equal(2);
+ expect(data.s[0].fp).to.equal('pubmatic');
expect(data.s[0].sz).to.deep.equal(['640x480']);
+ expect(data.s[0].sid).not.to.be.undefined;
expect(data.s[0].ps).to.be.an('array');
- expect(data.s[0].au).to.equal('/19968336/header-bid-tag-0');
+ expect(data.s[0].au).to.equal('/19968336/header-bid-tag-0');
expect(data.s[0].ps.length).to.equal(1);
expect(data.s[0].ps[0].pn).to.equal('pubmatic');
expect(data.s[0].ps[0].bc).to.equal('groupm');
@@ -1335,7 +1597,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[0].ps[0].di).to.equal('-1');
expect(data.s[0].ps[0].dc).to.equal('');
expect(data.s[0].ps[0].l1).to.equal(944);
- expect(data.s[0].ps[0].ol1).to.equal(3214);
+ expect(data.s[0].ps[0].ol1).to.equal(3214);
expect(data.s[0].ps[0].l2).to.equal(0);
expect(data.s[0].ps[0].ss).to.equal(0);
expect(data.s[0].ps[0].t).to.equal(0);
@@ -1344,10 +1606,12 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[0].ps[0].ocpm).to.equal(1.23);
expect(data.s[0].ps[0].ocry).to.equal('USD');
expect(data.s[0].ps[0].frv).to.equal(1.1);
+ expect(data.s[0].ps[0].pb).to.equal(1.2);
// slot 2
expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1');
expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']);
+ expect(data.s[1].sid).not.to.be.undefined;
expect(data.s[1].ps).to.be.an('array');
expect(data.s[1].ps.length).to.equal(1);
expect(data.s[1].ps[0].pn).to.equal('pubmatic');
@@ -1365,7 +1629,7 @@ describe('pubmatic analytics adapter', function () {
expect(data.s[1].ps[0].mi).to.equal('matched-impression');
expect(data.s[1].ps[0].adv).to.equal('example.com');
expect(data.s[0].ps[0].l1).to.equal(944);
- expect(data.s[0].ps[0].ol1).to.equal(3214);
+ expect(data.s[0].ps[0].ol1).to.equal(3214);
expect(data.s[1].ps[0].l2).to.equal(0);
expect(data.s[1].ps[0].ss).to.equal(1);
expect(data.s[1].ps[0].t).to.equal(0);
diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js
index 066004bd954..fda2c853e87 100644
--- a/test/spec/modules/pubmaticBidAdapter_spec.js
+++ b/test/spec/modules/pubmaticBidAdapter_spec.js
@@ -82,6 +82,7 @@ describe('PubMatic adapter', function () {
ortb2Imp: {
ext: {
tid: '92489f71-1bf2-49a0-adf9-000cea934729',
+ gpid: '/1111/homepage-leftnav'
}
},
schain: schainConfig
@@ -103,6 +104,7 @@ describe('PubMatic adapter', function () {
params: {
publisherId: '5890',
adSlot: 'Div1@0x0', // ad_id or tagid
+ wiid: 'new-unique-wiid',
video: {
mimes: ['video/mp4', 'video/x-flv'],
skippable: true,
@@ -153,6 +155,7 @@ describe('PubMatic adapter', function () {
params: {
publisherId: '5890',
adSlot: 'Div1@640x480', // ad_id or tagid
+ wiid: '1234567890',
video: {
mimes: ['video/mp4', 'video/x-flv'],
skippable: true,
@@ -212,6 +215,7 @@ describe('PubMatic adapter', function () {
params: {
publisherId: '5670',
adSlot: '/43743431/NativeAutomationPrebid@1x1',
+ wiid: 'new-unique-wiid'
},
bidId: '2a5571261281d4',
requestId: 'B68287E1-DC39-4B38-9790-FE4F179739D6',
@@ -277,6 +281,7 @@ describe('PubMatic adapter', function () {
params: {
publisherId: '5670',
adSlot: '/43743431/NativeAutomationPrebid@1x1',
+ wiid: 'new-unique-wiid'
},
bidId: '2a5571261281d4',
requestId: 'B68287E1-DC39-4B38-9790-FE4F179739D6',
@@ -303,6 +308,7 @@ describe('PubMatic adapter', function () {
params: {
publisherId: '5670',
adSlot: '/43743431/NativeAutomationPrebid@1x1',
+ wiid: 'new-unique-wiid'
}
}];
@@ -343,6 +349,7 @@ describe('PubMatic adapter', function () {
params: {
publisherId: '5670',
adSlot: '/43743431/NativeAutomationPrebid@1x1',
+ wiid: 'new-unique-wiid'
}
}];
@@ -501,6 +508,7 @@ describe('PubMatic adapter', function () {
params: {
publisherId: '301',
adSlot: '/15671365/DMDemo@300x250:0',
+ wiid: 'new-unique-wiid',
video: {
mimes: ['video/mp4', 'video/x-flv'],
skippable: true,
@@ -571,6 +579,7 @@ describe('PubMatic adapter', function () {
params: {
publisherId: '301',
adSlot: '/15671365/DMDemo@300x250:0',
+ wiid: 'new-unique-wiid',
video: {
mimes: ['video/mp4', 'video/x-flv'],
skippable: true,
@@ -1172,6 +1181,7 @@ describe('PubMatic adapter', function () {
expect(data.imp[0].tagid).to.equal('/15671365/DMDemo'); // tagid
expect(data.imp[0].banner.w).to.equal(300); // width
expect(data.imp[0].banner.h).to.equal(250); // height
+ expect(data.imp[0].ext.gpid).to.equal(bidRequests[0].ortb2Imp.ext.gpid);
expect(data.imp[0].ext.pmZoneId).to.equal(bidRequests[0].params.pmzoneid.split(',').slice(0, 50).map(id => id.trim()).join()); // pmzoneid
expect(data.imp[0].ext.key_val).to.exist.and.to.equal(bidRequests[0].params.dctr);
expect(data.imp[0].bidfloorcur).to.equal(bidRequests[0].params.currency);
@@ -1439,6 +1449,7 @@ describe('PubMatic adapter', function () {
expect(data.imp[0].banner.w).to.equal(728); // width
expect(data.imp[0].banner.h).to.equal(90); // height
expect(data.imp[0].banner.format).to.deep.equal([{w: 160, h: 600}]);
+ expect(data.imp[0].ext.gpid).to.equal(bidRequests[0].ortb2Imp.ext.gpid);
expect(data.imp[0].ext.key_val).to.exist.and.to.equal(bidRequests[0].params.dctr);
expect(data.imp[0].ext.pmZoneId).to.equal(bidRequests[0].params.pmzoneid.split(',').slice(0, 50).map(id => id.trim()).join()); // pmzoneid
expect(data.imp[0].bidfloorcur).to.equal(bidRequests[0].params.currency);
@@ -1663,6 +1674,7 @@ describe('PubMatic adapter', function () {
expect(data.imp[0].tagid).to.equal('/15671365/DMDemo'); // tagid
expect(data.imp[0].banner.w).to.equal(300); // width
expect(data.imp[0].banner.h).to.equal(250); // height
+ expect(data.imp[0].ext.gpid).to.equal(bidRequests[0].ortb2Imp.ext.gpid);
expect(data.imp[0].ext.pmZoneId).to.equal(bidRequests[0].params.pmzoneid.split(',').slice(0, 50).map(id => id.trim()).join()); // pmzoneid
});
@@ -1711,6 +1723,7 @@ describe('PubMatic adapter', function () {
expect(data.imp[0].id).to.equal(bidRequests[0].bidId); // Prebid bid id is passed as id
expect(data.imp[0].bidfloor).to.equal(parseFloat(bidRequests[0].params.kadfloor)); // kadfloor
expect(data.imp[0].tagid).to.equal('/15671365/DMDemo'); // tagid
+ expect(data.imp[0].ext.gpid).to.equal(bidRequests[0].ortb2Imp.ext.gpid);
expect(data.imp[0].banner.w).to.equal(300); // width
expect(data.imp[0].banner.h).to.equal(250); // height
expect(data.imp[0].ext.pmZoneId).to.equal(bidRequests[0].params.pmzoneid.split(',').slice(0, 50).map(id => id.trim()).join()); // pmzoneid
@@ -1759,6 +1772,7 @@ describe('PubMatic adapter', function () {
expect(data.imp[0].tagid).to.equal('/15671365/DMDemo'); // tagid
expect(data.imp[0].banner.w).to.equal(300); // width
expect(data.imp[0].banner.h).to.equal(250); // height
+ expect(data.imp[0].ext.gpid).to.equal(bidRequests[0].ortb2Imp.ext.gpid);
expect(data.imp[0].ext.pmZoneId).to.equal(bidRequests[0].params.pmzoneid.split(',').slice(0, 50).map(id => id.trim()).join()); // pmzoneid
// second request without USP/CCPA
@@ -1767,6 +1781,37 @@ describe('PubMatic adapter', function () {
expect(data2.regs).to.equal(undefined);// USP/CCPAs
});
+ it('Request params should include DSA signals if present', function () {
+ const dsa = {
+ dsarequired: 3,
+ pubrender: 0,
+ datatopub: 2,
+ transparency: [
+ {
+ domain: 'platform1domain.com',
+ dsaparams: [1]
+ },
+ {
+ domain: 'SSP2domain.com',
+ dsaparams: [1, 2]
+ }
+ ]
+ };
+
+ let bidRequest = {
+ ortb2: {
+ regs: {
+ ext: {
+ dsa
+ }
+ }
+ }
+ };
+ let request = spec.buildRequests(bidRequests, bidRequest);
+ let data = JSON.parse(request.data);
+ assert.deepEqual(data.regs.ext.dsa, dsa);
+ });
+
it('Request params check with JW player params', function() {
let bidRequests = [
{
@@ -1908,7 +1953,43 @@ describe('PubMatic adapter', function () {
expect(data.user.yob).to.equal(1985);
});
+ it('ortb2.badv should be merged in the request', function() {
+ const ortb2 = {
+ badv: ['example.com']
+ };
+ const request = spec.buildRequests(bidRequests, {ortb2});
+ let data = JSON.parse(request.data);
+ expect(data.badv).to.deep.equal(['example.com']);
+ });
+
describe('ortb2Imp', function() {
+ describe('ortb2Imp.ext.gpid', function() {
+ beforeEach(function () {
+ if (bidRequests[0].hasOwnProperty('ortb2Imp')) {
+ delete bidRequests[0].ortb2Imp;
+ }
+ });
+
+ it('should send gpid if imp[].ext.gpid is specified', function() {
+ bidRequests[0].ortb2Imp = {
+ ext: {
+ gpid: 'ortb2Imp.ext.gpid'
+ }
+ };
+ const request = spec.buildRequests(bidRequests, {});
+ let data = JSON.parse(request.data);
+ expect(data.imp[0].ext).to.have.property('gpid');
+ expect(data.imp[0].ext.gpid).to.equal('ortb2Imp.ext.gpid');
+ });
+
+ it('should not send if imp[].ext.gpid is not specified', function() {
+ bidRequests[0].ortb2Imp = { ext: { } };
+ const request = spec.buildRequests(bidRequests, {});
+ let data = JSON.parse(request.data);
+ expect(data.imp[0].ext).to.not.have.property('gpid');
+ });
+ });
+
describe('ortb2Imp.ext.data.pbadslot', function() {
beforeEach(function () {
if (bidRequests[0].hasOwnProperty('ortb2Imp')) {
@@ -2278,6 +2359,23 @@ describe('PubMatic adapter', function () {
expect(data.device.sua).to.deep.equal(suaObject);
});
+ it('should pass device.ext.cdep if present in bidderRequest fpd ortb2 object', function () {
+ const cdepObj = {
+ cdep: 'example_label_1'
+ };
+ let request = spec.buildRequests(multipleMediaRequests, {
+ auctionId: 'new-auction-id',
+ ortb2: {
+ device: {
+ ext: cdepObj
+ }
+ }
+ });
+ let data = JSON.parse(request.data);
+ expect(data.device.ext.cdep).to.exist.and.to.be.an('string');
+ expect(data.device.ext).to.deep.equal(cdepObj);
+ });
+
it('Request params should have valid native bid request for all valid params', function () {
let request = spec.buildRequests(nativeBidRequests, {
auctionId: 'new-auction-id'
@@ -3686,6 +3784,16 @@ describe('PubMatic adapter', function () {
describe('Preapare metadata', function () {
it('Should copy all fields from ext to meta', function () {
+ const dsa = {
+ behalf: 'Advertiser',
+ paid: 'Advertiser',
+ transparency: [{
+ domain: 'dsp1domain.com',
+ dsaparams: [1, 2]
+ }],
+ adrender: 1
+ };
+
const bid = {
'adomain': [
'mystartab.com'
@@ -3697,6 +3805,7 @@ describe('PubMatic adapter', function () {
'deal_channel': 1,
'bidtype': 0,
advertiserId: 'adid',
+ dsa,
// networkName: 'nwnm',
// primaryCatId: 'pcid',
// advertiserName: 'adnm',
@@ -3728,6 +3837,7 @@ describe('PubMatic adapter', function () {
expect(br.meta.secondaryCatIds[0]).to.equal('IAB_CATEGORY');
expect(br.meta.advertiserDomains).to.be.an('array').with.length.above(0); // adomain
expect(br.meta.clickUrl).to.equal('mystartab.com'); // adomain
+ expect(br.meta.dsa).to.equal(dsa); // dsa
});
it('Should be empty, when ext and adomain is absent in bid object', function () {
diff --git a/test/spec/modules/pxyzBidAdapter_spec.js b/test/spec/modules/pxyzBidAdapter_spec.js
index 3a336c86e46..36e7a1e9ad6 100644
--- a/test/spec/modules/pxyzBidAdapter_spec.js
+++ b/test/spec/modules/pxyzBidAdapter_spec.js
@@ -210,30 +210,15 @@ describe('pxyzBidAdapter', function () {
});
describe('getUserSyncs', function () {
- const syncUrl = '//ib.adnxs.com/getuidnb?https://ads.playground.xyz/usersync?partner=appnexus&uid=$UID';
-
- describe('when iframeEnabled is true', function () {
- const syncOptions = {
- 'iframeEnabled': true
- }
- it('should return one image type user sync pixel', function () {
- let result = spec.getUserSyncs(syncOptions);
- expect(result.length).to.equal(1);
- expect(result[0].type).to.equal('image')
- expect(result[0].url).to.equal(syncUrl);
- });
- });
-
- describe('when iframeEnabled is false', function () {
- const syncOptions = {
- 'iframeEnabled': false
- }
- it('should return one image type user sync pixel', function () {
- let result = spec.getUserSyncs(syncOptions);
- expect(result.length).to.equal(1);
- expect(result[0].type).to.equal('image')
- expect(result[0].url).to.equal(syncUrl);
- });
+ const syncImageUrl = '//ib.adnxs.com/getuidnb?https://ads.playground.xyz/usersync?partner=appnexus&uid=$UID';
+ const syncIframeUrl = '//rtb.gumgum.com/getuid/15801?r=https%3A%2F%2Fads.playground.xyz%2Fusersync%3Fpartner%3Dgumgum%26uid%3D';
+ it('should return one image type user sync pixel', function () {
+ let result = spec.getUserSyncs();
+ expect(result.length).to.equal(2);
+ expect(result[0].type).to.equal('image')
+ expect(result[0].url).to.equal(syncImageUrl);
+ expect(result[1].type).to.equal('iframe')
+ expect(result[1].url).to.equal(syncIframeUrl);
});
})
});
diff --git a/test/spec/modules/qortexRtdProvider_spec.js b/test/spec/modules/qortexRtdProvider_spec.js
index f6cf8798850..9baa526e4cc 100644
--- a/test/spec/modules/qortexRtdProvider_spec.js
+++ b/test/spec/modules/qortexRtdProvider_spec.js
@@ -168,21 +168,21 @@ describe('qortexRtdProvider', () => {
dispatchEvent(new CustomEvent('qortex-rtd', validImpressionEvent));
dispatchEvent(new CustomEvent('qortex-rtd', validImpressionEvent));
expect(billableEvents.length).to.be.equal(1);
- expect(logWarnSpy.calledWith('recieved invalid billable event due to duplicate uid: qx-impression')).to.be.ok;
+ expect(logWarnSpy.calledWith('received invalid billable event due to duplicate uid: qx-impression')).to.be.ok;
})
it('will not allow events with missing uid', () => {
loadScriptTag(config);
dispatchEvent(new CustomEvent('qortex-rtd', missingIdImpressionEvent));
expect(billableEvents.length).to.be.equal(0);
- expect(logWarnSpy.calledWith('recieved invalid billable event due to missing uid: qx-impression')).to.be.ok;
+ expect(logWarnSpy.calledWith('received invalid billable event due to missing uid: qx-impression')).to.be.ok;
})
it('will not allow events with unavailable type', () => {
loadScriptTag(config);
dispatchEvent(new CustomEvent('qortex-rtd', invalidTypeQortexEvent));
expect(billableEvents.length).to.be.equal(0);
- expect(logWarnSpy.calledWith('recieved invalid billable event: invalid-type')).to.be.ok;
+ expect(logWarnSpy.calledWith('received invalid billable event: invalid-type')).to.be.ok;
})
})
@@ -281,7 +281,7 @@ describe('qortexRtdProvider', () => {
initializeModuleData(validModuleConfig);
addContextToRequests(reqBidsConfig);
expect(logWarnSpy.calledOnce).to.be.true;
- expect(logWarnSpy.calledWith('No context data recieved at this time')).to.be.ok;
+ expect(logWarnSpy.calledWith('No context data received at this time')).to.be.ok;
expect(reqBidsConfig.ortb2Fragments.global).to.be.eql({});
expect(reqBidsConfig.ortb2Fragments.bidder).to.be.eql({});
})
diff --git a/test/spec/modules/r2b2BidAdapter_spec.js b/test/spec/modules/r2b2BidAdapter_spec.js
new file mode 100644
index 00000000000..b94b400a71d
--- /dev/null
+++ b/test/spec/modules/r2b2BidAdapter_spec.js
@@ -0,0 +1,689 @@
+import {expect} from 'chai';
+import {spec, internal as r2b2, internal} from 'modules/r2b2BidAdapter.js';
+import * as utils from '../../../src/utils';
+import 'modules/schain.js';
+import 'modules/userId/index.js';
+
+function encodePlacementIds (ids) {
+ return btoa(JSON.stringify(ids));
+}
+
+describe('R2B2 adapter', function () {
+ let serverResponse, requestForInterpretResponse;
+ let bidderRequest;
+ let bids = [];
+ let gdprConsent = {
+ gdprApplies: true,
+ consentString: 'consent-string',
+ };
+ let schain = {
+ ver: '1.0',
+ complete: 1,
+ nodes: [{
+ asi: 'example.com',
+ sid: '00001',
+ hp: 1
+ }]
+ };
+ const usPrivacyString = '1YNN';
+ const impId = 'impID';
+ const price = 10.6;
+ const ad = 'adm';
+ const creativeId = 'creativeID';
+ const cid = 41849;
+ const cdid = 595121;
+ const unitCode = 'unitCode';
+ const bidId1 = '1';
+ const bidId2 = '2';
+ const bidId3 = '3';
+ const bidId4 = '4';
+ const bidId5 = '5';
+ const bidWonUrl = 'url1';
+ const setTargetingUrl = 'url2';
+ const bidder = 'r2b2';
+ const foreignBidder = 'differentBidder';
+ const id1 = { pid: 'd/g/p' };
+ const id1Object = { d: 'd', g: 'g', p: 'p', m: 0 };
+ const id2 = { pid: 'd/g/p/1' };
+ const id2Object = { d: 'd', g: 'g', p: 'p', m: 1 };
+ const badId = { pid: 'd/g/' };
+ const bid1 = { bidId: bidId1, bidder, params: [ id1 ] };
+ const bid2 = { bidId: bidId2, bidder, params: [ id2 ] };
+ const bidWithBadSetup = { bidId: bidId3, bidder, params: [ badId ] };
+ const bidForeign1 = { bidId: bidId4, bidder: foreignBidder, params: [ { id: 'abc' } ] };
+ const bidForeign2 = { bidId: bidId5, bidder: foreignBidder, params: [ { id: 'xyz' } ] };
+ const fakeTime = 1234567890;
+ const cacheBusterRegex = /[\?&]cb=([^&]+)/;
+ let bidStub, time;
+
+ beforeEach(function () {
+ bids = [{
+ bidder: 'r2b2',
+ params: {
+ pid: 'example.com/generic/300x250/1'
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [300, 250]
+ ]
+ }
+ },
+ adUnitCode: unitCode,
+ transactionId: '29c408b9-65ce-48b1-9167-18a57791f908',
+ sizes: [
+ [300, 250]
+ ],
+ bidId: '20917a54ee9858',
+ bidderRequestId: '15270d403778d',
+ auctionId: '36acef1b-f635-4f57-b693-5cc55ee16346',
+ src: 'client',
+ ortb2: {
+ regs: {
+ ext: {
+ gdpr: 1,
+ us_privacy: '1YYY'
+ }
+ },
+ user: {
+ ext: {
+ consent: 'consent-string'
+ }
+ },
+ site: {},
+ device: {}
+ },
+ schain
+ }, {
+ bidder: 'r2b2',
+ params: {
+ pid: 'example.com/generic/300x600/0'
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [300, 600]
+ ]
+ }
+ },
+ adUnitCode: unitCode,
+ transactionId: '29c408b9-65ce-48b1-9167-18a57791f908',
+ sizes: [
+ [300, 600]
+ ],
+ bidId: '3dd53d30c691fe',
+ bidderRequestId: '15270d403778d',
+ auctionId: '36acef1b-f635-4f57-b693-5cc55ee16346',
+ src: 'client',
+ ortb2: {
+ regs: {
+ ext: {
+ gdpr: 1,
+ us_privacy: '1YYY'
+ }
+ },
+ user: {
+ ext: {
+ consent: 'consent-string'
+ }
+ },
+ site: {},
+ device: {}
+ },
+ schain
+ }];
+ bidderRequest = {
+ bidderCode: 'r2b2',
+ auctionId: '36acef1b-f635-4f57-b693-5cc55ee16346',
+ bidderRequestId: '15270d403778d',
+ bids: bids,
+ ortb2: {
+ regs: {
+ ext: {
+ gdpr: 1,
+ us_privacy: '1YYY'
+ }
+ },
+ user: {
+ ext: {
+ consent: 'consent-string'
+ }
+ },
+ site: {},
+ device: {}
+ },
+ gdprConsent: {
+ consentString: 'consent-string',
+ vendorData: {},
+ gdprApplies: true,
+ apiVersion: 2
+ },
+ uspConsent: '1YYY',
+ };
+ serverResponse = {
+ id: 'a66a6e32-2a7d-4ed3-bb13-6f3c9bdcf6a1',
+ seatbid: [{
+ bid: [{
+ id: '4756cc9e9b504fd0bd39fdd594506545',
+ impid: impId,
+ price: price,
+ adm: ad,
+ crid: creativeId,
+ w: 300,
+ h: 250,
+ ext: {
+ prebid: {
+ meta: {
+ adaptercode: 'r2b2'
+ },
+ type: 'banner'
+ },
+ r2b2: {
+ cdid: cdid,
+ cid: cid,
+ useRenderer: true
+ }
+ }
+ }],
+ seat: 'seat'
+ }]
+ };
+ requestForInterpretResponse = {
+ data: {
+ imp: [
+ {id: impId}
+ ]
+ },
+ bids
+ };
+ });
+
+ describe('isBidRequestValid', function () {
+ let bid = {};
+
+ it('should return false when missing required "pid" param', function () {
+ bid.params = {random: 'param'};
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ bid.params = {d: 'd', g: 'g', p: 'p', m: 1};
+ expect(spec.isBidRequestValid(bid)).to.equal(false)
+ });
+
+ it('should return false when "pid" is malformed', function () {
+ bid.params = {pid: 'pid'};
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ bid.params = {pid: '///'};
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ bid.params = {pid: '/g/p/m'};
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ bid.params = {pid: 'd//p/m'};
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ bid.params = {pid: 'd/g//m'};
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ bid.params = {pid: 'd/p/'};
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ bid.params = {pid: 'd/g/p/m/t'};
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+
+ it('should return true when "pid" is a correct dgpm', function () {
+ bid.params = {pid: 'd/g/p/m'};
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+ it('should return true when type is blank', function () {
+ bid.params = {pid: 'd/g/p/'};
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+ it('should return true when type is missing', function () {
+ bid.params = {pid: 'd/g/p'};
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+ it('should return true when "pid" is a number', function () {
+ bid.params = {pid: 12356};
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+ it('should return true when "pid" is a numeric string', function () {
+ bid.params = {pid: '12356'};
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+ it('should return true for selfpromo unit', function () {
+ bid.params = {pid: 'selfpromo'};
+ expect(spec.isBidRequestValid(bid)).to.equal(true)
+ });
+ });
+
+ describe('buildRequests', function () {
+ beforeEach(function () {
+ r2b2.placementsToSync = [];
+ r2b2.mappedParams = {};
+ });
+
+ it('should set correct request method and url and pass bids', function () {
+ let requests = spec.buildRequests([bids[0]], bidderRequest);
+ expect(requests).to.be.an('array').that.has.lengthOf(1);
+ let request = requests[0]
+ expect(request.method).to.equal('POST');
+ expect(request.url).to.equal('https://hb.r2b2.cz/openrtb2/bid');
+ expect(request.data).to.be.an('object');
+ expect(request.bids).to.deep.equal(bids);
+ });
+
+ it('should pass correct parameters', function () {
+ let requests = spec.buildRequests([bids[0]], bidderRequest);
+ let {data} = requests[0];
+ let {imp, device, site, source, ext, cur, test} = data;
+ expect(imp).to.be.an('array').that.has.lengthOf(1);
+ expect(device).to.be.an('object');
+ expect(site).to.be.an('object');
+ expect(source).to.be.an('object');
+ expect(cur).to.deep.equal(['USD']);
+ expect(ext.version).to.equal('1.0.0');
+ expect(test).to.equal(0);
+ });
+
+ it('should pass correct imp', function () {
+ let requests = spec.buildRequests([bids[0]], bidderRequest);
+ let {data} = requests[0];
+ let {imp} = data;
+ expect(imp).to.be.an('array').that.has.lengthOf(1);
+ expect(imp[0]).to.be.an('object');
+ let bid = imp[0];
+ expect(bid.id).to.equal('20917a54ee9858');
+ expect(bid.banner).to.deep.equal({topframe: 0, format: [{w: 300, h: 250}]});
+ expect(bid.ext).to.be.an('object');
+ expect(bid.ext.r2b2).to.deep.equal({d: 'example.com', g: 'generic', p: '300x250', m: 1});
+ });
+
+ it('should map type correctly', function () {
+ let result, bid;
+ let requestWithId = function(id) {
+ let b = bids[0];
+ b.params.pid = id;
+ let passedBids = [b];
+ bidderRequest.bids = passedBids;
+ return spec.buildRequests(passedBids, bidderRequest);
+ };
+
+ result = requestWithId('example.com/generic/300x250/mobile');
+ bid = result[0].data.imp[0];
+ expect(bid.ext.r2b2.m).to.be.a('number').that.is.equal(1);
+
+ result = requestWithId('example.com/generic/300x250/desktop');
+ bid = result[0].data.imp[0];
+ expect(bid.ext.r2b2.m).to.be.a('number').that.is.equal(0);
+
+ result = requestWithId('example.com/generic/300x250/1');
+ bid = result[0].data.imp[0];
+ expect(bid.ext.r2b2.m).to.be.a('number').that.is.equal(1);
+
+ result = requestWithId('example.com/generic/300x250/0');
+ bid = result[0].data.imp[0];
+ expect(bid.ext.r2b2.m).to.be.a('number').that.is.equal(0);
+
+ result = requestWithId('example.com/generic/300x250/m');
+ bid = result[0].data.imp[0];
+ expect(bid.ext.r2b2.m).to.be.a('number').that.is.equal(1);
+
+ result = requestWithId('example.com/generic/300x250');
+ bid = result[0].data.imp[0];
+ expect(bid.ext.r2b2.m).to.be.a('number').that.is.equal(0);
+ });
+
+ it('should pass correct parameters for test ad', function () {
+ let testAdBid = bids[0];
+ testAdBid.params = {pid: 'selfpromo'};
+ let requests = spec.buildRequests([testAdBid], bidderRequest);
+ let {data} = requests[0];
+ let {imp} = data;
+ expect(imp).to.be.an('array').that.has.lengthOf(1);
+ expect(imp[0]).to.be.an('object');
+ let bid = imp[0];
+ expect(bid.ext).to.be.an('object');
+ expect(bid.ext.r2b2).to.deep.equal({d: 'test', g: 'test', p: 'selfpromo', m: 0, 'selfpromo': 1});
+ });
+
+ it('should pass multiple bids', function () {
+ let requests = spec.buildRequests(bids, bidderRequest);
+ expect(requests).to.be.an('array').that.has.lengthOf(1);
+ let {data} = requests[0];
+ let {imp} = data;
+ expect(imp).to.be.an('array').that.has.lengthOf(bids.length);
+ let bid1 = imp[0];
+ expect(bid1.ext.r2b2).to.deep.equal({d: 'example.com', g: 'generic', p: '300x250', m: 1});
+ let bid2 = imp[1];
+ expect(bid2.ext.r2b2).to.deep.equal({d: 'example.com', g: 'generic', p: '300x600', m: 0});
+ });
+
+ it('should set up internal variables', function () {
+ let requests = spec.buildRequests(bids, bidderRequest);
+ let bid1Id = bids[0].bidId;
+ let bid2Id = bids[1].bidId;
+ expect(r2b2.placementsToSync).to.be.an('array').that.has.lengthOf(2);
+ expect(r2b2.mappedParams).to.have.property(bid1Id);
+ expect(r2b2.mappedParams[bid1Id]).to.deep.equal({d: 'example.com', g: 'generic', p: '300x250', m: 1, pid: 'example.com/generic/300x250/1'});
+ expect(r2b2.mappedParams).to.have.property(bid2Id);
+ expect(r2b2.mappedParams[bid2Id]).to.deep.equal({d: 'example.com', g: 'generic', p: '300x600', m: 0, pid: 'example.com/generic/300x600/0'});
+ });
+
+ it('should pass gdpr properties', function () {
+ let requests = spec.buildRequests(bids, bidderRequest);
+ let {data} = requests[0];
+ let {user, regs} = data;
+ expect(user).to.be.an('object').that.has.property('ext');
+ expect(regs).to.be.an('object').that.has.property('ext');
+ expect(user.ext.consent).to.equal('consent-string');
+ expect(regs.ext.gdpr).to.equal(1);
+ });
+
+ it('should pass us privacy properties', function () {
+ let requests = spec.buildRequests(bids, bidderRequest);
+ let {data} = requests[0];
+ let {regs} = data;
+ expect(regs).to.be.an('object').that.has.property('ext');
+ expect(regs.ext.us_privacy).to.equal('1YYY');
+ });
+
+ it('should pass supply chain', function () {
+ let requests = spec.buildRequests(bids, bidderRequest);
+ let {data} = requests[0];
+ let {source} = data;
+ expect(source).to.be.an('object').that.has.property('ext');
+ expect(source.ext.schain).to.deep.equal({
+ complete: 1,
+ nodes: [
+ {asi: 'example.com', hp: 1, sid: '00001'}
+ ],
+ ver: '1.0'
+ })
+ });
+
+ it('should pass extended ids', function () {
+ let eidsArray = [
+ {
+ source: 'adserver.org',
+ uids: [
+ {
+ atype: 1,
+ ext: {
+ rtiPartner: 'TDID',
+ },
+ id: 'TTD_ID_FROM_USER_ID_MODULE',
+ },
+ ],
+ },
+ {
+ source: 'pubcid.org',
+ uids: [
+ {
+ atype: 1,
+ id: 'pubCommonId_FROM_USER_ID_MODULE',
+ },
+ ],
+ },
+ ];
+ bids[0].userIdAsEids = eidsArray;
+ let requests = spec.buildRequests(bids, bidderRequest);
+ let request = requests[0];
+ let eids = request.data.user.ext.eids;
+
+ expect(eids).to.deep.equal(eidsArray);
+ });
+ });
+
+ describe('interpretResponse', function () {
+ it('should respond with empty response when there are no bids', function () {
+ let result = spec.interpretResponse({ body: {} }, {});
+ expect(result).to.be.an('array').that.has.lengthOf(0);
+ result = spec.interpretResponse({ body: { seatbid: [] } }, {});
+ expect(result).to.be.an('array').that.has.lengthOf(0);
+ result = spec.interpretResponse({ body: { seatbid: [ {} ] } }, {});
+ expect(result).to.be.an('array').that.has.lengthOf(0);
+ result = spec.interpretResponse({ body: { seatbid: [ { bids: [] } ] } }, {});
+ expect(result).to.be.an('array').that.has.lengthOf(0);
+ });
+
+ it('should map params correctly', function () {
+ let result = spec.interpretResponse({ body: serverResponse }, requestForInterpretResponse);
+ expect(result).to.be.an('array').that.has.lengthOf(1);
+ let bid = result[0];
+ expect(bid.requestId).to.equal(impId);
+ expect(bid.cpm).to.equal(price);
+ expect(bid.ad).to.equal(ad);
+ expect(bid.currency).to.equal('USD');
+ expect(bid.mediaType).to.equal('banner');
+ expect(bid.width).to.equal(300);
+ expect(bid.height).to.equal(250);
+ expect(bid.netRevenue).to.equal(true);
+ expect(bid.ttl).to.equal(360);
+ expect(bid.creativeId).to.equal(creativeId);
+ });
+
+ it('should set up renderer on bid', function () {
+ let result = spec.interpretResponse({ body: serverResponse }, requestForInterpretResponse);
+ expect(result).to.be.an('array').that.has.lengthOf(1);
+ let bid = result[0];
+ expect(bid.renderer).to.be.an('object');
+ expect(bid.renderer).to.have.property('render').that.is.a('function');
+ expect(bid.renderer).to.have.property('url').that.is.a('string');
+ });
+
+ it('should map ext params correctly', function() {
+ let dgpm = {something: 'something'};
+ r2b2.mappedParams = {};
+ r2b2.mappedParams[impId] = dgpm;
+ let result = spec.interpretResponse({ body: serverResponse }, requestForInterpretResponse);
+ expect(result).to.be.an('array').that.has.lengthOf(1);
+ let bid = result[0];
+ expect(bid.ext).to.be.an('object');
+ let { ext } = bid;
+ expect(ext.dgpm).to.deep.equal(dgpm);
+ expect(ext.cid).to.equal(cid);
+ expect(ext.cdid).to.equal(cdid);
+ expect(ext.adUnit).to.equal(unitCode);
+ expect(ext.mediaType).to.deep.equal({
+ type: 'banner',
+ settings: {
+ chd: null,
+ width: 300,
+ height: 250,
+ ad: {
+ type: 'content',
+ data: ad
+ }
+ }
+ });
+ });
+
+ it('should handle multiple bids', function() {
+ const impId2 = '123456';
+ const price2 = 12;
+ const ad2 = 'gaeouho';
+ const w2 = 300;
+ const h2 = 600;
+ let b = serverResponse.seatbid[0].bid[0];
+ let b2 = Object.assign({}, b);
+ b2.impid = impId2;
+ b2.price = price2;
+ b2.adm = ad2;
+ b2.w = w2;
+ b2.h = h2;
+ serverResponse.seatbid[0].bid.push(b2);
+ requestForInterpretResponse.data.imp.push({id: impId2});
+ let result = spec.interpretResponse({ body: serverResponse }, requestForInterpretResponse);
+ expect(result).to.be.an('array').that.has.lengthOf(2);
+ let firstBid = result[0];
+ let secondBid = result[1];
+ expect(firstBid.requestId).to.equal(impId);
+ expect(firstBid.ad).to.equal(ad);
+ expect(firstBid.cpm).to.equal(price);
+ expect(firstBid.width).to.equal(300);
+ expect(firstBid.height).to.equal(250);
+ expect(secondBid.requestId).to.equal(impId2);
+ expect(secondBid.ad).to.equal(ad2);
+ expect(secondBid.cpm).to.equal(price2);
+ expect(secondBid.width).to.equal(w2);
+ expect(secondBid.height).to.equal(h2);
+ });
+ });
+
+ describe('getUserSyncs', function() {
+ const syncOptions = {
+ iframeEnabled: true,
+ pixelEnabled: true
+ };
+
+ it('should return an array with a sync for all bids', function() {
+ r2b2.placementsToSync = [id1Object, id2Object];
+ const expectedEncodedIds = encodePlacementIds(r2b2.placementsToSync);
+ const syncs = spec.getUserSyncs(syncOptions);
+ expect(syncs).to.be.an('array').that.has.lengthOf(1);
+ const sync = syncs[0];
+ expect(sync).to.be.an('object');
+ expect(sync.type).to.equal('iframe');
+ expect(sync.url).to.include(`?p=${expectedEncodedIds}`);
+ });
+
+ it('should return the sync and include gdpr and usp parameters in the url', function() {
+ r2b2.placementsToSync = [id1Object, id2Object];
+ const syncs = spec.getUserSyncs(syncOptions, {}, gdprConsent, usPrivacyString);
+ const sync = syncs[0];
+ expect(sync).to.be.an('object');
+ expect(sync.url).to.include(`&gdpr=1`);
+ expect(sync.url).to.include(`&gdpr_consent=${gdprConsent.consentString}`);
+ expect(sync.url).to.include(`&us_privacy=${usPrivacyString}`);
+ });
+ });
+
+ describe('events', function() {
+ beforeEach(function() {
+ time = sinon.useFakeTimers(fakeTime);
+ sinon.stub(utils, 'triggerPixel');
+ r2b2.mappedParams = {};
+ r2b2.mappedParams[bidId1] = id1Object;
+ r2b2.mappedParams[bidId2] = id2Object;
+ bidStub = {
+ adserverTargeting: { hb_bidder: bidder, hb_pb: '10.00', hb_size: '300x300' },
+ cpm: 10,
+ currency: 'USD',
+ ext: {
+ dgpm: { d: 'r2b2.cz', g: 'generic', m: 1, p: '300x300', pid: 'r2b2.cz/generic/300x300/1' }
+ },
+ params: [ { pid: 'r2b2.cz/generic/300x300/1' } ],
+ };
+ });
+ afterEach(function() {
+ utils.triggerPixel.restore();
+ time.restore();
+ });
+
+ describe('onBidWon', function () {
+ it('exists and is a function', () => {
+ expect(spec.onBidWon).to.exist.and.to.be.a('function');
+ });
+ it('should return nothing and trigger a pixel with passed url', function () {
+ bidStub.ext.events = {
+ onBidWon: bidWonUrl,
+ onSetTargeting: setTargetingUrl
+ };
+ const response = spec.onBidWon(bidStub);
+ expect(response).to.be.an('undefined');
+ expect(utils.triggerPixel.called).to.equal(true);
+ expect(utils.triggerPixel.callCount).to.equal(1);
+ expect(utils.triggerPixel.calledWithMatch(bidWonUrl)).to.equal(true);
+ });
+ it('should not trigger a pixel if url is not available', function () {
+ bidStub.ext.events = null;
+ spec.onBidWon(bidStub);
+ expect(utils.triggerPixel.callCount).to.equal(0);
+ bidStub.ext.events = {
+ onBidWon: '',
+ onSetTargeting: '',
+ };
+ spec.onBidWon(bidStub);
+ expect(utils.triggerPixel.callCount).to.equal(0);
+ });
+ });
+
+ describe('onSetTargeting', function () {
+ it('exists and is a function', () => {
+ expect(spec.onSetTargeting).to.exist.and.to.be.a('function');
+ });
+ it('should return nothing and trigger a pixel with passed url', function () {
+ bidStub.ext.events = {
+ onBidWon: bidWonUrl,
+ onSetTargeting: setTargetingUrl
+ };
+ const response = spec.onSetTargeting(bidStub);
+ expect(response).to.be.an('undefined');
+ expect(utils.triggerPixel.called).to.equal(true);
+ expect(utils.triggerPixel.callCount).to.equal(1);
+ expect(utils.triggerPixel.calledWithMatch(setTargetingUrl)).to.equal(true);
+ });
+ it('should not trigger a pixel if url is not available', function () {
+ bidStub.ext.events = null;
+ spec.onSetTargeting(bidStub);
+ expect(utils.triggerPixel.callCount).to.equal(0);
+ bidStub.ext.events = {
+ onBidWon: '',
+ onSetTargeting: '',
+ };
+ spec.onSetTargeting(bidStub);
+ expect(utils.triggerPixel.callCount).to.equal(0);
+ });
+ });
+
+ describe('onTimeout', function () {
+ it('exists and is a function', () => {
+ expect(spec.onTimeout).to.exist.and.to.be.a('function');
+ });
+ it('should return nothing and trigger a pixel', function () {
+ const bids = [bid1, bid2];
+ const response = spec.onTimeout(bids);
+ expect(response).to.be.an('undefined');
+ expect(utils.triggerPixel.callCount).to.equal(1);
+ });
+ it('should not trigger a pixel if no bids available', function () {
+ const bids = [];
+ spec.onTimeout(bids);
+ expect(utils.triggerPixel.callCount).to.equal(0);
+ });
+ it('should trigger a pixel with correct ids and a cache buster', function () {
+ const bids = [bid1, bidForeign1, bidForeign2, bid2, bidWithBadSetup];
+ const expectedIds = [id1Object, id2Object];
+ const expectedEncodedIds = encodePlacementIds(expectedIds);
+ spec.onTimeout(bids);
+ expect(utils.triggerPixel.callCount).to.equal(1);
+ const triggeredUrl = utils.triggerPixel.args[0][0];
+ expect(triggeredUrl).to.include(`p=${expectedEncodedIds}`);
+ expect(triggeredUrl.match(cacheBusterRegex)).to.exist;
+ });
+ });
+
+ describe('onBidderError', function () {
+ it('exists and is a function', () => {
+ expect(spec.onBidderError).to.exist.and.to.be.a('function');
+ });
+ it('should return nothing and trigger a pixel', function () {
+ const bidderRequest = { bids: [bid1, bid2] };
+ const response = spec.onBidderError({ bidderRequest });
+ expect(response).to.be.an('undefined')
+ expect(utils.triggerPixel.callCount).to.equal(1);
+ });
+ it('should not trigger a pixel if no bids available', function () {
+ const bidderRequest = { bids: [] };
+ spec.onBidderError({ bidderRequest });
+ expect(utils.triggerPixel.callCount).to.equal(0);
+ });
+ it('should call triggerEvent with correct ids and a cache buster', function () {
+ const bids = [bid1, bid2, bidWithBadSetup]
+ const bidderRequest = { bids };
+ const expectedIds = [id1Object, id2Object];
+ const expectedEncodedIds = encodePlacementIds(expectedIds);
+ spec.onBidderError({ bidderRequest });
+ expect(utils.triggerPixel.callCount).to.equal(1);
+ const triggeredUrl = utils.triggerPixel.args[0][0];
+ expect(triggeredUrl).to.include(`p=${expectedEncodedIds}`);
+ expect(triggeredUrl.match(cacheBusterRegex)).to.exist;
+ });
+ });
+ });
+});
diff --git a/test/spec/modules/rasBidAdapter_spec.js b/test/spec/modules/rasBidAdapter_spec.js
index bfa72a2510e..f172d192221 100644
--- a/test/spec/modules/rasBidAdapter_spec.js
+++ b/test/spec/modules/rasBidAdapter_spec.js
@@ -63,6 +63,20 @@ describe('rasBidAdapter', function () {
customParams: {
test: 'name=value'
}
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [
+ 300,
+ 250
+ ],
+ [
+ 300,
+ 600
+ ]
+ ]
+ }
}
};
const bid2 = {
@@ -74,6 +88,16 @@ describe('rasBidAdapter', function () {
area: 'areatest',
site: 'test',
network: '4178463'
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [
+ 750,
+ 300
+ ]
+ ]
+ }
}
};
@@ -127,6 +151,7 @@ describe('rasBidAdapter', function () {
}
};
const requests = spec.buildRequests([bidCopy, bid2]);
+
expect(requests[0].url).to.have.string(CSR_ENDPOINT);
expect(requests[0].url).to.have.string('slot0=test');
expect(requests[0].url).to.have.string('id0=1');
@@ -147,6 +172,39 @@ describe('rasBidAdapter', function () {
expect(requests[0].url).to.have.string('kvadunit=test%2Fareatest');
expect(requests[0].url).to.have.string('pos0=0');
});
+
+ it('should parse dsainfo when available', function () {
+ const bidCopy = { ...bid };
+ bidCopy.params = {
+ ...bid.params,
+ pageContext: {
+ dv: 'test/areatest',
+ du: 'https://example.com/',
+ dr: 'https://example.org/',
+ keyWords: ['val1', 'val2'],
+ keyValues: {
+ adunit: 'test/areatest'
+ }
+ }
+ };
+ let bidderRequest = {
+ ortb2: {
+ regs: {
+ ext: {
+ dsa: {
+ required: 1
+ }
+ }
+ }
+ }
+ };
+ let requests = spec.buildRequests([bidCopy], bidderRequest);
+ expect(requests[0].url).to.have.string('dsainfo=1');
+
+ bidderRequest.ortb2.regs.ext.dsa.required = 0;
+ requests = spec.buildRequests([bidCopy], bidderRequest);
+ expect(requests[0].url).to.have.string('dsainfo=0');
+ });
});
describe('interpretResponse', function () {
@@ -171,7 +229,7 @@ describe('rasBidAdapter', function () {
it('should get correct bid response', function () {
const resp = spec.interpretResponse({ body: response }, { bidIds: [{ slot: 'flat-belkagorna', bidId: 1 }] });
- expect(resp[0]).to.have.all.keys('cpm', 'currency', 'netRevenue', 'requestId', 'ttl', 'width', 'height', 'creativeId', 'dealId', 'ad', 'meta');
+ expect(resp[0]).to.have.all.keys('cpm', 'currency', 'netRevenue', 'requestId', 'ttl', 'width', 'height', 'creativeId', 'dealId', 'ad', 'meta', 'actgMatch', 'mediaType');
expect(resp.length).to.equal(1);
});
@@ -192,5 +250,361 @@ describe('rasBidAdapter', function () {
const resp = spec.interpretResponse({ body: res }, {});
expect(resp).to.deep.equal([]);
});
+
+ it('should generate auctionConfig when fledge is enabled', function () {
+ let bidRequest = {
+ method: 'GET',
+ url: 'https://example.com',
+ bidIds: [{
+ slot: 'top',
+ bidId: '123',
+ network: 'testnetwork',
+ sizes: ['300x250'],
+ params: {
+ site: 'testsite',
+ area: 'testarea',
+ network: 'testnetwork'
+ },
+ fledgeEnabled: true
+ },
+ {
+ slot: 'top',
+ bidId: '456',
+ network: 'testnetwork',
+ sizes: ['300x250'],
+ params: {
+ site: 'testsite',
+ area: 'testarea',
+ network: 'testnetwork'
+ },
+ fledgeEnabled: false
+ }]
+ };
+
+ let auctionConfigs = [{
+ 'bidId': '123',
+ 'config': {
+ 'seller': 'https://csr.onet.pl',
+ 'decisionLogicUrl': 'https://csr.onet.pl/testnetwork/v1/protected-audience-api/decision-logic.js',
+ 'interestGroupBuyers': ['https://csr.onet.pl'],
+ 'auctionSignals': {
+ 'params': {
+ site: 'testsite',
+ area: 'testarea',
+ network: 'testnetwork'
+ },
+ 'sizes': ['300x250'],
+ 'gctx': '1234567890'
+ }
+ }
+ }];
+ const resp = spec.interpretResponse({body: {gctx: '1234567890'}}, bidRequest);
+ expect(resp).to.deep.equal({bids: [], fledgeAuctionConfigs: auctionConfigs});
+ });
+ });
+
+ describe('buildNativeRequests', function () {
+ const bid = {
+ sizes: 'fluid',
+ bidder: 'ras',
+ bidId: 1,
+ params: {
+ slot: 'nativestd',
+ area: 'areatest',
+ site: 'test',
+ slotSequence: '0',
+ network: '4178463',
+ customParams: {
+ test: 'name=value'
+ }
+ },
+ mediaTypes: {
+ native: {
+ clickUrl: {
+ required: true
+ },
+ image: {
+ required: true
+ },
+ sponsoredBy: {
+ len: 25,
+ required: true
+ },
+ title: {
+ len: 50,
+ required: true
+ }
+ }
+ }
+ };
+
+ it('should parse bids to native request', function () {
+ const requests = spec.buildRequests([bid], {
+ 'gdprConsent': {
+ 'gdprApplies': true,
+ 'consentString': 'some-consent-string'
+ },
+ 'refererInfo': {
+ 'ref': 'https://example.org/',
+ 'page': 'https://example.com/'
+ }
+ });
+
+ expect(requests[0].url).to.have.string(CSR_ENDPOINT);
+ expect(requests[0].url).to.have.string('slot0=nativestd');
+ expect(requests[0].url).to.have.string('id0=1');
+ expect(requests[0].url).to.have.string('site=test');
+ expect(requests[0].url).to.have.string('area=areatest');
+ expect(requests[0].url).to.have.string('cre_format=html');
+ expect(requests[0].url).to.have.string('systems=das');
+ expect(requests[0].url).to.have.string('ems_url=1');
+ expect(requests[0].url).to.have.string('bid_rate=1');
+ expect(requests[0].url).to.have.string('gdpr_applies=true');
+ expect(requests[0].url).to.have.string('euconsent=some-consent-string');
+ expect(requests[0].url).to.have.string('du=https%3A%2F%2Fexample.com%2F');
+ expect(requests[0].url).to.have.string('dr=https%3A%2F%2Fexample.org%2F');
+ expect(requests[0].url).to.have.string('test=name%3Dvalue');
+ expect(requests[0].url).to.have.string('cre_format0=native');
+ expect(requests[0].url).to.have.string('iusizes0=fluid');
+ });
+ });
+
+ describe('interpretNativeResponse', function () {
+ const response = {
+ 'adsCheck': 'ok',
+ 'geoloc': {},
+ 'ir': '92effd60-0c84-4dac-817e-763ea7b8ac65',
+ 'iv': '202003191334467636346500',
+ 'ads': [
+ {
+ 'id': 'nativestd',
+ 'slot': 'nativestd',
+ 'prio': 10,
+ 'type': 'native',
+ 'bid_rate': 0.321123,
+ 'adid': 'das,50463,152276',
+ 'id_3': '12734'
+ }
+ ]
+ };
+ const responseTeaserStandard = {
+ adsCheck: 'ok',
+ geoloc: {},
+ ir: '92effd60-0c84-4dac-817e-763ea7b8ac65',
+ iv: '202003191334467636346500',
+ ads: [
+ {
+ id: 'nativestd',
+ slot: 'nativestd',
+ prio: 10,
+ type: 'native',
+ bid_rate: 0.321123,
+ adid: 'das,50463,152276',
+ id_3: '12734',
+ data: {
+ fields: {
+ leadtext: 'BODY',
+ title: 'Headline',
+ image: '//img.url',
+ url: '//link.url',
+ impression: '//impression.url',
+ impression1: '//impression1.url',
+ impressionJs1: '//impressionJs1.url'
+ },
+ meta: {
+ slot: 'nativestd',
+ height: 1,
+ width: 1,
+ advertiser_name: 'Test Onet',
+ dsaurl: '//dsa.url',
+ adclick: '//adclick.url'
+ }
+ },
+ ems_link: '//ems.url'
+ }
+ ]
+ };
+ const responseNativeInFeed = {
+ adsCheck: 'ok',
+ geoloc: {},
+ ir: '92effd60-0c84-4dac-817e-763ea7b8ac65',
+ iv: '202003191334467636346500',
+ ads: [
+ {
+ id: 'nativestd',
+ slot: 'nativestd',
+ prio: 10,
+ type: 'native',
+ bid_rate: 0.321123,
+ adid: 'das,50463,152276',
+ id_3: '12734',
+ data: {
+ fields: {
+ Body: 'BODY',
+ Calltoaction: 'Calltoaction',
+ Headline: 'Headline',
+ Image: '//img.url',
+ Sponsorlabel: 'nie',
+ Thirdpartyclicktracker: '//link.url',
+ imp: '//imp.url'
+ },
+ meta: {
+ slot: 'nativestd',
+ height: 1,
+ width: 1,
+ advertiser_name: 'Test Onet',
+ dsaurl: '//dsa.url',
+ adclick: '//adclick.url'
+ }
+ },
+ ems_link: '//ems.url'
+ }
+ ]
+ };
+ const expectedTeaserStandardOrtbResponse = {
+ ver: '1.2',
+ assets: [
+ {
+ id: 2,
+ img: {
+ url: '//img.url',
+ w: 1,
+ h: 1
+ }
+ },
+ {
+ id: 4,
+ title: {
+ text: 'Headline'
+ }
+ },
+ {
+ id: 3,
+ data: {
+ value: 'Test Onet',
+ type: 1
+ }
+ }
+ ],
+ link: {
+ url: '//adclick.url//link.url'
+ },
+ eventtrackers: [
+ {
+ event: 1,
+ method: 1,
+ url: '//ems.url'
+ },
+ {
+ event: 1,
+ method: 1,
+ url: '//impression.url'
+ },
+ {
+ event: 1,
+ method: 1,
+ url: '//impression1.url'
+ },
+ {
+ event: 1,
+ method: 2,
+ url: '//impressionJs1.url'
+ }
+ ],
+ privacy: '//dsa.url'
+ };
+ const expectedTeaserStandardResponse = {
+ sendTargetingKeys: false,
+ title: 'Headline',
+ image: {
+ url: '//img.url',
+ width: 1,
+ height: 1
+ },
+ clickUrl: '//adclick.url//link.url',
+ cta: '',
+ body: 'BODY',
+ sponsoredBy: 'Test Onet',
+ ortb: expectedTeaserStandardOrtbResponse,
+ privacyLink: '//dsa.url'
+ };
+ const expectedNativeInFeedOrtbResponse = {
+ ver: '1.2',
+ assets: [
+ {
+ id: 2,
+ img: {
+ url: '//img.url',
+ w: 1,
+ h: 1
+ }
+ },
+ {
+ id: 4,
+ title: {
+ text: 'Headline'
+ }
+ },
+ {
+ id: 3,
+ data: {
+ value: 'Test Onet',
+ type: 1
+ }
+ }
+ ],
+ link: {
+ url: '//adclick.url//link.url'
+ },
+ eventtrackers: [
+ {
+ event: 1,
+ method: 1,
+ url: '//ems.url'
+ },
+ {
+ event: 1,
+ method: 1,
+ url: '//imp.url'
+ }
+ ],
+ privacy: '//dsa.url',
+ };
+ const expectedNativeInFeedResponse = {
+ sendTargetingKeys: false,
+ title: 'Headline',
+ image: {
+ url: '//img.url',
+ width: 1,
+ height: 1
+ },
+ clickUrl: '//adclick.url//link.url',
+ cta: 'Calltoaction',
+ body: 'BODY',
+ sponsoredBy: 'Test Onet',
+ ortb: expectedNativeInFeedOrtbResponse,
+ privacyLink: '//dsa.url'
+ };
+
+ it('should get correct bid native response', function () {
+ const resp = spec.interpretResponse({ body: response }, { bidIds: [{ slot: 'nativestd', bidId: 1, mediaType: 'native' }] });
+
+ expect(resp[0]).to.have.all.keys('cpm', 'currency', 'netRevenue', 'requestId', 'ttl', 'width', 'height', 'creativeId', 'dealId', 'meta', 'actgMatch', 'mediaType', 'native');
+ expect(resp.length).to.equal(1);
+ });
+
+ it('should get correct native response for TeaserStandard', function () {
+ const resp = spec.interpretResponse({ body: responseTeaserStandard }, { bidIds: [{ slot: 'nativestd', bidId: 1, mediaType: 'native' }] });
+ const teaserStandardResponse = resp[0].native;
+
+ expect(JSON.stringify(teaserStandardResponse)).to.equal(JSON.stringify(expectedTeaserStandardResponse));
+ });
+
+ it('should get correct native response for NativeInFeed', function () {
+ const resp = spec.interpretResponse({ body: responseNativeInFeed }, { bidIds: [{ slot: 'nativestd', bidId: 1, mediaType: 'native' }] });
+ const nativeInFeedResponse = resp[0].native;
+
+ expect(JSON.stringify(nativeInFeedResponse)).to.equal(JSON.stringify(expectedNativeInFeedResponse));
+ });
});
});
diff --git a/test/spec/modules/raynRtdProvider_spec.js b/test/spec/modules/raynRtdProvider_spec.js
new file mode 100644
index 00000000000..69ea316e8b5
--- /dev/null
+++ b/test/spec/modules/raynRtdProvider_spec.js
@@ -0,0 +1,308 @@
+import * as raynRTD from 'modules/raynRtdProvider.js';
+import { config } from 'src/config.js';
+import * as utils from 'src/utils.js';
+
+const TEST_CHECKSUM = '-1135402174';
+const TEST_URL = 'http://localhost:9876/context.html';
+const TEST_SEGMENTS = {
+ [TEST_CHECKSUM]: {
+ 7: {
+ 2: ['51', '246', '652', '48', '324']
+ }
+ }
+};
+
+const RTD_CONFIG = {
+ auctionDelay: 250,
+ dataProviders: [
+ {
+ name: 'rayn',
+ waitForIt: true,
+ params: {
+ bidders: [],
+ integration: {
+ iabAudienceCategories: {
+ v1_1: {
+ tier: 6,
+ enabled: true,
+ },
+ },
+ iabContentCategories: {
+ v3_0: {
+ tier: 4,
+ enabled: true,
+ },
+ v2_2: {
+ tier: 4,
+ enabled: true,
+ },
+ },
+ }
+ },
+ },
+ ],
+};
+
+describe('rayn RTD Submodule', function () {
+ let getDataFromLocalStorageStub;
+
+ beforeEach(function () {
+ config.resetConfig();
+ getDataFromLocalStorageStub = sinon.stub(
+ raynRTD.storage,
+ 'getDataFromLocalStorage',
+ );
+ });
+
+ afterEach(function () {
+ getDataFromLocalStorageStub.restore();
+ });
+
+ describe('Initialize module', function () {
+ it('should initialize and return true', function () {
+ expect(raynRTD.raynSubmodule.init(RTD_CONFIG.dataProviders[0])).to.equal(
+ true,
+ );
+ });
+ });
+
+ describe('Generate ortb data object', function () {
+ it('should set empty segment array', function () {
+ expect(raynRTD.generateOrtbDataObject(7, 'invalid', 2).segment).to.be.instanceOf(Array).and.lengthOf(0);
+ });
+
+ it('should set segment array', function () {
+ const expectedSegmentIdsMap = TEST_SEGMENTS[TEST_CHECKSUM][7][2].map((id) => {
+ return { id };
+ });
+ expect(raynRTD.generateOrtbDataObject(7, TEST_SEGMENTS[TEST_CHECKSUM][7], 4)).to.deep.equal({
+ name: raynRTD.SEGMENTS_RESOLVER,
+ ext: {
+ segtax: 7,
+ },
+ segment: expectedSegmentIdsMap,
+ });
+ });
+ });
+
+ describe('Generate checksum', function () {
+ it('should generate checksum', function () {
+ expect(raynRTD.generateChecksum(TEST_URL)).to.equal(TEST_CHECKSUM);
+ });
+ });
+
+ describe('Get segments', function () {
+ it('should get segments from local storage', function () {
+ getDataFromLocalStorageStub
+ .withArgs(raynRTD.RAYN_LOCAL_STORAGE_KEY)
+ .returns(JSON.stringify(TEST_SEGMENTS));
+
+ const segments = raynRTD.readSegments(raynRTD.RAYN_LOCAL_STORAGE_KEY);
+
+ expect(segments).to.deep.equal(TEST_SEGMENTS);
+ });
+
+ it('should return null if unable to read and parse data from local storage', function () {
+ const testString = 'test';
+ getDataFromLocalStorageStub
+ .withArgs(raynRTD.RAYN_LOCAL_STORAGE_KEY)
+ .returns(testString);
+
+ const segments = raynRTD.readSegments(raynRTD.RAYN_LOCAL_STORAGE_KEY);
+
+ expect(segments).to.equal(null);
+ });
+ });
+
+ describe('Set segments as bidder ortb2', function () {
+ it('should set global ortb2 config', function () {
+ const globalOrtb2 = {};
+ const bidders = RTD_CONFIG.dataProviders[0].params.bidders;
+ const integrationConfig = RTD_CONFIG.dataProviders[0].params.integration;
+
+ raynRTD.setSegmentsAsBidderOrtb2({ ortb2Fragments: { global: globalOrtb2 } }, bidders, integrationConfig, TEST_SEGMENTS, TEST_CHECKSUM);
+
+ TEST_SEGMENTS[TEST_CHECKSUM]['7']['2'].forEach((id) => {
+ expect(globalOrtb2.site.content.data[0].segment.find(segment => segment.id === id)).to.exist;
+ })
+ });
+
+ it('should set bidder specific ortb2 config', function () {
+ RTD_CONFIG.dataProviders[0].params.bidders = ['appnexus'];
+
+ const bidderOrtb2 = {};
+ const bidders = RTD_CONFIG.dataProviders[0].params.bidders;
+ const integrationConfig = RTD_CONFIG.dataProviders[0].params.integration;
+
+ raynRTD.setSegmentsAsBidderOrtb2({ ortb2Fragments: { bidder: bidderOrtb2 } }, bidders, integrationConfig, TEST_SEGMENTS, TEST_CHECKSUM);
+
+ bidders.forEach((bidder) => {
+ const ortb2 = bidderOrtb2[bidder];
+ TEST_SEGMENTS[TEST_CHECKSUM]['7']['2'].forEach((id) => {
+ expect(ortb2.site.content.data[0].segment.find(segment => segment.id === id)).to.exist;
+ })
+ });
+ });
+
+ it('should set bidder specific ortb2 config with all segments', function () {
+ TEST_SEGMENTS['4'] = {
+ 3: ['4', '17', '72', '612']
+ };
+ TEST_SEGMENTS[TEST_CHECKSUM]['6'] = {
+ 2: ['71', '313'],
+ 4: ['33', '145', '712']
+ };
+
+ const bidderOrtb2 = {};
+ const bidders = RTD_CONFIG.dataProviders[0].params.bidders;
+ const integrationConfig = RTD_CONFIG.dataProviders[0].params.integration;
+
+ raynRTD.setSegmentsAsBidderOrtb2({ ortb2Fragments: { bidder: bidderOrtb2 } }, bidders, integrationConfig, TEST_SEGMENTS, TEST_CHECKSUM);
+
+ bidders.forEach((bidder) => {
+ const ortb2 = bidderOrtb2[bidder];
+
+ TEST_SEGMENTS[TEST_CHECKSUM]['6']['2'].forEach((id) => {
+ expect(ortb2.site.content.data[0].segment.find(segment => segment.id === id)).to.exist;
+ });
+ TEST_SEGMENTS[TEST_CHECKSUM]['6']['4'].forEach((id) => {
+ expect(ortb2.site.content.data[0].segment.find(segment => segment.id === id)).to.exist;
+ });
+ TEST_SEGMENTS[TEST_CHECKSUM]['7']['2'].forEach((id) => {
+ expect(ortb2.site.content.data[1].segment.find(segment => segment.id === id)).to.exist;
+ });
+ TEST_SEGMENTS['4']['3'].forEach((id) => {
+ expect(ortb2.user.data[0].segment.find(segment => segment.id === id)).to.exist;
+ });
+ });
+ });
+ });
+
+ describe('Alter Bid Requests', function () {
+ it('should update reqBidsConfigObj and execute callback', function () {
+ const callbackSpy = sinon.spy();
+ const logMessageSpy = sinon.spy(utils, 'logMessage');
+
+ getDataFromLocalStorageStub
+ .withArgs(raynRTD.RAYN_LOCAL_STORAGE_KEY)
+ .returns(JSON.stringify(TEST_SEGMENTS));
+
+ const reqBidsConfigObj = { ortb2Fragments: { bidder: {} } };
+
+ raynRTD.raynSubmodule.getBidRequestData(reqBidsConfigObj, callbackSpy, RTD_CONFIG);
+
+ expect(callbackSpy.calledOnce).to.be.true;
+ expect(logMessageSpy.lastCall.lastArg).to.equal(`Segtax data from localStorage: ${JSON.stringify(TEST_SEGMENTS)}`);
+
+ logMessageSpy.restore();
+ });
+
+ it('should update reqBidsConfigObj and execute callback using user segments from localStorage', function () {
+ const callbackSpy = sinon.spy();
+ const logMessageSpy = sinon.spy(utils, 'logMessage');
+ const testSegments = {
+ 4: {
+ 3: ['4', '17', '72', '612']
+ }
+ };
+
+ getDataFromLocalStorageStub
+ .withArgs(raynRTD.RAYN_LOCAL_STORAGE_KEY)
+ .returns(JSON.stringify(testSegments));
+
+ RTD_CONFIG.dataProviders[0].params.integration.iabContentCategories = {
+ v3_0: {
+ enabled: false,
+ },
+ v2_2: {
+ enabled: false,
+ },
+ };
+
+ const reqBidsConfigObj = { ortb2Fragments: { bidder: {} } };
+
+ raynRTD.raynSubmodule.getBidRequestData(reqBidsConfigObj, callbackSpy, RTD_CONFIG.dataProviders[0]);
+
+ expect(callbackSpy.calledOnce).to.be.true;
+ expect(logMessageSpy.lastCall.lastArg).to.equal(`Segtax data from localStorage: ${JSON.stringify(testSegments)}`);
+
+ logMessageSpy.restore();
+ });
+
+ it('should update reqBidsConfigObj and execute callback using segments from raynJS', function () {
+ const callbackSpy = sinon.spy();
+ const logMessageSpy = sinon.spy(utils, 'logMessage');
+
+ getDataFromLocalStorageStub
+ .withArgs(raynRTD.RAYN_LOCAL_STORAGE_KEY)
+ .returns(null);
+
+ const reqBidsConfigObj = { ortb2Fragments: { bidder: {} } };
+
+ raynRTD.raynSubmodule.getBidRequestData(reqBidsConfigObj, callbackSpy, RTD_CONFIG.dataProviders[0]);
+
+ expect(callbackSpy.calledOnce).to.be.true;
+ expect(logMessageSpy.lastCall.lastArg).to.equal(`No segtax data`);
+
+ logMessageSpy.restore();
+ });
+
+ it('should update reqBidsConfigObj and execute callback using audience from localStorage', function (done) {
+ const callbackSpy = sinon.spy();
+ const logMessageSpy = sinon.spy(utils, 'logMessage');
+ const testSegments = {
+ 6: {
+ 4: ['3', '27', '177']
+ }
+ };
+
+ global.window.raynJS = {
+ getSegtax: function () {
+ return Promise.resolve(testSegments);
+ }
+ };
+
+ getDataFromLocalStorageStub
+ .withArgs(raynRTD.RAYN_LOCAL_STORAGE_KEY)
+ .returns(null);
+
+ const reqBidsConfigObj = { ortb2Fragments: { bidder: {} } };
+
+ raynRTD.raynSubmodule.getBidRequestData(reqBidsConfigObj, callbackSpy, RTD_CONFIG.dataProviders[0]);
+
+ setTimeout(() => {
+ expect(callbackSpy.calledOnce).to.be.true;
+ expect(logMessageSpy.lastCall.lastArg).to.equal(`Segtax data from RaynJS: ${JSON.stringify(testSegments)}`);
+ logMessageSpy.restore();
+ done();
+ }, 0)
+ });
+
+ it('should execute callback if log error', function (done) {
+ const callbackSpy = sinon.spy();
+ const logErrorSpy = sinon.spy(utils, 'logError');
+ const rejectError = 'Error';
+
+ global.window.raynJS = {
+ getSegtax: function () {
+ return Promise.reject(rejectError);
+ }
+ };
+
+ getDataFromLocalStorageStub
+ .withArgs(raynRTD.RAYN_LOCAL_STORAGE_KEY)
+ .returns(null);
+
+ const reqBidsConfigObj = { ortb2Fragments: { bidder: {} } };
+
+ raynRTD.raynSubmodule.getBidRequestData(reqBidsConfigObj, callbackSpy, RTD_CONFIG.dataProviders[0]);
+
+ setTimeout(() => {
+ expect(callbackSpy.calledOnce).to.be.true;
+ expect(logErrorSpy.lastCall.lastArg).to.equal(rejectError);
+ logErrorSpy.restore();
+ done();
+ }, 0)
+ });
+ });
+});
diff --git a/test/spec/modules/readpeakBidAdapter_spec.js b/test/spec/modules/readpeakBidAdapter_spec.js
index 8772aeac88f..32a4d991054 100644
--- a/test/spec/modules/readpeakBidAdapter_spec.js
+++ b/test/spec/modules/readpeakBidAdapter_spec.js
@@ -376,7 +376,7 @@ describe('ReadPeakAdapter', function() {
height: 500
});
expect(bidResponse.native.clickUrl).to.equal(
- 'http%3A%2F%2Furl.to%2Ftarget'
+ 'http://url.to/target'
);
expect(bidResponse.native.impressionTrackers).to.contain(
'http://url.to/pixeltracker'
diff --git a/test/spec/modules/relaidoBidAdapter_spec.js b/test/spec/modules/relaidoBidAdapter_spec.js
index 7778e9cbf80..f0d019913e8 100644
--- a/test/spec/modules/relaidoBidAdapter_spec.js
+++ b/test/spec/modules/relaidoBidAdapter_spec.js
@@ -239,6 +239,7 @@ describe('RelaidoAdapter', function () {
const request = data.bids[0];
expect(bidRequests.method).to.equal('POST');
expect(bidRequests.url).to.equal('https://api.relaido.jp/bid/v1/sprebid');
+ expect(data.canonical_url).to.equal('https://publisher.com/home');
expect(data.canonical_url_hash).to.equal('e6092f44a0044903ae3764126eedd6187c1d9f04');
expect(data.ref).to.equal(bidderRequest.refererInfo.page);
expect(data.timeout_ms).to.equal(bidderRequest.timeout);
@@ -317,6 +318,23 @@ describe('RelaidoAdapter', function () {
expect(data.bids).to.have.lengthOf(1);
expect(data.imuid).to.equal('i.tjHcK_7fTcqnbrS_YA2vaw');
});
+
+ it('should get userIdAsEids', function () {
+ const userIdAsEids = [
+ {
+ source: 'hogehoge.com',
+ uids: {
+ atype: 1,
+ id: 'hugahuga'
+ }
+ }
+ ]
+ bidRequest.userIdAsEids = userIdAsEids
+ const bidRequests = spec.buildRequests([bidRequest], bidderRequest);
+ const data = JSON.parse(bidRequests.data);
+ expect(data.bids[0].userIdAsEids).to.have.lengthOf(1);
+ expect(data.bids[0].userIdAsEids[0].source).to.equal('hogehoge.com');
+ });
});
describe('spec.interpretResponse', function () {
@@ -325,6 +343,7 @@ describe('RelaidoAdapter', function () {
expect(bidResponses).to.have.lengthOf(1);
const response = bidResponses[0];
expect(response.requestId).to.equal(serverRequest.data.bids[0].bidId);
+ expect(response.placementId).to.equal(serverResponse.body.ads[0].placementId);
expect(response.width).to.equal(serverRequest.data.bids[0].width);
expect(response.height).to.equal(serverRequest.data.bids[0].height);
expect(response.cpm).to.equal(serverResponse.body.ads[0].price);
@@ -343,6 +362,7 @@ describe('RelaidoAdapter', function () {
expect(bidResponses).to.have.lengthOf(1);
const response = bidResponses[0];
expect(response.requestId).to.equal(serverRequest.data.bids[0].bidId);
+ expect(response.placementId).to.equal(serverResponse.body.ads[0].placementId);
expect(response.width).to.equal(serverRequest.data.bids[0].width);
expect(response.height).to.equal(serverRequest.data.bids[0].height);
expect(response.cpm).to.equal(serverResponse.body.ads[0].price);
@@ -360,6 +380,7 @@ describe('RelaidoAdapter', function () {
expect(bidResponses).to.have.lengthOf(1);
const response = bidResponses[0];
expect(response.requestId).to.equal(serverRequest.data.bids[0].bidId);
+ expect(response.placementId).to.equal(serverResponseBanner.body.ads[0].placementId);
expect(response.cpm).to.equal(serverResponseBanner.body.ads[0].price);
expect(response.currency).to.equal(serverResponseBanner.body.ads[0].currency);
expect(response.creativeId).to.equal(serverResponseBanner.body.ads[0].creativeId);
diff --git a/test/spec/modules/relevantdigitalBidAdapter_spec.js b/test/spec/modules/relevantdigitalBidAdapter_spec.js
index b2a5495b3cb..0e21453c8ba 100644
--- a/test/spec/modules/relevantdigitalBidAdapter_spec.js
+++ b/test/spec/modules/relevantdigitalBidAdapter_spec.js
@@ -1,5 +1,10 @@
import {spec, resetBidderConfigs} from 'modules/relevantdigitalBidAdapter.js';
import { parseUrl, deepClone } from 'src/utils.js';
+import { config } from 'src/config.js';
+import CONSTANTS from 'src/constants.json';
+
+import adapterManager, {
+} from 'src/adapterManager.js';
const expect = require('chai').expect;
@@ -9,14 +14,29 @@ const ACCOUNT_ID = 'example_account_id';
const TEST_DOMAIN = 'example.com';
const TEST_PAGE = `https://${TEST_DOMAIN}/page.html`;
-const BID_REQUEST =
-{
- 'bidder': 'relevantdigital',
+const CONFIG = {
+ enabled: true,
+ endpoint: CONSTANTS.S2S.DEFAULT_ENDPOINT,
+ timeout: 1000,
+ maxBids: 1,
+ adapter: 'prebidServer',
+ bidders: ['relevantdigital'],
+ accountId: 'abc'
+};
+
+const ADUNIT_CODE = '/19968336/header-bid-tag-0';
+
+const BID_PARAMS = {
'params': {
'placementId': PLACEMENT_ID,
'accountId': ACCOUNT_ID,
- 'pbsHost': PBS_HOST,
- },
+ 'pbsHost': PBS_HOST
+ }
+};
+
+const BID_REQUEST = {
+ 'bidder': 'relevantdigital',
+ ...BID_PARAMS,
'ortb2Imp': {
'ext': {
'tid': 'e13391ea-00f3-495d-99a6-d937990d73a9'
@@ -32,7 +52,7 @@ const BID_REQUEST =
]
}
},
- 'adUnitCode': '/19968336/header-bid-tag-0',
+ 'adUnitCode': ADUNIT_CODE,
'transactionId': 'e13391ea-00f3-495d-99a6-d937990d73a9',
'sizes': [
[
@@ -292,4 +312,64 @@ describe('Relevant Digital Bid Adaper', function () {
expect(allSyncs).to.deep.equal(expectedResult)
});
});
+ describe('transformBidParams', function () {
+ beforeEach(() => {
+ config.setConfig({
+ s2sConfig: CONFIG,
+ });
+ });
+ afterEach(() => {
+ config.resetConfig();
+ });
+
+ const adUnit = (params) => ({
+ code: ADUNIT_CODE,
+ bids: [
+ {
+ bidder: 'relevantdigital',
+ adUnitCode: ADUNIT_CODE,
+ params,
+ }
+ ]
+ });
+
+ const request = (params) => adapterManager.makeBidRequests([adUnit(params)], 123, 'auction-id', 123, [], {})[0];
+
+ it('transforms adunit bid params and config params correctly', function () {
+ config.setConfig({
+ relevantdigital: {
+ pbsHost: PBS_HOST,
+ accountId: ACCOUNT_ID,
+ },
+ });
+ const adUnitParams = { placementId: PLACEMENT_ID };
+ const expextedTransformedBidParams = {
+ ...BID_PARAMS.params, pbsHost: `https://${BID_PARAMS.params.pbsHost}`, 'pbsBufferMs': 250
+ };
+ expect(spec.transformBidParams(adUnitParams, null, null, [request(adUnitParams)])).to.deep.equal(expextedTransformedBidParams);
+ });
+ it('transforms adunit bid params correctly', function () {
+ const adUnitParams = { ...BID_PARAMS.params, pbsHost: 'host.relevant-digital.com', pbsBufferMs: 500 };
+ const expextedTransformedBidParams = {
+ ...BID_PARAMS.params, pbsHost: 'host.relevant-digital.com', pbsBufferMs: 500
+ };
+ expect(spec.transformBidParams(adUnitParams, null, null, [request(adUnitParams)])).to.deep.equal(expextedTransformedBidParams);
+ });
+ it('transforms adunit bid params correctly', function () {
+ const adUnitParams = { ...BID_PARAMS.params, pbsHost: 'host.relevant-digital.com', pbsBufferMs: 500 };
+ const expextedTransformedBidParams = {
+ ...BID_PARAMS.params, pbsHost: 'host.relevant-digital.com', pbsBufferMs: 500
+ };
+ expect(spec.transformBidParams(adUnitParams, null, null, [request(adUnitParams)])).to.deep.equal(expextedTransformedBidParams);
+ });
+ it('does not transform bid params if placementId is missing', function () {
+ const adUnitParams = { ...BID_PARAMS.params, placementId: null };
+ expect(spec.transformBidParams(adUnitParams, null, null, [request(adUnitParams)])).to.equal(undefined);
+ });
+ it('does not transform bid params s2s config is missing', function () {
+ config.resetConfig();
+ const adUnitParams = BID_PARAMS.params;
+ expect(spec.transformBidParams(adUnitParams, null, null, [request(adUnitParams)])).to.equal(undefined);
+ });
+ })
});
diff --git a/test/spec/modules/richaudienceBidAdapter_spec.js b/test/spec/modules/richaudienceBidAdapter_spec.js
index ea45ff7e0b0..d2b173f53df 100644
--- a/test/spec/modules/richaudienceBidAdapter_spec.js
+++ b/test/spec/modules/richaudienceBidAdapter_spec.js
@@ -4,6 +4,8 @@ import {
spec
} from 'modules/richaudienceBidAdapter.js';
import {config} from 'src/config.js';
+import * as utils from 'src/utils.js';
+import sinon from 'sinon';
describe('Richaudience adapter tests', function () {
var DEFAULT_PARAMS_NEW_SIZES = [{
@@ -64,6 +66,30 @@ describe('Richaudience adapter tests', function () {
user: {}
}];
+ var DEFAULT_PARAMS_VIDEO_TIMEOUT = [{
+ adUnitCode: 'test-div',
+ bidId: '2c7c8e9c900244',
+ mediaTypes: {
+ video: {
+ context: 'instream',
+ playerSize: [640, 480],
+ mimes: ['video/mp4']
+ }
+ },
+ bidder: 'richaudience',
+ params: [{
+ bidfloor: 0.5,
+ pid: 'ADb1f40rmi',
+ supplyType: 'site'
+ }],
+ timeout: 3000,
+ auctionId: '0cb3144c-d084-4686-b0d6-f5dbe917c563',
+ bidRequestsCount: 1,
+ bidderRequestId: '1858b7382993ca',
+ transactionId: '29df2112-348b-4961-8863-1b33684d95e6',
+ user: {}
+ }]
+
var DEFAULT_PARAMS_VIDEO_IN = [{
adUnitCode: 'test-div',
bidId: '2c7c8e9c900244',
@@ -267,7 +293,7 @@ describe('Richaudience adapter tests', function () {
expect(requestContent.sizes[3]).to.have.property('w').and.to.equal(970);
expect(requestContent.sizes[3]).to.have.property('h').and.to.equal(250);
expect(requestContent).to.have.property('transactionId').and.to.equal('29df2112-348b-4961-8863-1b33684d95e6');
- expect(requestContent).to.have.property('timeout').and.to.equal(3000);
+ expect(requestContent).to.have.property('timeout').and.to.equal(600);
expect(requestContent).to.have.property('numIframes').and.to.equal(0);
expect(typeof requestContent.scr_rsl === 'string')
expect(typeof requestContent.cpuc === 'number')
@@ -879,7 +905,32 @@ describe('Richaudience adapter tests', function () {
expect(requestContent).to.have.property('gpid').and.to.equal('/19968336/header-bid-tag-1#example-2');
})
+ describe('onTimeout', function () {
+ beforeEach(function() {
+ sinon.stub(utils, 'triggerPixel');
+ });
+
+ afterEach(function() {
+ utils.triggerPixel.restore();
+ });
+ it('onTimeout exist as a function', () => {
+ expect(spec.onTimeout).to.exist.and.to.be.a('function');
+ });
+ it('should send timeouts', function () {
+ spec.onTimeout(DEFAULT_PARAMS_VIDEO_TIMEOUT);
+ expect(utils.triggerPixel.called).to.equal(true);
+ expect(utils.triggerPixel.firstCall.args[0]).to.equal('https://s.richaudience.com/err/?ec=6&ev=3000&pla=ADb1f40rmi&int=PREBID&pltfm=&node=&dm=localhost:9876');
+ });
+ });
+
describe('userSync', function () {
+ let sandbox;
+ beforeEach(function () {
+ sandbox = sinon.sandbox.create();
+ });
+ afterEach(function() {
+ sandbox.restore();
+ });
it('Verifies user syncs iframe include', function () {
config.setConfig({
'userSync': {filterSettings: {iframe: {bidders: '*', filter: 'include'}}}
@@ -1217,5 +1268,37 @@ describe('Richaudience adapter tests', function () {
}, [], {consentString: '', gdprApplies: true});
expect(syncs).to.have.lengthOf(0);
});
+
+ it('Verifies user syncs iframe/image include with GPP', function () {
+ config.setConfig({
+ 'userSync': {filterSettings: {iframe: {bidders: '*', filter: 'include'}}}
+ })
+
+ var syncs = spec.getUserSyncs({iframeEnabled: true}, [BID_RESPONSE], {
+ gppString: 'DBABL~BVVqAAEABgA.QA',
+ applicableSections: [7]},
+ );
+ expect(syncs).to.have.lengthOf(1);
+ expect(syncs[0].type).to.equal('iframe');
+
+ config.setConfig({
+ 'userSync': {filterSettings: {image: {bidders: '*', filter: 'include'}}}
+ })
+
+ var syncs = spec.getUserSyncs({pixelEnabled: true}, [BID_RESPONSE], {
+ gppString: 'DBABL~BVVqAAEABgA.QA',
+ applicableSections: [7, 5]},
+ );
+ expect(syncs).to.have.lengthOf(1);
+ expect(syncs[0].type).to.equal('image');
+ });
+
+ it('Verifies user syncs URL image include with GPP', function () {
+ const gppConsent = { gppString: 'DBACMYA~CP5P4cAP5P4cAPoABAESAlEAAAAAAAAAAAAAA2QAQA2ADZABADYAAAAA.QA2QAQA2AAAA.IA2QAQA2AAAA~BP5P4cAP5P4cAPoABABGBACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA', applicableSections: [0] };
+ const result = spec.getUserSyncs({pixelEnabled: true}, undefined, undefined, undefined, gppConsent);
+ expect(result).to.deep.equal([{
+ type: 'image', url: `https://sync.richaudience.com/bf7c142f4339da0278e83698a02b0854/?referrer=http%3A%2F%2Fdomain.com&gpp=DBACMYA~CP5P4cAP5P4cAPoABAESAlEAAAAAAAAAAAAAA2QAQA2ADZABADYAAAAA.QA2QAQA2AAAA.IA2QAQA2AAAA~BP5P4cAP5P4cAPoABABGBACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA&gpp_sid=0`
+ }]);
+ });
})
});
diff --git a/test/spec/modules/riseBidAdapter_spec.js b/test/spec/modules/riseBidAdapter_spec.js
index eed8d74f271..ec9309fd4ae 100644
--- a/test/spec/modules/riseBidAdapter_spec.js
+++ b/test/spec/modules/riseBidAdapter_spec.js
@@ -22,6 +22,12 @@ describe('riseAdapter', function () {
});
});
+ describe('bid adapter', function () {
+ it('should have aliases', function () {
+ expect(spec.aliases).to.be.an('array').that.is.not.empty;
+ });
+ });
+
describe('isBidRequestValid', function () {
const bid = {
'bidder': spec.code,
@@ -53,7 +59,7 @@ describe('riseAdapter', function () {
'adUnitCode': 'adunit-code',
'sizes': [[640, 480]],
'params': {
- 'org': 'jdye8weeyirk00000001'
+ 'org': 'jdye8weeyirk00000001',
},
'bidId': '299ffc8cca0b87',
'loop': 1,
@@ -195,6 +201,16 @@ describe('riseAdapter', function () {
expect(request.data.bids[1].mediaType).to.equal(BANNER)
});
+ it('should send the correct currency in bid request', function () {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.params = {
+ 'currency': 'EUR'
+ };
+ const expectedCurrency = bid.params.currency;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0].currency).to.equal(expectedCurrency);
+ });
+
it('should respect syncEnabled option', function() {
config.setConfig({
userSync: {
@@ -308,6 +324,24 @@ describe('riseAdapter', function () {
expect(request.data.params).to.have.property('gdpr_consent', 'test-consent-string');
});
+ it('should not send the gpp param if gppConsent is false in the bidRequest', function () {
+ const bidderRequestWithoutGPP = Object.assign({gppConsent: false}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithoutGPP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('gpp');
+ expect(request.data.params).to.not.have.property('gpp_sid');
+ });
+
+ it('should send the gpp param if gppConsent is true in the bidRequest', function () {
+ const bidderRequestWithGPP = Object.assign({gppConsent: {gppString: 'gpp-consent', applicableSections: [7]}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGPP);
+ console.log('request.data.params');
+ console.log(request.data.params);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('gpp', 'gpp-consent');
+ expect(request.data.params.gpp_sid[0]).to.be.equal(7);
+ });
+
it('should have schain param if it is available in the bidRequest', () => {
const schain = {
ver: '1.0',
diff --git a/test/spec/modules/rixengineBidAdapter_spec.js b/test/spec/modules/rixengineBidAdapter_spec.js
new file mode 100644
index 00000000000..a400b5c755b
--- /dev/null
+++ b/test/spec/modules/rixengineBidAdapter_spec.js
@@ -0,0 +1,141 @@
+import { spec } from 'modules/rixengineBidAdapter.js';
+const ENDPOINT = 'http://demo.svr.rixengine.com/rtb?sid=36540&token=1e05a767930d7d96ef6ce16318b4ab99';
+
+const REQUEST = [
+ {
+ adUnitCode: 'adUnitCode1',
+ bidId: 'bidId1',
+ auctionId: 'auctionId-56a2-4f71-9098-720a68f2f708',
+ mediaTypes: {
+ banner: {},
+ },
+ bidder: 'rixengine',
+ params: {
+ endpoint: 'http://demo.svr.rixengine.com/rtb',
+ token: '1e05a767930d7d96ef6ce16318b4ab99',
+ sid: '36540',
+ },
+ },
+];
+
+const RESPONSE = {
+ headers: null,
+ body: {
+ id: 'requestId',
+ bidid: 'bidId1',
+ cur: 'USD',
+ seatbid: [
+ {
+ bid: [
+ {
+ id: 'bidId1',
+ impid: 'bidId1',
+ adm: '',
+ cid: '24:17:18',
+ crid: '40_37_66:30_32_132:31_27_70',
+ adomain: ['www.rixengine.com'],
+ price: 10.00,
+ bundle:
+ 'com.xinggame.cast.video.screenmirroring.casttotv:https://www.greysa.com.tw/Product/detail/pid/119/?utm_source=popIn&utm_medium=cpc&utm_campaign=neck_202307_300*250:https://www.avaige.top/',
+ iurl: 'https://crs.rixbeedesk.com/test/kkd2ms/04c6d62912cff9037106fb50ed21b558.png:https://crs.rixbeedesk.com/test/kkd2ms/69a72b23c6c52e703c0c8e3f634e44eb.png:https://crs.rixbeedesk.com/test/kkd2ms/d229c5cd66bcc5856cb26bb2817718c9.png',
+ w: 300,
+ h: 250,
+ exp: 30,
+ },
+ ],
+ seat: 'Zh2Kiyk=',
+ },
+ ],
+ },
+};
+
+describe('rixengine bid adapter', function () {
+ describe('isBidRequestValid', function () {
+ let bid = {
+ bidder: 'rixengine',
+ params: {
+ endpoint: 'http://demo.svr.rixengine.com/rtb',
+ token: '1e05a767930d7d96ef6ce16318b4ab99',
+ sid: '36540',
+ },
+ };
+ it('should return true when required params found', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+ it('should return false when missing endpoint', function () {
+ delete bid.params.endpoint;
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+ it('should return false when missing sid', function () {
+ delete bid.params.sid;
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+ it('should return false when missing token', function () {
+ delete bid.params.token;
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+ });
+ describe('buildRequests', function () {
+ it('creates request data', function () {
+ const request = spec.buildRequests(REQUEST, {
+ refererInfo: {
+ page: 'page',
+ },
+ })[0];
+ expect(request).to.exist.and.to.be.a('object');
+ });
+ it('sends bid request to ENDPOINT via POST', function () {
+ const request = spec.buildRequests(REQUEST, {})[0];
+ expect(request.url).to.equal(ENDPOINT);
+ expect(request.method).to.equal('POST');
+ });
+ });
+
+ describe('interpretResponse', function () {
+ it('has bids', function () {
+ let request = spec.buildRequests(REQUEST, {})[0];
+ let bids = spec.interpretResponse(RESPONSE, request);
+ expect(bids).to.be.an('array').that.is.not.empty;
+ validateBidOnIndex(0);
+
+ function validateBidOnIndex(index) {
+ expect(bids[index]).to.have.property('currency', 'USD');
+ expect(bids[index]).to.have.property(
+ 'requestId',
+ RESPONSE.body.seatbid[0].bid[index].id
+ );
+ expect(bids[index]).to.have.property(
+ 'cpm',
+ RESPONSE.body.seatbid[0].bid[index].price
+ );
+ expect(bids[index]).to.have.property(
+ 'width',
+ RESPONSE.body.seatbid[0].bid[index].w
+ );
+ expect(bids[index]).to.have.property(
+ 'height',
+ RESPONSE.body.seatbid[0].bid[index].h
+ );
+ expect(bids[index]).to.have.property(
+ 'ad',
+ RESPONSE.body.seatbid[0].bid[index].adm
+ );
+ expect(bids[index]).to.have.property(
+ 'creativeId',
+ RESPONSE.body.seatbid[0].bid[index].crid
+ );
+ expect(bids[index]).to.have.property('ttl', 30);
+ expect(bids[index]).to.have.property('netRevenue', true);
+ }
+ });
+
+ it('handles empty response', function () {
+ it('No bid response', function() {
+ var noBidResponse = spec.interpretResponse({
+ body: '',
+ });
+ expect(noBidResponse.length).to.equal(0);
+ });
+ });
+ });
+});
diff --git a/test/spec/modules/rtbhouseBidAdapter_spec.js b/test/spec/modules/rtbhouseBidAdapter_spec.js
index 0b944dcb077..77b746b9b69 100644
--- a/test/spec/modules/rtbhouseBidAdapter_spec.js
+++ b/test/spec/modules/rtbhouseBidAdapter_spec.js
@@ -2,6 +2,7 @@ import { expect } from 'chai';
import { OPENRTB, spec } from 'modules/rtbhouseBidAdapter.js';
import { newBidder } from 'src/adapters/bidderFactory.js';
import { config } from 'src/config.js';
+import { mergeDeep } from '../../../src/utils';
describe('RTBHouseAdapter', () => {
const adapter = newBidder(spec);
@@ -304,6 +305,152 @@ describe('RTBHouseAdapter', () => {
expect(data.user).to.nested.include({'ext.data': 'some user data'});
});
+ context('DSA', () => {
+ const validDSAObject = {
+ 'dsarequired': 3,
+ 'pubrender': 0,
+ 'datatopub': 2,
+ 'transparency': [
+ {
+ 'domain': 'platform1domain.com',
+ 'dsaparams': [1]
+ },
+ {
+ 'domain': 'SSP2domain.com',
+ 'dsaparams': [1, 2]
+ }
+ ]
+ };
+ const invalidDSAObjects = [
+ -1,
+ 0,
+ '',
+ 'x',
+ true,
+ [],
+ [1],
+ {},
+ {
+ 'dsarequired': -1
+ },
+ {
+ 'pubrender': -1
+ },
+ {
+ 'datatopub': -1
+ },
+ {
+ 'dsarequired': 4
+ },
+ {
+ 'pubrender': 3
+ },
+ {
+ 'datatopub': 3
+ },
+ {
+ 'dsarequired': '1'
+ },
+ {
+ 'pubrender': '1'
+ },
+ {
+ 'datatopub': '1'
+ },
+ {
+ 'transparency': '1'
+ },
+ {
+ 'transparency': 2
+ },
+ {
+ 'transparency': [
+ 1, 2
+ ]
+ },
+ {
+ 'transparency': [
+ {
+ domain: '',
+ dsaparams: []
+ }
+ ]
+ },
+ {
+ 'transparency': [
+ {
+ domain: 'x',
+ dsaparams: null
+ }
+ ]
+ },
+ {
+ 'transparency': [
+ {
+ domain: 'x',
+ dsaparams: [1, '2']
+ }
+ ]
+ },
+ ];
+ let bidRequest;
+
+ beforeEach(() => {
+ bidRequest = Object.assign([], bidRequests);
+ });
+
+ it('should add dsa information to the request via bidderRequest.ortb2.regs.ext.dsa', function () {
+ const localBidderRequest = {
+ ...bidderRequest,
+ ortb2: {
+ regs: {
+ ext: {
+ dsa: validDSAObject
+ }
+ }
+ }
+ };
+
+ const request = spec.buildRequests(bidRequest, localBidderRequest);
+ const data = JSON.parse(request.data);
+
+ expect(data).to.have.nested.property('regs.ext.dsa');
+ expect(data.regs.ext.dsa.dsarequired).to.equal(3);
+ expect(data.regs.ext.dsa.pubrender).to.equal(0);
+ expect(data.regs.ext.dsa.datatopub).to.equal(2);
+ expect(data.regs.ext.dsa.transparency).to.deep.equal([
+ {
+ 'domain': 'platform1domain.com',
+ 'dsaparams': [1]
+ },
+ {
+ 'domain': 'SSP2domain.com',
+ 'dsaparams': [1, 2]
+ }
+ ]);
+ });
+
+ invalidDSAObjects.forEach((invalidDSA, index) => {
+ it(`should not add dsa information to the request via bidderRequest.ortb2.regs.ext.dsa; test# ${index}`, function () {
+ const localBidderRequest = {
+ ...bidderRequest,
+ ortb2: {
+ regs: {
+ ext: {
+ dsa: invalidDSA
+ }
+ }
+ }
+ };
+
+ const request = spec.buildRequests(bidRequest, localBidderRequest);
+ const data = JSON.parse(request.data);
+
+ expect(data).to.not.have.nested.property('regs.ext.dsa');
+ });
+ });
+ });
+
context('FLEDGE', function() {
afterEach(function () {
config.resetConfig();
@@ -563,17 +710,20 @@ describe('RTBHouseAdapter', () => {
});
describe('interpretResponse', function () {
- let response = [{
- 'id': 'bidder_imp_identifier',
- 'impid': '552b8922e28f27',
- 'price': 0.5,
- 'adid': 'Ad_Identifier',
- 'adm': '',
- 'adomain': ['rtbhouse.com'],
- 'cid': 'Ad_Identifier',
- 'w': 300,
- 'h': 250
- }];
+ let response;
+ beforeEach(() => {
+ response = [{
+ 'id': 'bidder_imp_identifier',
+ 'impid': '552b8922e28f27',
+ 'price': 0.5,
+ 'adid': 'Ad_Identifier',
+ 'adm': '',
+ 'adomain': ['rtbhouse.com'],
+ 'cid': 'Ad_Identifier',
+ 'w': 300,
+ 'h': 250
+ }];
+ });
let fledgeResponse = {
'id': 'bid-identifier',
@@ -638,6 +788,51 @@ describe('RTBHouseAdapter', () => {
});
});
+ context('when the response contains DSA object', function () {
+ it('should get correct bid response', function () {
+ const dsa = {
+ 'dsa': {
+ 'behalf': 'Advertiser',
+ 'paid': 'Advertiser',
+ 'transparency': [{
+ 'domain': 'dsp1domain.com',
+ 'dsaparams': [1, 2]
+ }],
+ 'adrender': 1
+ }
+ };
+ mergeDeep(response[0], { ext: dsa });
+
+ const expectedResponse = [
+ {
+ 'requestId': '552b8922e28f27',
+ 'cpm': 0.5,
+ 'creativeId': 29681110,
+ 'width': 300,
+ 'height': 250,
+ 'ad': '',
+ 'mediaType': 'banner',
+ 'currency': 'USD',
+ 'ttl': 300,
+ 'meta': {
+ 'advertiserDomains': ['rtbhouse.com'],
+ ...dsa
+ },
+ 'netRevenue': true,
+ ext: { ...dsa }
+ }
+ ];
+ let bidderRequest;
+ let result = spec.interpretResponse({body: response}, {bidderRequest});
+
+ expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0]));
+ expect(result[0]).to.have.nested.property('meta.dsa');
+ expect(result[0]).to.have.nested.property('ext.dsa');
+ expect(result[0].meta.dsa).to.deep.equal(expectedResponse[0].meta.dsa);
+ expect(result[0].ext.dsa).to.deep.equal(expectedResponse[0].meta.dsa);
+ });
+ });
+
describe('native', () => {
const adm = {
native: {
diff --git a/test/spec/modules/rubiconBidAdapter_spec.js b/test/spec/modules/rubiconBidAdapter_spec.js
index dd6f52c0646..55e8909f6c8 100644
--- a/test/spec/modules/rubiconBidAdapter_spec.js
+++ b/test/spec/modules/rubiconBidAdapter_spec.js
@@ -21,6 +21,7 @@ import 'modules/priceFloors.js';
import 'modules/multibid/index.js';
import adapterManager from 'src/adapterManager.js';
import {syncAddFPDToBidderRequest} from '../../helpers/fpd.js';
+import { deepClone } from '../../../src/utils.js';
const INTEGRATION = `pbjs_lite_v$prebid.version$`; // $prebid.version$ will be substituted in by gulp in built prebid
const PBS_INTEGRATION = 'pbjs';
@@ -33,6 +34,7 @@ describe('the rubicon adapter', function () {
logErrorSpy;
/**
+ * @typedef {import('../../../src/adapters/bidderFactory.js').BidRequest} BidRequest
* @typedef {Object} sizeMapConverted
* @property {string} sizeId
* @property {string} size
@@ -696,6 +698,16 @@ describe('the rubicon adapter', function () {
expect(data['p_pos']).to.equal('atf;;btf;;');
});
+ it('should correctly send cdep signal when requested', () => {
+ var badposRequest = utils.deepClone(bidderRequest);
+ badposRequest.bids[0].ortb2 = {device: {ext: {cdep: 3}}};
+
+ let [request] = spec.buildRequests(badposRequest.bids, badposRequest);
+ let data = parseQuery(request.data);
+
+ expect(data['o_cdep']).to.equal('3');
+ });
+
it('ad engine query params should be ordered correctly', function () {
sandbox.stub(Math, 'random').callsFake(() => 0.1);
let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest);
@@ -1701,6 +1713,57 @@ describe('the rubicon adapter', function () {
expect(data['p_gpid']).to.equal('/1233/sports&div1');
});
+ describe('Pass DSA signals', function() {
+ const ortb2 = {
+ regs: {
+ ext: {
+ dsa: {
+ dsarequired: 3,
+ pubrender: 0,
+ datatopub: 2,
+ transparency: [
+ {
+ domain: 'testdomain.com',
+ dsaparams: [1],
+ },
+ {
+ domain: 'testdomain2.com',
+ dsaparams: [1, 2]
+ }
+ ]
+ }
+ }
+ }
+ }
+ it('should send dsa signals if \"ortb2.regs.ext.dsa\"', function() {
+ const expectedTransparency = 'testdomain.com~1~~testdomain2.com~1_2'
+ const [request] = spec.buildRequests(bidderRequest.bids.map((b) => ({...b, ortb2})), bidderRequest)
+ const data = parseQuery(request.data);
+
+ expect(data).to.be.an('Object');
+ expect(data).to.have.property('dsarequired');
+ expect(data).to.have.property('dsapubrender');
+ expect(data).to.have.property('dsadatatopubs');
+ expect(data).to.have.property('dsatransparency');
+
+ expect(data['dsarequired']).to.equal(ortb2.regs.ext.dsa.dsarequired.toString());
+ expect(data['dsapubrender']).to.equal(ortb2.regs.ext.dsa.pubrender.toString());
+ expect(data['dsadatatopubs']).to.equal(ortb2.regs.ext.dsa.datatopub.toString());
+ expect(data['dsatransparency']).to.equal(expectedTransparency)
+ })
+ it('should return one transparency param', function() {
+ const expectedTransparency = 'testdomain.com~1';
+ const ortb2Clone = deepClone(ortb2);
+ ortb2Clone.regs.ext.dsa.transparency.pop()
+ const [request] = spec.buildRequests(bidderRequest.bids.map((b) => ({...b, ortb2: ortb2Clone})), bidderRequest)
+ const data = parseQuery(request.data);
+
+ expect(data).to.be.an('Object');
+ expect(data).to.have.property('dsatransparency');
+ expect(data['dsatransparency']).to.equal(expectedTransparency);
+ })
+ })
+
it('should send gpid and pbadslot since it is prefered over dfp code', function () {
bidderRequest.bids[0].ortb2Imp = {
ext: {
@@ -1808,6 +1871,126 @@ describe('the rubicon adapter', function () {
expect(data['tg_i.dfp_ad_unit_code']).to.equal('/a/b/c');
});
});
+
+ describe('client hints', function () {
+ let standardSuaObject;
+ beforeEach(function () {
+ standardSuaObject = {
+ source: 2,
+ platform: {
+ brand: 'macOS',
+ version: [
+ '12',
+ '6',
+ '0'
+ ]
+ },
+ browsers: [
+ {
+ brand: 'Not.A/Brand',
+ version: [
+ '8',
+ '0',
+ '0',
+ '0'
+ ]
+ },
+ {
+ brand: 'Chromium',
+ version: [
+ '114',
+ '0',
+ '5735',
+ '198'
+ ]
+ },
+ {
+ brand: 'Google Chrome',
+ version: [
+ '114',
+ '0',
+ '5735',
+ '198'
+ ]
+ }
+ ],
+ mobile: 0,
+ model: '',
+ bitness: '64',
+ architecture: 'x86'
+ }
+ });
+ it('should send m_ch_* params if ortb2.device.sua object is there', function () {
+ let bidRequestSua = utils.deepClone(bidderRequest);
+ bidRequestSua.bids[0].ortb2 = { device: { sua: standardSuaObject } };
+
+ // How should fastlane query be constructed with default SUA
+ let expectedValues = {
+ m_ch_arch: 'x86',
+ m_ch_bitness: '64',
+ m_ch_ua: `"Not.A/Brand"|v="8","Chromium"|v="114","Google Chrome"|v="114"`,
+ m_ch_full_ver: `"Not.A/Brand"|v="8.0.0.0","Chromium"|v="114.0.5735.198","Google Chrome"|v="114.0.5735.198"`,
+ m_ch_mobile: '?0',
+ m_ch_platform: 'macOS',
+ m_ch_platform_ver: '12.6.0'
+ }
+
+ // Build Fastlane call
+ let [request] = spec.buildRequests(bidRequestSua.bids, bidRequestSua);
+ let data = parseQuery(request.data);
+
+ // Loop through expected values and if they do not match push an error
+ const errors = Object.entries(expectedValues).reduce((accum, [key, val]) => {
+ if (data[key] !== val) accum.push(`${key} - expect: ${val} - got: ${data[key]}`)
+ return accum;
+ }, []);
+
+ // should be no errors
+ expect(errors).to.deep.equal([]);
+ });
+ it('should not send invalid values for m_ch_*', function () {
+ let bidRequestSua = utils.deepClone(bidderRequest);
+
+ // Alter input SUA object
+ // send model
+ standardSuaObject.model = 'Suface Duo';
+ // send mobile = 1
+ standardSuaObject.mobile = 1;
+
+ // make browsers not an array
+ standardSuaObject.browsers = 'My Browser';
+
+ // make platform not have version
+ delete standardSuaObject.platform.version;
+
+ // delete architecture
+ delete standardSuaObject.architecture;
+
+ // add SUA to bid
+ bidRequestSua.bids[0].ortb2 = { device: { sua: standardSuaObject } };
+
+ // Build Fastlane request
+ let [request] = spec.buildRequests(bidRequestSua.bids, bidRequestSua);
+ let data = parseQuery(request.data);
+
+ // should show new names
+ expect(data.m_ch_model).to.equal('Suface Duo');
+ expect(data.m_ch_mobile).to.equal('?1');
+
+ // should still send platform
+ expect(data.m_ch_platform).to.equal('macOS');
+
+ // platform version not sent
+ expect(data).to.not.haveOwnProperty('m_ch_platform_ver');
+
+ // both ua and full_ver not sent because browsers not array
+ expect(data).to.not.haveOwnProperty('m_ch_ua');
+ expect(data).to.not.haveOwnProperty('m_ch_full_ver');
+
+ // arch not sent
+ expect(data).to.not.haveOwnProperty('m_ch_arch');
+ });
+ });
});
if (FEATURES.VIDEO) {
@@ -2085,17 +2268,6 @@ describe('the rubicon adapter', function () {
expect(payload.ext.prebid.analytics).to.be.undefined;
});
- it('should send video exp param correctly when set', function () {
- const bidderRequest = createVideoBidderRequest();
- config.setConfig({s2sConfig: {defaultTtl: 600}});
- let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest);
- let post = request.data;
-
- // should exp set to the right value according to config
- let imp = post.imp[0];
- expect(imp.exp).to.equal(600);
- });
-
it('should not send video exp at all if not set in s2sConfig config', function () {
const bidderRequest = createVideoBidderRequest();
let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest);
@@ -2251,16 +2423,6 @@ describe('the rubicon adapter', function () {
bidderRequest = createVideoBidderRequest();
delete bidderRequest.bids[0].mediaTypes.video.linearity;
expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.equal(false);
-
- // change api to an string, no good
- bidderRequest = createVideoBidderRequest();
- bidderRequest.bids[0].mediaTypes.video.api = 'string';
- expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.equal(false);
-
- // delete api, no good
- bidderRequest = createVideoBidderRequest();
- delete bidderRequest.bids[0].mediaTypes.video.api;
- expect(spec.isBidRequestValid(bidderRequest.bids[0])).to.equal(false);
});
it('bid request is valid when video context is outstream', function () {
@@ -2589,6 +2751,65 @@ describe('the rubicon adapter', function () {
const slotParams = spec.createSlotParams(bidderRequest.bids[0], bidderRequest);
expect(slotParams.kw).to.equal('a,b,c');
});
+
+ it('should pass along o_ae param when fledge is enabled', () => {
+ const localBidRequest = Object.assign({}, bidderRequest.bids[0]);
+ localBidRequest.ortb2Imp.ext.ae = true;
+
+ const slotParams = spec.createSlotParams(localBidRequest, bidderRequest);
+
+ expect(slotParams['o_ae']).to.equal(1)
+ });
+
+ it('should pass along desired segtaxes, but not non-desired ones', () => {
+ const localBidderRequest = Object.assign({}, bidderRequest);
+ localBidderRequest.refererInfo = {domain: 'bob'};
+ config.setConfig({
+ rubicon: {
+ sendUserSegtax: [9],
+ sendSiteSegtax: [10]
+ }
+ });
+ localBidderRequest.ortb2.user = {
+ data: [{
+ ext: {
+ segtax: '404'
+ },
+ segment: [{id: 5}, {id: 6}]
+ }, {
+ ext: {
+ segtax: '508'
+ },
+ segment: [{id: 5}, {id: 2}]
+ }, {
+ ext: {
+ segtax: '9'
+ },
+ segment: [{id: 1}, {id: 2}]
+ }]
+ }
+ localBidderRequest.ortb2.site = {
+ content: {
+ data: [{
+ ext: {
+ segtax: '10'
+ },
+ segment: [{id: 2}, {id: 3}]
+ }, {
+ ext: {
+ segtax: '507'
+ },
+ segment: [{id: 3}, {id: 4}]
+ }]
+ }
+ }
+ const slotParams = spec.createSlotParams(bidderRequest.bids[0], localBidderRequest);
+ expect(slotParams['tg_i.tax507']).is.equal('3,4');
+ expect(slotParams['tg_v.tax508']).is.equal('5,2');
+ expect(slotParams['tg_v.tax9']).is.equal('1,2');
+ expect(slotParams['tg_i.tax10']).is.equal('2,3');
+ expect(slotParams['tg_v.tax404']).is.equal(undefined);
+ });
});
describe('classifiedAsVideo', function () {
@@ -2855,7 +3076,7 @@ describe('the rubicon adapter', function () {
expect(bids[0].width).to.equal(320);
expect(bids[0].height).to.equal(50);
expect(bids[0].cpm).to.equal(0.911);
- expect(bids[0].ttl).to.equal(300);
+ expect(bids[0].ttl).to.equal(360);
expect(bids[0].netRevenue).to.equal(true);
expect(bids[0].rubicon.advertiserId).to.equal(7);
expect(bids[0].rubicon.networkId).to.equal(8);
@@ -2872,7 +3093,7 @@ describe('the rubicon adapter', function () {
expect(bids[1].width).to.equal(300);
expect(bids[1].height).to.equal(250);
expect(bids[1].cpm).to.equal(0.811);
- expect(bids[1].ttl).to.equal(300);
+ expect(bids[1].ttl).to.equal(360);
expect(bids[1].netRevenue).to.equal(true);
expect(bids[1].rubicon.advertiserId).to.equal(7);
expect(bids[1].rubicon.networkId).to.equal(8);
@@ -3147,6 +3368,86 @@ describe('the rubicon adapter', function () {
expect(bids[0].cpm).to.be.equal(0);
});
+ it('should handle DSA object from response', function() {
+ let response = {
+ 'status': 'ok',
+ 'account_id': 14062,
+ 'site_id': 70608,
+ 'zone_id': 530022,
+ 'size_id': 15,
+ 'alt_size_ids': [
+ 43
+ ],
+ 'tracking': '',
+ 'inventory': {},
+ 'ads': [
+ {
+ 'status': 'ok',
+ 'impression_id': '153dc240-8229-4604-b8f5-256933b9374c',
+ 'size_id': '15',
+ 'ad_id': '6',
+ 'adomain': ['test.com'],
+ 'advertiser': 7,
+ 'network': 8,
+ 'creative_id': 'crid-9',
+ 'type': 'script',
+ 'script': 'alert(\'foo\')',
+ 'campaign_id': 10,
+ 'cpm': 0.811,
+ 'targeting': [
+ {
+ 'key': 'rpfl_14062',
+ 'values': [
+ '15_tier_all_test'
+ ]
+ }
+ ],
+ 'dsa': {
+ 'behalf': 'Advertiser',
+ 'paid': 'Advertiser',
+ 'transparency': [{
+ 'domain': 'dsp1domain.com',
+ 'dsaparams': [1, 2]
+ }],
+ 'adrender': 1
+ }
+ },
+ {
+ 'status': 'ok',
+ 'impression_id': '153dc240-8229-4604-b8f5-256933b9374d',
+ 'size_id': '43',
+ 'ad_id': '7',
+ 'adomain': ['test.com'],
+ 'advertiser': 7,
+ 'network': 8,
+ 'creative_id': 'crid-9',
+ 'type': 'script',
+ 'script': 'alert(\'foo\')',
+ 'campaign_id': 10,
+ 'cpm': 0.911,
+ 'targeting': [
+ {
+ 'key': 'rpfl_14062',
+ 'values': [
+ '43_tier_all_test'
+ ]
+ }
+ ],
+ 'dsa': {}
+ }
+ ]
+ };
+ let bids = spec.interpretResponse({body: response}, {
+ bidRequest: bidderRequest.bids[0]
+ });
+ expect(bids).to.be.lengthOf(2);
+ expect(bids[1].meta.dsa).to.have.property('behalf');
+ expect(bids[1].meta.dsa).to.have.property('paid');
+
+ // if we dont have dsa field in response or the dsa object is empty
+ expect(bids[0].meta).to.not.have.property('dsa');
+ })
+
it('should create bids with matching requestIds if imp id matches', function () {
let bidRequests = [{
'bidder': 'rubicon',
@@ -3309,6 +3610,43 @@ describe('the rubicon adapter', function () {
expect(bids).to.be.lengthOf(0);
});
+ it('Should support recieving an auctionConfig and pass it along to Prebid', function () {
+ let response = {
+ 'status': 'ok',
+ 'account_id': 14062,
+ 'site_id': 70608,
+ 'zone_id': 530022,
+ 'size_id': 15,
+ 'alt_size_ids': [
+ 43
+ ],
+ 'tracking': '',
+ 'inventory': {},
+ 'ads': [{
+ 'status': 'ok',
+ 'cpm': 0,
+ 'size_id': 15
+ }],
+ 'component_auction_config': [{
+ 'random': 'value',
+ 'bidId': '5432'
+ },
+ {
+ 'random': 'string',
+ 'bidId': '6789'
+ }]
+ };
+
+ let {bids, fledgeAuctionConfigs} = spec.interpretResponse({body: response}, {
+ bidRequest: bidderRequest.bids[0]
+ });
+
+ expect(bids).to.be.lengthOf(1);
+ expect(fledgeAuctionConfigs[0].bidId).to.equal('5432');
+ expect(fledgeAuctionConfigs[0].config.random).to.equal('value');
+ expect(fledgeAuctionConfigs[1].bidId).to.equal('6789');
+ });
+
it('should handle an error', function () {
let response = {
'status': 'ok',
@@ -3567,7 +3905,7 @@ describe('the rubicon adapter', function () {
expect(bids[0].seatBidId).to.equal('0');
expect(bids[0].creativeId).to.equal('4259970');
expect(bids[0].cpm).to.equal(2);
- expect(bids[0].ttl).to.equal(300);
+ expect(bids[0].ttl).to.equal(360);
expect(bids[0].netRevenue).to.equal(true);
expect(bids[0].adserverTargeting).to.deep.equal({hb_uuid: '0c498f63-5111-4bed-98e2-9be7cb932a64'});
expect(bids[0].mediaType).to.equal('video');
@@ -3601,7 +3939,8 @@ describe('the rubicon adapter', function () {
config.setConfig({rubicon: {
rendererConfig: {
align: 'left',
- closeButton: true
+ closeButton: true,
+ collapse: false
},
rendererUrl: 'https://example.test/renderer.js'
}});
@@ -3658,7 +3997,7 @@ describe('the rubicon adapter', function () {
expect(bids[0].seatBidId).to.equal('0');
expect(bids[0].creativeId).to.equal('4259970');
expect(bids[0].cpm).to.equal(2);
- expect(bids[0].ttl).to.equal(300);
+ expect(bids[0].ttl).to.equal(360);
expect(bids[0].netRevenue).to.equal(true);
expect(bids[0].adserverTargeting).to.deep.equal({hb_uuid: '0c498f63-5111-4bed-98e2-9be7cb932a64'});
expect(bids[0].mediaType).to.equal('video');
@@ -3673,7 +4012,8 @@ describe('the rubicon adapter', function () {
expect(typeof bids[0].renderer).to.equal('object');
expect(bids[0].renderer.getConfig()).to.deep.equal({
align: 'left',
- closeButton: true
+ closeButton: true,
+ collapse: false
});
expect(bids[0].renderer.url).to.equal('https://example.test/renderer.js');
});
@@ -3727,7 +4067,7 @@ describe('the rubicon adapter', function () {
const renderCall = window.MagniteApex.renderAd.getCall(0);
expect(renderCall.args[0]).to.deep.equal({
closeButton: true,
- collapse: true,
+ collapse: false,
height: 320,
label: undefined,
placement: {
@@ -3796,7 +4136,7 @@ describe('the rubicon adapter', function () {
const renderCall = window.MagniteApex.renderAd.getCall(0);
expect(renderCall.args[0]).to.deep.equal({
closeButton: true,
- collapse: true,
+ collapse: false,
height: 480,
label: undefined,
placement: {
diff --git a/test/spec/modules/seedtagBidAdapter_spec.js b/test/spec/modules/seedtagBidAdapter_spec.js
index fb666e89f73..516c5ec933a 100644
--- a/test/spec/modules/seedtagBidAdapter_spec.js
+++ b/test/spec/modules/seedtagBidAdapter_spec.js
@@ -2,10 +2,24 @@ import { expect } from 'chai';
import { spec, getTimeoutUrl } from 'modules/seedtagBidAdapter.js';
import * as utils from 'src/utils.js';
import { config } from '../../../src/config.js';
+import * as mockGpt from 'test/spec/integration/faker/googletag.js';
const PUBLISHER_ID = '0000-0000-01';
const ADUNIT_ID = '000000';
+const adUnitCode = '/19968336/header-bid-tag-0'
+
+// create a default adunit
+const slot = document.createElement('div');
+slot.id = adUnitCode;
+slot.style.width = '300px'
+slot.style.height = '250px'
+slot.style.position = 'absolute'
+slot.style.top = '10px'
+slot.style.left = '20px'
+
+document.body.appendChild(slot);
+
function getSlotConfigs(mediaTypes, params) {
return {
params: params,
@@ -25,7 +39,7 @@ function getSlotConfigs(mediaTypes, params) {
tid: 'd704d006-0d6e-4a09-ad6c-179e7e758096',
}
},
- adUnitCode: 'adunit-code',
+ adUnitCode: adUnitCode,
};
}
@@ -46,6 +60,13 @@ const createBannerSlotConfig = (placement, mediatypes) => {
};
describe('Seedtag Adapter', function () {
+ beforeEach(function () {
+ mockGpt.reset();
+ });
+
+ afterEach(function () {
+ mockGpt.enable();
+ });
describe('isBidRequestValid method', function () {
describe('returns true', function () {
describe('when banner slot config has all mandatory params', () => {
@@ -277,7 +298,7 @@ describe('Seedtag Adapter', function () {
expect(data.auctionStart).to.be.greaterThanOrEqual(now);
expect(data.ttfb).to.be.greaterThanOrEqual(0);
- expect(data.bidRequests[0].adUnitCode).to.equal('adunit-code');
+ expect(data.bidRequests[0].adUnitCode).to.equal(adUnitCode);
});
describe('GDPR params', function () {
@@ -374,6 +395,35 @@ describe('Seedtag Adapter', function () {
expect(videoBid.sizes[1][1]).to.equal(600);
expect(videoBid.requestCount).to.equal(1);
});
+
+ it('should have geom parameters if slot is available', function() {
+ const request = spec.buildRequests(validBidRequests, bidderRequest);
+ const data = JSON.parse(request.data);
+ const bidRequests = data.bidRequests;
+ const bannerBid = bidRequests[0];
+
+ // on some CI, the DOM is not initialized, so we need to check if the slot is available
+ const slot = document.getElementById(adUnitCode)
+ if (slot) {
+ expect(bannerBid).to.have.property('geom')
+
+ const params = [['width', 300], ['height', 250], ['top', 10], ['left', 20], ['scrollY', 0]]
+ params.forEach(([param, value]) => {
+ expect(bannerBid.geom).to.have.property(param)
+ expect(bannerBid.geom[param]).to.be.a('number')
+ expect(bannerBid.geom[param]).to.be.equal(value)
+ })
+
+ expect(bannerBid.geom).to.have.property('viewport')
+ const viewportParams = ['width', 'height']
+ viewportParams.forEach(param => {
+ expect(bannerBid.geom.viewport).to.have.property(param)
+ expect(bannerBid.geom.viewport[param]).to.be.a('number')
+ })
+ } else {
+ expect(bannerBid).to.not.have.property('geom')
+ }
+ })
});
describe('COPPA param', function () {
diff --git a/test/spec/modules/setupadBidAdapter_spec.js b/test/spec/modules/setupadBidAdapter_spec.js
new file mode 100644
index 00000000000..d4ff73d005f
--- /dev/null
+++ b/test/spec/modules/setupadBidAdapter_spec.js
@@ -0,0 +1,348 @@
+import { spec } from 'modules/setupadBidAdapter.js';
+
+describe('SetupadAdapter', function () {
+ const userIdAsEids = [
+ {
+ source: 'pubcid.org',
+ uids: [
+ {
+ atype: 1,
+ id: '01EAJWWNEPN3CYMM5N8M5VXY22',
+ },
+ ],
+ },
+ ];
+
+ const bidRequests = [
+ {
+ adUnitCode: 'test-div',
+ auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917',
+ bidId: '22c4871113f461',
+ bidder: 'rubicon',
+ bidderRequestId: '15246a574e859f',
+ uspConsent: 'usp-context-string',
+ gdprConsent: {
+ consentString: 'BOtmiBKOtmiBKABABAENAFAAAAACeAAA',
+ gdprApplies: true,
+ },
+ params: {
+ placement_id: '123',
+ account_id: 'test-account-id',
+ },
+ sizes: [[300, 250]],
+ ortb2: {
+ device: {
+ w: 1500,
+ h: 1000,
+ },
+ site: {
+ domain: 'test.com',
+ page: 'http://test.com',
+ },
+ },
+ userIdAsEids,
+ },
+ ];
+
+ const bidderRequest = {
+ ortb2: {
+ device: {
+ w: 1500,
+ h: 1000,
+ },
+ },
+ refererInfo: {
+ domain: 'test.com',
+ page: 'http://test.com',
+ ref: '',
+ },
+ };
+
+ const serverResponse = {
+ body: {
+ id: 'f7b3d2da-e762-410c-b069-424f92c4c4b2',
+ seatbid: [
+ {
+ bid: [
+ {
+ id: 'test-bid-id',
+ price: 0.8,
+ adm: 'this is an ad',
+ adid: 'test-ad-id',
+ adomain: ['test.addomain.com'],
+ w: 300,
+ h: 250,
+ },
+ ],
+ seat: 'testBidder',
+ },
+ ],
+ cur: 'USD',
+ ext: {
+ sync: {
+ image: ['urlA?gdpr={{.GDPR}}'],
+ iframe: ['urlB'],
+ },
+ },
+ },
+ };
+
+ describe('isBidRequestValid', function () {
+ const bid = {
+ bidder: 'setupad',
+ params: {
+ placement_id: '123',
+ },
+ };
+ it('should return true when required params found', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+ it('should return false when required params are not passed', function () {
+ delete bid.params.placement_id;
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', function () {
+ it('check request params with GDPR and USP', function () {
+ const request = spec.buildRequests(bidRequests, bidRequests[0]);
+ expect(JSON.parse(request[0].data).user.ext.consent).to.equal(
+ 'BOtmiBKOtmiBKABABAENAFAAAAACeAAA'
+ );
+ expect(JSON.parse(request[0].data).regs.ext.gdpr).to.equal(1);
+ expect(JSON.parse(request[0].data).regs.ext.us_privacy).to.equal('usp-context-string');
+ });
+
+ it('check request params without GDPR', function () {
+ let bidRequestsWithoutGDPR = Object.assign({}, bidRequests[0]);
+ delete bidRequestsWithoutGDPR.gdprConsent;
+ const request = spec.buildRequests([bidRequestsWithoutGDPR], bidRequestsWithoutGDPR);
+ expect(JSON.parse(request[0].data).regs.ext.gdpr).to.be.undefined;
+ expect(JSON.parse(request[0].data).regs.ext.us_privacy).to.equal('usp-context-string');
+ });
+
+ it('should return correct storedrequest id if account_id is provided', function () {
+ const request = spec.buildRequests(bidRequests, bidRequests[0]);
+ expect(JSON.parse(request[0].data).ext.prebid.storedrequest.id).to.equal('test-account-id');
+ });
+
+ it('should return correct storedrequest id if account_id is not provided', function () {
+ let bidRequestsWithoutAccountId = Object.assign({}, bidRequests[0]);
+ delete bidRequestsWithoutAccountId.params.account_id;
+ const request = spec.buildRequests(
+ [bidRequestsWithoutAccountId],
+ bidRequestsWithoutAccountId
+ );
+ expect(JSON.parse(request[0].data).ext.prebid.storedrequest.id).to.equal('default');
+ });
+
+ it('validate generated params', function () {
+ const request = spec.buildRequests(bidRequests);
+ expect(request[0].bidId).to.equal('22c4871113f461');
+ expect(JSON.parse(request[0].data).id).to.equal('15246a574e859f');
+ });
+
+ it('check if correct site object was added', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ const siteObj = JSON.parse(request[0].data).site;
+
+ expect(siteObj.domain).to.equal('test.com');
+ expect(siteObj.page).to.equal('http://test.com');
+ expect(siteObj.ref).to.equal('');
+ });
+
+ it('check if correct device object was added', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ const deviceObj = JSON.parse(request[0].data).device;
+
+ expect(deviceObj.w).to.equal(1500);
+ expect(deviceObj.h).to.equal(1000);
+ });
+
+ it('check if imp object was added', function () {
+ const request = spec.buildRequests(bidRequests);
+ expect(JSON.parse(request[0].data).imp).to.be.an('array');
+ });
+
+ it('should send "user.ext.eids" in the request for Prebid.js supported modules only', function () {
+ const request = spec.buildRequests(bidRequests);
+ expect(JSON.parse(request[0].data).user.ext.eids).to.deep.equal(userIdAsEids);
+ });
+
+ it('should send an undefined "user.ext.eids" in the request if userId module is unsupported', function () {
+ let bidRequestsUnsupportedUserIdModule = Object.assign({}, bidRequests[0]);
+ delete bidRequestsUnsupportedUserIdModule.userIdAsEids;
+ const request = spec.buildRequests(bidRequestsUnsupportedUserIdModule);
+
+ expect(JSON.parse(request[0].data).user.ext.eids).to.be.undefined;
+ });
+ });
+
+ describe('getUserSyncs', () => {
+ it('should return user sync', () => {
+ const syncOptions = {
+ iframeEnabled: true,
+ pixelEnabled: true,
+ };
+ const responses = [
+ {
+ body: {
+ ext: {
+ responsetimemillis: {
+ 'test seat 1': 2,
+ 'test seat 2': 1,
+ },
+ },
+ },
+ },
+ ];
+ const gdprConsent = {
+ gdprApplies: 1,
+ consentString: 'dkj49Sjmfjuj34as:12jaf90123hufabidfy9u23brfpoig',
+ };
+ const uspConsent = 'mkjvbiniwot4827obfoy8sdg8203gb';
+ const expectedUserSyncs = [
+ {
+ type: 'iframe',
+ url: 'https://cookie.stpd.cloud/sync?bidders=%5B%22test%20seat%201%22%2C%22test%20seat%202%22%5D&gdpr=1&gdpr_consent=dkj49Sjmfjuj34as:12jaf90123hufabidfy9u23brfpoig&usp_consent=mkjvbiniwot4827obfoy8sdg8203gb&type=iframe',
+ },
+ ];
+
+ const userSyncs = spec.getUserSyncs(syncOptions, responses, gdprConsent, uspConsent);
+
+ expect(userSyncs).to.deep.equal(expectedUserSyncs);
+ });
+
+ it('should return empty user syncs when responsetimemillis is not defined', () => {
+ const syncOptions = {
+ iframeEnabled: true,
+ pixelEnabled: true,
+ };
+ const responses = [
+ {
+ body: {
+ ext: {},
+ },
+ },
+ ];
+ const gdprConsent = {
+ gdprApplies: 1,
+ consentString: 'dkj49Sjmfjuj34as:12jaf90123hufabidfy9u23brfpoig',
+ };
+ const uspConsent = 'mkjvbiniwot4827obfoy8sdg8203gb';
+ const expectedUserSyncs = [];
+
+ const userSyncs = spec.getUserSyncs(syncOptions, responses, gdprConsent, uspConsent);
+
+ expect(userSyncs).to.deep.equal(expectedUserSyncs);
+ });
+ });
+
+ describe('interpretResponse', function () {
+ it('should return empty array if error during parsing', () => {
+ const wrongServerResponse = 'wrong data';
+ let request = spec.buildRequests(bidRequests, bidRequests[0]);
+ let result = spec.interpretResponse(wrongServerResponse, request);
+
+ expect(result).to.be.instanceof(Array);
+ expect(result.length).to.equal(0);
+ });
+
+ it('should get correct bid response', function () {
+ const result = spec.interpretResponse(serverResponse, bidRequests[0]);
+ expect(result).to.be.an('array').with.lengthOf(1);
+ expect(result[0].requestId).to.equal('22c4871113f461');
+ expect(result[0].cpm).to.equal(0.8);
+ expect(result[0].width).to.equal(300);
+ expect(result[0].height).to.equal(250);
+ expect(result[0].creativeId).to.equal('test-bid-id');
+ expect(result[0].currency).to.equal('USD');
+ expect(result[0].netRevenue).to.equal(true);
+ expect(result[0].ttl).to.equal(360);
+ expect(result[0].ad).to.equal('this is an ad');
+ });
+ });
+
+ describe('onBidWon', function () {
+ it('should stop if bidder is not equal to BIDDER_CODE', function () {
+ const bid = {
+ bidder: 'rubicon',
+ };
+ const result = spec.onBidWon(bid);
+ expect(result).to.be.undefined;
+ });
+
+ it('should stop if bid.params is not provided', function () {
+ const bid = {
+ bidder: 'setupad',
+ };
+ const result = spec.onBidWon(bid);
+ expect(result).to.be.undefined;
+ });
+
+ it('should stop if bid.params is empty array', function () {
+ const bid = {
+ bidder: 'setupad',
+ params: [],
+ };
+ const result = spec.onBidWon(bid);
+ expect(result).to.be.undefined;
+ });
+
+ it('should stop if bid.params is not array', function () {
+ expect(
+ spec.onBidWon({
+ bidder: 'setupad',
+ params: {},
+ })
+ ).to.be.undefined;
+
+ expect(
+ spec.onBidWon({
+ bidder: 'setupad',
+ params: 'test',
+ })
+ ).to.be.undefined;
+
+ expect(
+ spec.onBidWon({
+ bidder: 'setupad',
+ params: 1,
+ })
+ ).to.be.undefined;
+
+ expect(
+ spec.onBidWon({
+ bidder: 'setupad',
+ params: null,
+ })
+ ).to.be.undefined;
+
+ expect(
+ spec.onBidWon({
+ bidder: 'setupad',
+ params: undefined,
+ })
+ ).to.be.undefined;
+ });
+
+ it('should stop if bid.params.placement_id is not provided', function () {
+ const bid = {
+ bidder: 'setupad',
+ params: [{ account_id: 'test' }],
+ };
+ const result = spec.onBidWon(bid);
+ expect(result).to.be.undefined;
+ });
+
+ it('should stop if bid.params is not provided and bid.bids is not an array', function () {
+ const bid = {
+ bidder: 'setupad',
+ params: undefined,
+ bids: {},
+ };
+ const result = spec.onBidWon(bid);
+ expect(result).to.be.undefined;
+ });
+ });
+});
diff --git a/test/spec/modules/sharethroughBidAdapter_spec.js b/test/spec/modules/sharethroughBidAdapter_spec.js
index eb0b45dda11..ab099d87429 100644
--- a/test/spec/modules/sharethroughBidAdapter_spec.js
+++ b/test/spec/modules/sharethroughBidAdapter_spec.js
@@ -425,6 +425,41 @@ describe('sharethrough adapter spec', function () {
});
});
+ describe('dsa', () => {
+ it('should properly attach dsa information to the request when applicable', () => {
+ bidderRequest.ortb2 = {
+ regs: {
+ ext: {
+ dsa: {
+ 'dsarequired': 1,
+ 'pubrender': 0,
+ 'datatopub': 1,
+ 'transparency': [{
+ 'domain': 'good-domain',
+ 'dsaparams': [1, 2]
+ }, {
+ 'domain': 'bad-setup',
+ 'dsaparams': ['1', 3]
+ }]
+ }
+ }
+ }
+ }
+
+ const openRtbReq = spec.buildRequests(bidRequests, bidderRequest)[0].data;
+ expect(openRtbReq.regs.ext.dsa.dsarequired).to.equal(1);
+ expect(openRtbReq.regs.ext.dsa.pubrender).to.equal(0);
+ expect(openRtbReq.regs.ext.dsa.datatopub).to.equal(1);
+ expect(openRtbReq.regs.ext.dsa.transparency).to.deep.equal([{
+ 'domain': 'good-domain',
+ 'dsaparams': [1, 2]
+ }, {
+ 'domain': 'bad-setup',
+ 'dsaparams': ['1', 3]
+ }]);
+ });
+ });
+
describe('transaction id at the impression level', () => {
it('should include transaction id when provided', () => {
const requests = spec.buildRequests(bidRequests, bidderRequest);
@@ -585,6 +620,64 @@ describe('sharethrough adapter spec', function () {
expect(videoImp.placement).to.equal(4);
});
+
+ it('should not override "placement" value if "plcmt" prop is present', () => {
+ // ASSEMBLE
+ const ARBITRARY_PLACEMENT_VALUE = 99;
+ const ARBITRARY_PLCMT_VALUE = 100;
+
+ bidRequests[1].mediaTypes.video.context = 'instream';
+ bidRequests[1].mediaTypes.video.placement = ARBITRARY_PLACEMENT_VALUE;
+
+ // adding "plcmt" property - this should prevent "placement" prop
+ // from getting overridden to 1
+ bidRequests[1].mediaTypes.video['plcmt'] = ARBITRARY_PLCMT_VALUE;
+
+ // ACT
+ const builtRequest = spec.buildRequests(bidRequests, bidderRequest)[1];
+ const videoImp = builtRequest.data.imp[0].video;
+
+ // ASSERT
+ expect(videoImp.placement).to.equal(ARBITRARY_PLACEMENT_VALUE);
+ expect(videoImp.plcmt).to.equal(ARBITRARY_PLCMT_VALUE);
+ });
+ });
+ });
+
+ describe('cookie deprecation', () => {
+ it('should not add cdep if we do not get it in an impression request', () => {
+ const builtRequests = spec.buildRequests(bidRequests, {
+ auctionId: 'new-auction-id',
+ ortb2: {
+ device: {
+ ext: {
+ propThatIsNotCdep: 'value-we-dont-care-about',
+ },
+ },
+ },
+ });
+ const noCdep = builtRequests.every((builtRequest) => {
+ const ourCdepValue = builtRequest.data.device?.ext?.cdep;
+ return ourCdepValue === undefined;
+ });
+ expect(noCdep).to.be.true;
+ });
+
+ it('should add cdep if we DO get it in an impression request', () => {
+ const builtRequests = spec.buildRequests(bidRequests, {
+ auctionId: 'new-auction-id',
+ ortb2: {
+ device: {
+ ext: {
+ cdep: 'cdep-value',
+ },
+ },
+ },
+ });
+ const cdepPresent = builtRequests.every((builtRequest) => {
+ return builtRequest.data.device.ext.cdep === 'cdep-value';
+ });
+ expect(cdepPresent).to.be.true;
});
});
@@ -655,6 +748,22 @@ describe('sharethrough adapter spec', function () {
expect(openRtbReq.regs.ext.gpp_sid).to.equal(firstPartyData.regs.gpp_sid);
});
});
+
+ describe('fledge', () => {
+ it('should attach "ae" as a property to the request if 1) fledge auctions are enabled, and 2) request is display (only supporting display for now)', () => {
+ // ASSEMBLE
+ const EXPECTED_AE_VALUE = 1;
+
+ // ACT
+ bidderRequest['fledgeEnabled'] = true;
+ const builtRequests = spec.buildRequests(bidRequests, bidderRequest);
+ const ACTUAL_AE_VALUE = builtRequests[0].data.imp[0].ext.ae;
+
+ // ASSERT
+ expect(ACTUAL_AE_VALUE).to.equal(EXPECTED_AE_VALUE);
+ expect(builtRequests[1].data.imp[0].ext.ae).to.be.undefined;
+ });
+ });
});
describe('interpretResponse', function () {
diff --git a/test/spec/modules/shinezRtbBidAdapter_spec.js b/test/spec/modules/shinezRtbBidAdapter_spec.js
new file mode 100644
index 00000000000..3965cd69c5f
--- /dev/null
+++ b/test/spec/modules/shinezRtbBidAdapter_spec.js
@@ -0,0 +1,639 @@
+import {expect} from 'chai';
+import {
+ spec as adapter,
+ createDomain,
+ hashCode,
+ extractPID,
+ extractCID,
+ extractSubDomain,
+ getStorageItem,
+ setStorageItem,
+ tryParseJSON,
+ getUniqueDealId,
+} from 'modules/shinezRtbBidAdapter';
+import * as utils from 'src/utils.js';
+import {version} from 'package.json';
+import {useFakeTimers} from 'sinon';
+import {BANNER, VIDEO} from '../../../src/mediaTypes';
+import {config} from '../../../src/config';
+import {deepAccess} from 'src/utils.js';
+
+export const TEST_ID_SYSTEMS = ['britepoolid', 'criteoId', 'id5id', 'idl_env', 'lipb', 'netId', 'parrableId', 'pubcid', 'tdid', 'pubProvidedId', 'digitrustid'];
+
+const SUB_DOMAIN = 'exchange';
+
+const BID = {
+ 'bidId': '2d52001cabd527',
+ 'adUnitCode': 'div-gpt-ad-12345-0',
+ 'params': {
+ 'subDomain': SUB_DOMAIN,
+ 'cId': '59db6b3b4ffaa70004f45cdc',
+ 'pId': '59ac17c192832d0011283fe3',
+ 'bidFloor': 0.1,
+ 'ext': {
+ 'param1': 'loremipsum',
+ 'param2': 'dolorsitamet'
+ }
+ },
+ 'placementCode': 'div-gpt-ad-1460505748561-0',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidderRequestId': '1fdb5ff1b6eaa7',
+ 'bidRequestsCount': 4,
+ 'bidderRequestsCount': 3,
+ 'bidderWinsCount': 1,
+ 'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a',
+ 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc',
+ 'mediaTypes': [BANNER],
+ 'ortb2Imp': {
+ 'ext': {
+ 'gpid': '0123456789',
+ 'tid': '56e184c6-bde9-497b-b9b9-cf47a61381ee'
+ }
+ }
+};
+
+const VIDEO_BID = {
+ 'bidId': '2d52001cabd527',
+ 'adUnitCode': '63550ad1ff6642d368cba59dh5884270560',
+ 'bidderRequestId': '12a8ae9ada9c13',
+ 'bidRequestsCount': 4,
+ 'bidderRequestsCount': 3,
+ 'bidderWinsCount': 1,
+ 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc',
+ 'params': {
+ 'subDomain': SUB_DOMAIN,
+ 'cId': '635509f7ff6642d368cb9837',
+ 'pId': '59ac17c192832d0011283fe3',
+ 'bidFloor': 0.1
+ },
+ 'sizes': [[545, 307]],
+ 'mediaTypes': {
+ 'video': {
+ 'playerSize': [[545, 307]],
+ 'context': 'instream',
+ 'mimes': [
+ 'video/mp4',
+ 'application/javascript'
+ ],
+ 'protocols': [2, 3, 5, 6],
+ 'maxduration': 60,
+ 'minduration': 0,
+ 'startdelay': 0,
+ 'linearity': 1,
+ 'api': [2],
+ 'placement': 1
+ }
+ },
+ 'ortb2Imp': {
+ 'ext': {
+ 'gpid': '0123456789',
+ 'tid': '56e184c6-bde9-497b-b9b9-cf47a61381ee'
+ }
+ }
+}
+
+const BIDDER_REQUEST = {
+ 'gdprConsent': {
+ 'consentString': 'consent_string',
+ 'gdprApplies': true
+ },
+ 'gppConsent': {
+ 'gppString': 'gpp_string',
+ 'applicableSections': [7]
+ },
+ 'uspConsent': 'consent_string',
+ 'refererInfo': {
+ 'page': 'https://www.greatsite.com',
+ 'ref': 'https://www.somereferrer.com'
+ },
+ 'ortb2': {
+ 'regs': {
+ 'gpp': 'gpp_string',
+ 'gpp_sid': [7]
+ },
+ 'device': {
+ 'sua': {
+ 'source': 2,
+ 'platform': {
+ 'brand': 'Android',
+ 'version': ['8', '0', '0']
+ },
+ 'browsers': [
+ {'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']},
+ {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']},
+ {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']}
+ ],
+ 'mobile': 1,
+ 'model': 'SM-G955U',
+ 'bitness': '64',
+ 'architecture': ''
+ }
+ }
+ }
+};
+
+const SERVER_RESPONSE = {
+ body: {
+ cid: 'testcid123',
+ results: [{
+ 'ad': '
',
+ 'price': 0.8,
+ 'creativeId': '12610997325162499419',
+ 'exp': 30,
+ 'width': 300,
+ 'height': 250,
+ 'advertiserDomains': ['securepubads.g.doubleclick.net'],
+ 'cookies': [{
+ 'src': 'https://sync.com',
+ 'type': 'iframe'
+ }, {
+ 'src': 'https://sync.com',
+ 'type': 'img'
+ }]
+ }]
+ }
+};
+
+const VIDEO_SERVER_RESPONSE = {
+ body: {
+ 'cid': '635509f7ff6642d368cb9837',
+ 'results': [{
+ 'ad': '
',
+ 'advertiserDomains': ['sweetgum.io'],
+ 'exp': 60,
+ 'width': 545,
+ 'height': 307,
+ 'mediaType': 'video',
+ 'creativeId': '12610997325162499419',
+ 'price': 2,
+ 'cookies': []
+ }]
+ }
+};
+
+const REQUEST = {
+ data: {
+ width: 300,
+ height: 250,
+ bidId: '2d52001cabd527'
+ }
+};
+
+function getTopWindowQueryParams() {
+ try {
+ const parsedUrl = utils.parseUrl(window.top.document.URL, {decodeSearchAsString: true});
+ return parsedUrl.search;
+ } catch (e) {
+ return '';
+ }
+}
+
+describe('ShinezRtbBidAdapter', function () {
+ describe('validtae spec', function () {
+ it('exists and is a function', function () {
+ expect(adapter.isBidRequestValid).to.exist.and.to.be.a('function');
+ });
+
+ it('exists and is a function', function () {
+ expect(adapter.buildRequests).to.exist.and.to.be.a('function');
+ });
+
+ it('exists and is a function', function () {
+ expect(adapter.interpretResponse).to.exist.and.to.be.a('function');
+ });
+
+ it('exists and is a function', function () {
+ expect(adapter.getUserSyncs).to.exist.and.to.be.a('function');
+ });
+
+ it('exists and is a string', function () {
+ expect(adapter.code).to.exist.and.to.be.a('string');
+ });
+
+ it('exists and contains media types', function () {
+ expect(adapter.supportedMediaTypes).to.exist.and.to.be.an('array').with.length(2);
+ expect(adapter.supportedMediaTypes).to.contain.members([BANNER, VIDEO]);
+ });
+ });
+
+ describe('validate bid requests', function () {
+ it('should require cId', function () {
+ const isValid = adapter.isBidRequestValid({
+ params: {
+ pId: 'pid'
+ }
+ });
+ expect(isValid).to.be.false;
+ });
+
+ it('should require pId', function () {
+ const isValid = adapter.isBidRequestValid({
+ params: {
+ cId: 'cid'
+ }
+ });
+ expect(isValid).to.be.false;
+ });
+
+ it('should validate correctly', function () {
+ const isValid = adapter.isBidRequestValid({
+ params: {
+ cId: 'cid',
+ pId: 'pid'
+ }
+ });
+ expect(isValid).to.be.true;
+ });
+ });
+
+ describe('build requests', function () {
+ let sandbox;
+ before(function () {
+ $$PREBID_GLOBAL$$.bidderSettings = {
+ shinezRtb: {
+ storageAllowed: true
+ }
+ };
+ sandbox = sinon.sandbox.create();
+ sandbox.stub(Date, 'now').returns(1000);
+ });
+
+ it('should build video request', function () {
+ const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page);
+ config.setConfig({
+ bidderTimeout: 3000,
+ enableTIDs: true
+ });
+ const requests = adapter.buildRequests([VIDEO_BID], BIDDER_REQUEST);
+ expect(requests).to.have.length(1);
+ expect(requests[0]).to.deep.equal({
+ method: 'POST',
+ url: `${createDomain(SUB_DOMAIN)}/prebid/multi/635509f7ff6642d368cb9837`,
+ data: {
+ adUnitCode: '63550ad1ff6642d368cba59dh5884270560',
+ bidFloor: 0.1,
+ bidId: '2d52001cabd527',
+ bidderVersion: adapter.version,
+ bidderRequestId: '12a8ae9ada9c13',
+ cb: 1000,
+ gdpr: 1,
+ gdprConsent: 'consent_string',
+ usPrivacy: 'consent_string',
+ gppString: 'gpp_string',
+ gppSid: [7],
+ transactionId: '56e184c6-bde9-497b-b9b9-cf47a61381ee',
+ prebidVersion: version,
+ bidRequestsCount: 4,
+ bidderRequestsCount: 3,
+ bidderWinsCount: 1,
+ bidderTimeout: 3000,
+ publisherId: '59ac17c192832d0011283fe3',
+ url: 'https%3A%2F%2Fwww.greatsite.com',
+ referrer: 'https://www.somereferrer.com',
+ res: `${window.top.screen.width}x${window.top.screen.height}`,
+ schain: VIDEO_BID.schain,
+ sizes: ['545x307'],
+ sua: {
+ 'source': 2,
+ 'platform': {
+ 'brand': 'Android',
+ 'version': ['8', '0', '0']
+ },
+ 'browsers': [
+ {'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']},
+ {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']},
+ {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']}
+ ],
+ 'mobile': 1,
+ 'model': 'SM-G955U',
+ 'bitness': '64',
+ 'architecture': ''
+ },
+ uniqueDealId: `${hashUrl}_${Date.now().toString()}`,
+ uqs: getTopWindowQueryParams(),
+ mediaTypes: {
+ video: {
+ api: [2],
+ context: 'instream',
+ linearity: 1,
+ maxduration: 60,
+ mimes: [
+ 'video/mp4',
+ 'application/javascript'
+ ],
+ minduration: 0,
+ placement: 1,
+ playerSize: [[545, 307]],
+ protocols: [2, 3, 5, 6],
+ startdelay: 0
+ }
+ },
+ gpid: '0123456789'
+ }
+ });
+ });
+
+ it('should build banner request for each size', function () {
+ const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page);
+ config.setConfig({
+ bidderTimeout: 3000,
+ enableTIDs: true
+ });
+ const requests = adapter.buildRequests([BID], BIDDER_REQUEST);
+ expect(requests).to.have.length(1);
+ expect(requests[0]).to.deep.equal({
+ method: 'POST',
+ url: `${createDomain(SUB_DOMAIN)}/prebid/multi/59db6b3b4ffaa70004f45cdc`,
+ data: {
+ gdprConsent: 'consent_string',
+ gdpr: 1,
+ gppString: 'gpp_string',
+ gppSid: [7],
+ usPrivacy: 'consent_string',
+ bidRequestsCount: 4,
+ bidderRequestsCount: 3,
+ bidderWinsCount: 1,
+ bidderTimeout: 3000,
+ bidderRequestId: '1fdb5ff1b6eaa7',
+ transactionId: '56e184c6-bde9-497b-b9b9-cf47a61381ee',
+ sizes: ['300x250', '300x600'],
+ sua: {
+ 'source': 2,
+ 'platform': {
+ 'brand': 'Android',
+ 'version': ['8', '0', '0']
+ },
+ 'browsers': [
+ {'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']},
+ {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']},
+ {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']}
+ ],
+ 'mobile': 1,
+ 'model': 'SM-G955U',
+ 'bitness': '64',
+ 'architecture': ''
+ },
+ url: 'https%3A%2F%2Fwww.greatsite.com',
+ referrer: 'https://www.somereferrer.com',
+ cb: 1000,
+ bidFloor: 0.1,
+ bidId: '2d52001cabd527',
+ adUnitCode: 'div-gpt-ad-12345-0',
+ publisherId: '59ac17c192832d0011283fe3',
+ uniqueDealId: `${hashUrl}_${Date.now().toString()}`,
+ bidderVersion: adapter.version,
+ prebidVersion: version,
+ schain: BID.schain,
+ res: `${window.top.screen.width}x${window.top.screen.height}`,
+ mediaTypes: [BANNER],
+ gpid: '0123456789',
+ uqs: getTopWindowQueryParams(),
+ 'ext.param1': 'loremipsum',
+ 'ext.param2': 'dolorsitamet',
+ }
+ });
+ });
+
+ after(function () {
+ $$PREBID_GLOBAL$$.bidderSettings = {};
+ sandbox.restore();
+ });
+ });
+ describe('getUserSyncs', function () {
+ it('should have valid user sync with iframeEnabled', function () {
+ const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]);
+
+ expect(result).to.deep.equal([{
+ type: 'iframe',
+ url: 'https://sync.sweetgum.io/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy='
+ }]);
+ });
+
+ it('should have valid user sync with cid on response', function () {
+ const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]);
+ expect(result).to.deep.equal([{
+ type: 'iframe',
+ url: 'https://sync.sweetgum.io/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy='
+ }]);
+ });
+
+ it('should have valid user sync with pixelEnabled', function () {
+ const result = adapter.getUserSyncs({pixelEnabled: true}, [SERVER_RESPONSE]);
+
+ expect(result).to.deep.equal([{
+ 'url': 'https://sync.sweetgum.io/api/sync/image/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=',
+ 'type': 'image'
+ }]);
+ })
+ });
+
+ describe('interpret response', function () {
+ it('should return empty array when there is no response', function () {
+ const responses = adapter.interpretResponse(null);
+ expect(responses).to.be.empty;
+ });
+
+ it('should return empty array when there is no ad', function () {
+ const responses = adapter.interpretResponse({price: 1, ad: ''});
+ expect(responses).to.be.empty;
+ });
+
+ it('should return empty array when there is no price', function () {
+ const responses = adapter.interpretResponse({price: null, ad: 'great ad'});
+ expect(responses).to.be.empty;
+ });
+
+ it('should return an array of interpreted banner responses', function () {
+ const responses = adapter.interpretResponse(SERVER_RESPONSE, REQUEST);
+ expect(responses).to.have.length(1);
+ expect(responses[0]).to.deep.equal({
+ requestId: '2d52001cabd527',
+ cpm: 0.8,
+ width: 300,
+ height: 250,
+ creativeId: '12610997325162499419',
+ currency: 'USD',
+ netRevenue: true,
+ ttl: 30,
+ ad: '
',
+ meta: {
+ advertiserDomains: ['securepubads.g.doubleclick.net']
+ }
+ });
+ });
+
+ it('should get meta from response metaData', function () {
+ const serverResponse = utils.deepClone(SERVER_RESPONSE);
+ serverResponse.body.results[0].metaData = {
+ advertiserDomains: ['sweetgum.io'],
+ agencyName: 'Agency Name',
+ };
+ const responses = adapter.interpretResponse(serverResponse, REQUEST);
+ expect(responses[0].meta).to.deep.equal({
+ advertiserDomains: ['sweetgum.io'],
+ agencyName: 'Agency Name'
+ });
+ });
+
+ it('should return an array of interpreted video responses', function () {
+ const responses = adapter.interpretResponse(VIDEO_SERVER_RESPONSE, REQUEST);
+ expect(responses).to.have.length(1);
+ expect(responses[0]).to.deep.equal({
+ requestId: '2d52001cabd527',
+ cpm: 2,
+ width: 545,
+ height: 307,
+ mediaType: 'video',
+ creativeId: '12610997325162499419',
+ currency: 'USD',
+ netRevenue: true,
+ ttl: 60,
+ vastXml: '
',
+ meta: {
+ advertiserDomains: ['sweetgum.io']
+ }
+ });
+ });
+
+ it('should take default TTL', function () {
+ const serverResponse = utils.deepClone(SERVER_RESPONSE);
+ delete serverResponse.body.results[0].exp;
+ const responses = adapter.interpretResponse(serverResponse, REQUEST);
+ expect(responses).to.have.length(1);
+ expect(responses[0].ttl).to.equal(300);
+ });
+ });
+
+ describe('user id system', function () {
+ TEST_ID_SYSTEMS.forEach((idSystemProvider) => {
+ const id = Date.now().toString();
+ const bid = utils.deepClone(BID);
+
+ const userId = (function () {
+ switch (idSystemProvider) {
+ case 'digitrustid':
+ return {data: {id}};
+ case 'lipb':
+ return {lipbid: id};
+ case 'parrableId':
+ return {eid: id};
+ case 'id5id':
+ return {uid: id};
+ default:
+ return id;
+ }
+ })();
+
+ bid.userId = {
+ [idSystemProvider]: userId
+ };
+
+ it(`should include 'uid.${idSystemProvider}' in request params`, function () {
+ const requests = adapter.buildRequests([bid], BIDDER_REQUEST);
+ expect(requests[0].data[`uid.${idSystemProvider}`]).to.equal(id);
+ });
+ });
+ });
+
+ describe('alternate param names extractors', function () {
+ it('should return undefined when param not supported', function () {
+ const cid = extractCID({'c_id': '1'});
+ const pid = extractPID({'p_id': '1'});
+ const subDomain = extractSubDomain({'sub_domain': 'prebid'});
+ expect(cid).to.be.undefined;
+ expect(pid).to.be.undefined;
+ expect(subDomain).to.be.undefined;
+ });
+
+ it('should return value when param supported', function () {
+ const cid = extractCID({'cID': '1'});
+ const pid = extractPID({'Pid': '2'});
+ const subDomain = extractSubDomain({'subDOMAIN': 'prebid'});
+ expect(cid).to.be.equal('1');
+ expect(pid).to.be.equal('2');
+ expect(subDomain).to.be.equal('prebid');
+ });
+ });
+
+ describe('unique deal id', function () {
+ before(function () {
+ $$PREBID_GLOBAL$$.bidderSettings = {
+ shinezRtb: {
+ storageAllowed: true
+ }
+ };
+ });
+ after(function () {
+ $$PREBID_GLOBAL$$.bidderSettings = {};
+ });
+ const key = 'myKey';
+ let uniqueDealId;
+ beforeEach(() => {
+ uniqueDealId = getUniqueDealId(key, 0);
+ })
+
+ it('should get current unique deal id', function (done) {
+ // waiting some time so `now` will become past
+ setTimeout(() => {
+ const current = getUniqueDealId(key);
+ expect(current).to.be.equal(uniqueDealId);
+ done();
+ }, 200);
+ });
+
+ it('should get new unique deal id on expiration', function (done) {
+ setTimeout(() => {
+ const current = getUniqueDealId(key, 100);
+ expect(current).to.not.be.equal(uniqueDealId);
+ done();
+ }, 200)
+ });
+ });
+
+ describe('storage utils', function () {
+ before(function () {
+ $$PREBID_GLOBAL$$.bidderSettings = {
+ shinezRtb: {
+ storageAllowed: true
+ }
+ };
+ });
+ after(function () {
+ $$PREBID_GLOBAL$$.bidderSettings = {};
+ });
+ it('should get value from storage with create param', function () {
+ const now = Date.now();
+ const clock = useFakeTimers({
+ shouldAdvanceTime: true,
+ now
+ });
+ setStorageItem('myKey', 2020);
+ const {value, created} = getStorageItem('myKey');
+ expect(created).to.be.equal(now);
+ expect(value).to.be.equal(2020);
+ expect(typeof value).to.be.equal('number');
+ expect(typeof created).to.be.equal('number');
+ clock.restore();
+ });
+
+ it('should get external stored value', function () {
+ const value = 'superman'
+ window.localStorage.setItem('myExternalKey', value);
+ const item = getStorageItem('myExternalKey');
+ expect(item).to.be.equal(value);
+ });
+
+ it('should parse JSON value', function () {
+ const data = JSON.stringify({event: 'send'});
+ const {event} = tryParseJSON(data);
+ expect(event).to.be.equal('send');
+ });
+
+ it('should get original value on parse fail', function () {
+ const value = 21;
+ const parsed = tryParseJSON(value);
+ expect(typeof parsed).to.be.equal('number');
+ expect(parsed).to.be.equal(value);
+ });
+ });
+});
diff --git a/test/spec/modules/silvermobBidAdapter_spec.js b/test/spec/modules/silvermobBidAdapter_spec.js
new file mode 100644
index 00000000000..7d7fbacc04e
--- /dev/null
+++ b/test/spec/modules/silvermobBidAdapter_spec.js
@@ -0,0 +1,301 @@
+import { expect } from 'chai';
+import {spec} from '../../../modules/silvermobBidAdapter.js';
+import 'modules/priceFloors.js';
+import { newBidder } from 'src/adapters/bidderFactory';
+import { config } from '../../../src/config.js';
+import { syncAddFPDToBidderRequest } from '../../helpers/fpd.js';
+
+// load modules that register ORTB processors
+import 'src/prebid.js';
+import 'modules/currency.js';
+import 'modules/userId/index.js';
+import 'modules/multibid/index.js';
+import 'modules/priceFloors.js';
+import 'modules/consentManagement.js';
+import 'modules/consentManagementUsp.js';
+import 'modules/schain.js';
+
+const SIMPLE_BID_REQUEST = {
+ bidder: 'silvermob',
+ params: {
+ zoneid: '0',
+ host: 'us',
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [320, 250],
+ [300, 600],
+ ],
+ },
+ },
+ adUnitCode: 'div-gpt-ad-1499748733608-0',
+ transactionId: 'f183e871-fbed-45f0-a427-c8a63c4c01eb',
+ bidId: '33e9500b21129f',
+ bidderRequestId: '2772c1e566670b',
+ auctionId: '192721e36a0239',
+ sizes: [[300, 250], [160, 600]],
+ gdprConsent: {
+ apiVersion: 2,
+ consentString: 'CONSENT',
+ vendorData: { purpose: { consents: { 1: true } } },
+ gdprApplies: true,
+ addtlConsent: '1~1.35.41.101',
+ },
+}
+
+const BANNER_BID_REQUEST = {
+ bidder: 'silvermob',
+ params: {
+ zoneid: '0',
+ host: 'us',
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [300, 250],
+ [300, 600],
+ ],
+ },
+ },
+ adUnitCode: '/adunit-code/test-path',
+ bidId: 'test-bid-id-1',
+ bidderRequestId: 'test-bid-request-1',
+ auctionId: 'test-auction-1',
+ transactionId: 'test-transactionId-1',
+ code: 'banner_example',
+ timeout: 1000,
+}
+
+const VIDEO_BID_REQUEST = {
+ placementCode: '/DfpAccount1/slotVideo',
+ bidId: 'test-bid-id-2',
+ mediaTypes: {
+ video: {
+ playerSize: [400, 300],
+ w: 400,
+ h: 300,
+ minduration: 5,
+ maxduration: 10,
+ startdelay: 0,
+ skip: 1,
+ minbitrate: 200,
+ protocols: [1, 2, 4]
+ }
+ },
+ bidder: 'silvermob',
+ params: {
+ zoneid: '0',
+ host: 'us',
+ },
+ adUnitCode: '/adunit-code/test-path',
+ bidderRequestId: 'test-bid-request-1',
+ auctionId: 'test-auction-1',
+ transactionId: 'test-transactionId-1',
+ timeout: 1000,
+}
+
+const NATIVE_BID_REQUEST = {
+ code: 'native_example',
+ mediaTypes: {
+ native: {
+ title: {
+ required: true,
+ len: 800
+ },
+ image: {
+ required: true,
+ len: 80
+ },
+ sponsoredBy: {
+ required: true
+ },
+ clickUrl: {
+ required: true
+ },
+ privacyLink: {
+ required: false
+ },
+ body: {
+ required: true
+ },
+ icon: {
+ required: true,
+ sizes: [50, 50]
+ }
+ }
+ },
+ bidder: 'silvermob',
+ params: {
+ zoneid: '0',
+ host: 'us',
+ },
+ adUnitCode: '/adunit-code/test-path',
+ bidId: 'test-bid-id-1',
+ bidderRequestId: 'test-bid-request-1',
+ auctionId: 'test-auction-1',
+ transactionId: 'test-transactionId-1',
+ timeout: 1000,
+ uspConsent: 'uspConsent'
+};
+
+const bidderRequest = {
+ refererInfo: {
+ page: 'https://publisher.com/home',
+ ref: 'https://referrer'
+ }
+};
+
+const gdprConsent = {
+ apiVersion: 2,
+ consentString: 'CONSENT',
+ vendorData: { purpose: { consents: { 1: true } } },
+ gdprApplies: true,
+ addtlConsent: '1~1.35.41.101',
+}
+
+describe('silvermobAdapter', function () {
+ const adapter = newBidder(spec);
+ describe('inherited functions', function () {
+ it('exists and is a function', function () {
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
+ });
+ });
+
+ describe('with user privacy regulations', function () {
+ it('should send the Coppa "required" flag set to "1" in the request', function () {
+ sinon.stub(config, 'getConfig')
+ .withArgs('coppa')
+ .returns(true);
+ const serverRequest = spec.buildRequests([SIMPLE_BID_REQUEST], syncAddFPDToBidderRequest(bidderRequest));
+ expect(serverRequest.data.regs.coppa).to.equal(1);
+ config.getConfig.restore();
+ });
+
+ it('should send the GDPR Consent data in the request', function () {
+ const serverRequest = spec.buildRequests([SIMPLE_BID_REQUEST], syncAddFPDToBidderRequest({ ...bidderRequest, gdprConsent }));
+ expect(serverRequest.data.regs.ext.gdpr).to.exist.and.to.equal(1);
+ expect(serverRequest.data.user.ext.consent).to.equal('CONSENT');
+ });
+
+ it('should send the CCPA data in the request', function () {
+ const serverRequest = spec.buildRequests([SIMPLE_BID_REQUEST], syncAddFPDToBidderRequest({...bidderRequest, ...{ uspConsent: '1YYY' }}));
+ expect(serverRequest.data.regs.ext.us_privacy).to.equal('1YYY');
+ });
+ });
+
+ describe('isBidRequestValid', function () {
+ it('should return true when required params found', function () {
+ expect(spec.isBidRequestValid(BANNER_BID_REQUEST)).to.equal(true);
+ });
+
+ it('should return false when zoneid is missing', function () {
+ let localbid = Object.assign({}, BANNER_BID_REQUEST);
+ delete localbid.params.zoneid;
+ expect(spec.isBidRequestValid(BANNER_BID_REQUEST)).to.equal(false);
+ });
+ });
+
+ describe('build request', function () {
+ it('should return an empty array when no bid requests', function () {
+ const bidRequest = spec.buildRequests([], syncAddFPDToBidderRequest(bidderRequest));
+ expect(bidRequest).to.be.an('array');
+ expect(bidRequest.length).to.equal(0);
+ });
+
+ it('should return a valid bid request object', function () {
+ const request = spec.buildRequests([SIMPLE_BID_REQUEST], syncAddFPDToBidderRequest(bidderRequest));
+ expect(request).to.not.equal('array');
+ expect(request.data).to.be.an('object');
+ expect(request.method).to.equal('POST');
+ expect(request.url).to.equal('https://us.silvermob.com/marketplace/api/dsp/prebidjs/0');
+
+ expect(request.data.site).to.have.property('page');
+ expect(request.data.site).to.have.property('domain');
+ expect(request.data).to.have.property('id');
+ expect(request.data).to.have.property('imp');
+ expect(request.data).to.have.property('device');
+ });
+
+ it('should return a valid bid BANNER request object', function () {
+ const request = spec.buildRequests([BANNER_BID_REQUEST], syncAddFPDToBidderRequest(bidderRequest));
+ expect(request.data.imp[0].banner).to.exist;
+ expect(request.data.imp[0].banner.format[0].w).to.be.an('number');
+ expect(request.data.imp[0].banner.format[0].h).to.be.an('number');
+ });
+
+ if (FEATURES.VIDEO) {
+ it('should return a valid bid VIDEO request object', function () {
+ const request = spec.buildRequests([VIDEO_BID_REQUEST], syncAddFPDToBidderRequest(bidderRequest));
+ expect(request.data.imp[0].video).to.exist;
+ expect(request.data.imp[0].video.w).to.be.an('number');
+ expect(request.data.imp[0].video.h).to.be.an('number');
+ });
+ }
+
+ it('should return a valid bid NATIVE request object', function () {
+ const request = spec.buildRequests([NATIVE_BID_REQUEST], syncAddFPDToBidderRequest(bidderRequest));
+ expect(request.data.imp[0]).to.be.an('object');
+ });
+ })
+
+ describe('interpretResponse', function () {
+ let bidRequests, bidderRequest;
+ beforeEach(function () {
+ bidRequests = [{
+ 'bidId': '28ffdk2B952532',
+ 'bidder': 'silvermob',
+ 'userId': {
+ 'freepassId': {
+ 'userIp': '172.21.0.1',
+ 'userId': '123',
+ 'commonId': 'commonIdValue'
+ }
+ },
+ 'adUnitCode': 'adunit-code',
+ 'params': {
+ 'publisherId': 'publisherIdValue'
+ }
+ }];
+ bidderRequest = {};
+ });
+
+ it('Empty response must return empty array', function () {
+ const emptyResponse = null;
+ let response = spec.interpretResponse(emptyResponse, BANNER_BID_REQUEST);
+
+ expect(response).to.be.an('array').that.is.empty;
+ })
+
+ it('Should interpret banner response', function () {
+ const serverResponse = {
+ body: {
+ 'cur': 'USD',
+ 'seatbid': [{
+ 'bid': [{
+ 'impid': '28ffdk2B952532',
+ 'price': 97,
+ 'adm': '
',
+ 'w': 300,
+ 'h': 250,
+ 'crid': 'creative0'
+ }]
+ }]
+ }
+ };
+ it('should interpret server response', function () {
+ const bidRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest));
+ const bids = spec.interpretResponse(serverResponse, bidRequest);
+ expect(bids).to.be.an('array');
+ const bid = bids[0];
+ expect(bid).to.be.an('object');
+ expect(bid.currency).to.equal('USD');
+ expect(bid.cpm).to.equal(97);
+ expect(bid.ad).to.equal(ad)
+ expect(bid.width).to.equal(300);
+ expect(bid.height).to.equal(250);
+ expect(bid.creativeId).to.equal('creative0');
+ });
+ })
+ });
+});
diff --git a/test/spec/modules/smartadserverBidAdapter_spec.js b/test/spec/modules/smartadserverBidAdapter_spec.js
index 9daa6a87826..b01d95e2a4c 100644
--- a/test/spec/modules/smartadserverBidAdapter_spec.js
+++ b/test/spec/modules/smartadserverBidAdapter_spec.js
@@ -786,8 +786,8 @@ describe('Smart bid adapter tests', function () {
expect(request[0]).to.have.property('method').and.to.equal('POST');
const requestContent = JSON.parse(request[0].data);
expect(requestContent).to.have.property('videoData');
- expect(requestContent.videoData).to.have.property('videoProtocol').and.to.equal(null);
- expect(requestContent.videoData).to.have.property('adBreak').and.to.equal(2);
+ expect(requestContent.videoData).not.to.have.property('videoProtocol').eq(true);
+ expect(requestContent.videoData).to.have.property('adBreak').and.to.equal(1);
});
it('Verify videoData params override meta values', function () {
@@ -833,6 +833,73 @@ describe('Smart bid adapter tests', function () {
expect(requestContent.videoData).to.have.property('videoProtocol').and.to.equal(6);
expect(requestContent.videoData).to.have.property('adBreak').and.to.equal(3);
});
+
+ it('should pass additional parameters', function () {
+ const request = spec.buildRequests([{
+ bidder: 'smartadserver',
+ mediaTypes: {
+ video: {
+ context: 'instream',
+ api: [1, 2, 3],
+ maxbitrate: 50,
+ minbitrate: 20,
+ maxduration: 30,
+ minduration: 5,
+ placement: 3,
+ playbackmethod: [2, 4],
+ playerSize: [[640, 480]],
+ plcmt: 1,
+ skip: 0
+ }
+ },
+ params: {
+ siteId: '123'
+ }
+ }]);
+ const requestContent = JSON.parse(request[0].data);
+
+ expect(requestContent.videoData).to.have.property('iabframeworks').and.to.equal('1,2,3');
+ expect(requestContent.videoData).not.to.have.property('skip');
+ expect(requestContent.videoData).to.have.property('vbrmax').and.to.equal(50);
+ expect(requestContent.videoData).to.have.property('vbrmin').and.to.equal(20);
+ expect(requestContent.videoData).to.have.property('vdmax').and.to.equal(30);
+ expect(requestContent.videoData).to.have.property('vdmin').and.to.equal(5);
+ expect(requestContent.videoData).to.have.property('vplcmt').and.to.equal(1);
+ expect(requestContent.videoData).to.have.property('vpmt').and.to.have.lengthOf(2);
+ expect(requestContent.videoData.vpmt[0]).to.equal(2);
+ expect(requestContent.videoData.vpmt[1]).to.equal(4);
+ expect(requestContent.videoData).to.have.property('vpt').and.to.equal(3);
+ });
+
+ it('should not pass not valuable parameters', function () {
+ const request = spec.buildRequests([{
+ bidder: 'smartadserver',
+ mediaTypes: {
+ video: {
+ context: 'instream',
+ maxbitrate: 20,
+ minbitrate: null,
+ maxduration: 0,
+ playbackmethod: [],
+ playerSize: [[640, 480]],
+ plcmt: 1
+ }
+ },
+ params: {
+ siteId: '123'
+ }
+ }]);
+ const requestContent = JSON.parse(request[0].data);
+
+ expect(requestContent.videoData).not.to.have.property('iabframeworks');
+ expect(requestContent.videoData).to.have.property('vbrmax').and.to.equal(20);
+ expect(requestContent.videoData).not.to.have.property('vbrmin');
+ expect(requestContent.videoData).not.to.have.property('vdmax');
+ expect(requestContent.videoData).not.to.have.property('vdmin');
+ expect(requestContent.videoData).to.have.property('vplcmt').and.to.equal(1);
+ expect(requestContent.videoData).not.to.have.property('vpmt');
+ expect(requestContent.videoData).not.to.have.property('vpt');
+ });
});
});
@@ -1029,8 +1096,8 @@ describe('Smart bid adapter tests', function () {
expect(request[0]).to.have.property('method').and.to.equal('POST');
const requestContent = JSON.parse(request[0].data);
expect(requestContent).to.have.property('videoData');
- expect(requestContent.videoData).to.have.property('videoProtocol').and.to.equal(null);
- expect(requestContent.videoData).to.have.property('adBreak').and.to.equal(2);
+ expect(requestContent.videoData).not.to.have.property('videoProtocol').eq(true);
+ expect(requestContent.videoData).to.have.property('adBreak').and.to.equal(1);
});
it('Verify videoData params override meta values', function () {
@@ -1076,6 +1143,50 @@ describe('Smart bid adapter tests', function () {
expect(requestContent.videoData).to.have.property('videoProtocol').and.to.equal(6);
expect(requestContent.videoData).to.have.property('adBreak').and.to.equal(3);
});
+
+ it('should handle value of videoMediaType.startdelay', function () {
+ const request = spec.buildRequests([{
+ bidder: 'smartadserver',
+ mediaTypes: {
+ video: {
+ context: 'outstream',
+ playerSize: [[640, 480]],
+ startdelay: -2
+ }
+ },
+ params: {
+ siteId: 123,
+ pageId: 456,
+ formatId: 78
+ }
+ }]);
+
+ const requestContent = JSON.parse(request[0].data);
+ expect(requestContent).to.have.property('videoData');
+ expect(requestContent.videoData).to.have.property('adBreak').and.to.equal(3);
+ });
+
+ it('should return specified value of videoMediaType.startdelay', function () {
+ const request = spec.buildRequests([{
+ bidder: 'smartadserver',
+ mediaTypes: {
+ video: {
+ context: 'outstream',
+ playerSize: [[640, 480]],
+ startdelay: 60
+ }
+ },
+ params: {
+ siteId: 123,
+ pageId: 456,
+ formatId: 78
+ }
+ }]);
+
+ const requestContent = JSON.parse(request[0].data);
+ expect(requestContent).to.have.property('videoData');
+ expect(requestContent.videoData).to.have.property('adBreak').and.to.equal(2);
+ });
});
describe('External ids tests', function () {
@@ -1393,4 +1504,41 @@ describe('Smart bid adapter tests', function () {
expect(requestContent).to.have.property('gpid').and.to.equal(gpid);
});
});
+
+ describe('#getValuableProperty method', function () {
+ it('should return an object when calling with a number value', () => {
+ const obj = spec.getValuableProperty('prop', 3);
+ expect(obj).to.deep.equal({ prop: 3 });
+ });
+
+ it('should return an empty object when calling with a string value', () => {
+ const obj = spec.getValuableProperty('prop', 'str');
+ expect(obj).to.deep.equal({});
+ });
+
+ it('should return an empty object when calling with a number property', () => {
+ const obj = spec.getValuableProperty(7, 'str');
+ expect(obj).to.deep.equal({});
+ });
+
+ it('should return an empty object when calling with a null value', () => {
+ const obj = spec.getValuableProperty('prop', null);
+ expect(obj).to.deep.equal({});
+ });
+
+ it('should return an empty object when calling with an object value', () => {
+ const obj = spec.getValuableProperty('prop', {});
+ expect(obj).to.deep.equal({});
+ });
+
+ it('should return an empty object when calling with a 0 value', () => {
+ const obj = spec.getValuableProperty('prop', 0);
+ expect(obj).to.deep.equal({});
+ });
+
+ it('should return an empty object when calling without the value argument', () => {
+ const obj = spec.getValuableProperty('prop');
+ expect(obj).to.deep.equal({});
+ });
+ });
});
diff --git a/test/spec/modules/smartyadsBidAdapter_spec.js b/test/spec/modules/smartyadsBidAdapter_spec.js
index 992fff14f33..1b592e142c3 100644
--- a/test/spec/modules/smartyadsBidAdapter_spec.js
+++ b/test/spec/modules/smartyadsBidAdapter_spec.js
@@ -52,12 +52,16 @@ describe('SmartyadsAdapter', function () {
expect(serverRequest.method).to.equal('POST');
});
it('Returns valid URL', function () {
- expect(serverRequest.url).to.equal('https://n1.smartyads.com/?c=o&m=prebid&secret_key=prebid_js');
+ expect(serverRequest.url).to.be.oneOf([
+ 'https://n1.smartyads.com/?c=o&m=prebid&secret_key=prebid_js',
+ 'https://n2.smartyads.com/?c=o&m=prebid&secret_key=prebid_js',
+ 'https://n6.smartyads.com/?c=o&m=prebid&secret_key=prebid_js'
+ ]);
});
it('Returns valid data if array of bids is valid', function () {
let data = serverRequest.data;
expect(data).to.be.an('object');
- expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements', 'coppa');
+ expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements', 'coppa', 'eeid', 'ifa');
expect(data.deviceWidth).to.be.a('number');
expect(data.deviceHeight).to.be.a('number');
expect(data.coppa).to.be.a('number');
diff --git a/test/spec/modules/smilewantedBidAdapter_spec.js b/test/spec/modules/smilewantedBidAdapter_spec.js
index 22221dbe1ef..99c4034610f 100644
--- a/test/spec/modules/smilewantedBidAdapter_spec.js
+++ b/test/spec/modules/smilewantedBidAdapter_spec.js
@@ -93,7 +93,24 @@ const BID_RESPONSE_DISPLAY = {
const VIDEO_INSTREAM_REQUEST = [{
code: 'video1',
mediaTypes: {
- video: {}
+ video: {
+ context: 'instream',
+ mimes: ['video/mp4'],
+ minduration: 0,
+ maxduration: 120,
+ protocols: [1, 2, 3, 4, 5, 6, 7, 8],
+ startdelay: 0,
+ placement: 1,
+ skip: 1,
+ skipafter: 10,
+ minbitrate: 10,
+ maxbitrate: 10,
+ delivery: [1],
+ playbackmethod: [2],
+ api: [1, 2],
+ linearity: 1,
+ playerSize: [640, 480]
+ }
},
sizes: [
[640, 480]
@@ -163,6 +180,99 @@ const BID_RESPONSE_VIDEO_OUTSTREAM = {
}
};
+const NATIVE_REQUEST = [{
+ adUnitCode: 'native_300x250',
+ code: '/19968336/prebid_native_example_1',
+ bidId: '12345',
+ sizes: [
+ [300, 250]
+ ],
+ mediaTypes: {
+ native: {
+ sendTargetingKeys: false,
+ title: {
+ required: true,
+ len: 140
+ },
+ image: {
+ required: true,
+ sizes: [300, 250]
+ },
+ icon: {
+ required: false,
+ sizes: [50, 50]
+ },
+ sponsoredBy: {
+ required: true
+ },
+ body: {
+ required: true
+ },
+ clickUrl: {
+ required: false
+ },
+ privacyLink: {
+ required: false
+ },
+ cta: {
+ required: false
+ },
+ rating: {
+ required: false
+ },
+ likes: {
+ required: false
+ },
+ downloads: {
+ required: false
+ },
+ price: {
+ required: false
+ },
+ salePrice: {
+ required: false
+ },
+ phone: {
+ required: false
+ },
+ address: {
+ required: false
+ },
+ desc2: {
+ required: false
+ },
+ displayUrl: {
+ required: false
+ }
+ }
+ },
+ bidder: 'smilewanted',
+ params: {
+ zoneId: 4,
+ },
+ requestId: 'request_abcd1234',
+ ortb2Imp: {
+ ext: {
+ tid: 'trans_abcd1234',
+ }
+ },
+}];
+
+const BID_RESPONSE_NATIVE = {
+ body: {
+ cpm: 3,
+ width: 300,
+ height: 250,
+ creativeId: 'crea_sw_1',
+ currency: 'EUR',
+ isNetCpm: true,
+ ttl: 300,
+ ad: '{"link":{"url":"https://www.smilewanted.com"},"assets":[{"id":0,"required":1,"title":{"len":50}},{"id":1,"required":1,"img":{"type":3,"w":150,"h":50,"ext":{"aspectratios":["2:1"]}}},{"id":2,"required":0,"img":{"type":1,"w":50,"h":50,"ext":{"aspectratios":["2:1"]}}},{"id":3,"required":1,"data":{"type":1,"value":"Smilewanted sponsor"}},{"id":4,"required":1,"data":{"type":2,"value":"Smilewanted Description"}}]}',
+ cSyncUrl: 'https://csync.smilewanted.com',
+ formatTypeSw: 'native'
+ }
+};
+
// Default params with optional ones
describe('smilewantedBidAdapterTests', function () {
it('SmileWanted - Verify build request', function () {
@@ -195,6 +305,23 @@ describe('smilewantedBidAdapterTests', function () {
expect(requestVideoInstreamContent.sizes[0]).to.have.property('w').and.to.equal(640);
expect(requestVideoInstreamContent.sizes[0]).to.have.property('h').and.to.equal(480);
expect(requestVideoInstreamContent).to.have.property('transactionId').and.to.not.equal(null).and.to.not.be.undefined;
+ expect(requestVideoInstreamContent).to.have.property('videoParams');
+ expect(requestVideoInstreamContent.videoParams).to.have.property('context').and.to.equal('instream').and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('mimes').to.be.an('array').that.include('video/mp4').and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('minduration').and.to.equal(0).and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('maxduration').and.to.equal(120).and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('protocols').to.be.an('array').that.include.members([1, 2, 3, 4, 5, 6, 7, 8]).and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('startdelay').and.to.equal(0).and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('placement').and.to.equal(1).and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('skip').and.to.equal(1).and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('skipafter').and.to.equal(10).and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('minbitrate').and.to.equal(10).and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('maxbitrate').and.to.equal(10).and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('delivery').to.be.an('array').that.include(1).and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('playbackmethod').to.be.an('array').that.include(2).and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('api').to.be.an('array').that.include.members([1, 2]).and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('linearity').and.to.equal(1).and.to.not.be.undefined;
+ expect(requestVideoInstreamContent.videoParams).to.have.property('playerSize').to.be.an('array').that.include.members([640, 480]).and.to.not.be.undefined;
const requestVideoOutstream = spec.buildRequests(VIDEO_OUTSTREAM_REQUEST);
expect(requestVideoOutstream[0]).to.have.property('url').and.to.equal('https://prebid.smilewanted.com');
@@ -206,6 +333,39 @@ describe('smilewantedBidAdapterTests', function () {
expect(requestVideoOutstreamContent.sizes[0]).to.have.property('w').and.to.equal(640);
expect(requestVideoOutstreamContent.sizes[0]).to.have.property('h').and.to.equal(480);
expect(requestVideoOutstreamContent).to.have.property('transactionId').and.to.not.equal(null).and.to.not.be.undefined;
+
+ const requestNative = spec.buildRequests(NATIVE_REQUEST);
+ expect(requestNative[0]).to.have.property('url').and.to.equal('https://prebid.smilewanted.com');
+ expect(requestNative[0]).to.have.property('method').and.to.equal('POST');
+ const requestNativeContent = JSON.parse(requestNative[0].data);
+ expect(requestNativeContent).to.have.property('zoneId').and.to.equal(4);
+ expect(requestNativeContent).to.have.property('currencyCode').and.to.equal('EUR');
+ expect(requestNativeContent).to.have.property('sizes');
+ expect(requestNativeContent.sizes[0]).to.have.property('w').and.to.equal(300);
+ expect(requestNativeContent.sizes[0]).to.have.property('h').and.to.equal(250);
+ expect(requestNativeContent).to.have.property('transactionId').and.to.not.equal(null).and.to.not.be.undefined;
+ expect(requestNativeContent).to.have.property('context').and.to.equal('native').and.to.not.be.undefined;
+ expect(requestNativeContent).to.have.property('nativeParams');
+ expect(requestNativeContent.nativeParams.title).to.have.property('required').and.to.equal(true);
+ expect(requestNativeContent.nativeParams.title).to.have.property('len').and.to.equal(140);
+ expect(requestNativeContent.nativeParams.image).to.have.property('required').and.to.equal(true);
+ expect(requestNativeContent.nativeParams.image).to.have.property('sizes').to.be.an('array').that.include.members([300, 250]).and.to.not.be.undefined;
+ expect(requestNativeContent.nativeParams.icon).to.have.property('required').and.to.equal(false);
+ expect(requestNativeContent.nativeParams.icon).to.have.property('sizes').to.be.an('array').that.include.members([50, 50]).and.to.not.be.undefined;
+ expect(requestNativeContent.nativeParams.sponsoredBy).to.have.property('required').and.to.equal(true);
+ expect(requestNativeContent.nativeParams.body).to.have.property('required').and.to.equal(true);
+ expect(requestNativeContent.nativeParams.clickUrl).to.have.property('required').and.to.equal(false);
+ expect(requestNativeContent.nativeParams.privacyLink).to.have.property('required').and.to.equal(false);
+ expect(requestNativeContent.nativeParams.cta).to.have.property('required').and.to.equal(false);
+ expect(requestNativeContent.nativeParams.rating).to.have.property('required').and.to.equal(false);
+ expect(requestNativeContent.nativeParams.likes).to.have.property('required').and.to.equal(false);
+ expect(requestNativeContent.nativeParams.downloads).to.have.property('required').and.to.equal(false);
+ expect(requestNativeContent.nativeParams.price).to.have.property('required').and.to.equal(false);
+ expect(requestNativeContent.nativeParams.salePrice).to.have.property('required').and.to.equal(false);
+ expect(requestNativeContent.nativeParams.phone).to.have.property('required').and.to.equal(false);
+ expect(requestNativeContent.nativeParams.address).to.have.property('required').and.to.equal(false);
+ expect(requestNativeContent.nativeParams.desc2).to.have.property('required').and.to.equal(false);
+ expect(requestNativeContent.nativeParams.displayUrl).to.have.property('required').and.to.equal(false);
});
it('SmileWanted - Verify build request with referrer', function () {
@@ -337,7 +497,7 @@ describe('smilewantedBidAdapterTests', function () {
}).to.not.throw();
});
- it('SmileWanted - Verify parse response - Video Oustream', function () {
+ it('SmileWanted - Verify parse response - Video Outstream', function () {
const request = spec.buildRequests(VIDEO_OUTSTREAM_REQUEST);
const bids = spec.interpretResponse(BID_RESPONSE_VIDEO_OUTSTREAM, request[0]);
expect(bids).to.have.lengthOf(1);
@@ -360,6 +520,28 @@ describe('smilewantedBidAdapterTests', function () {
}).to.not.throw();
});
+ it('SmileWanted - Verify parse response - Native', function () {
+ const request = spec.buildRequests(NATIVE_REQUEST);
+ const bids = spec.interpretResponse(BID_RESPONSE_NATIVE, request[0]);
+ expect(bids).to.have.lengthOf(1);
+ const bid = bids[0];
+ expect(bid.cpm).to.equal(3);
+ expect(bid.ad).to.equal('{"link":{"url":"https://www.smilewanted.com"},"assets":[{"id":0,"required":1,"title":{"len":50}},{"id":1,"required":1,"img":{"type":3,"w":150,"h":50,"ext":{"aspectratios":["2:1"]}}},{"id":2,"required":0,"img":{"type":1,"w":50,"h":50,"ext":{"aspectratios":["2:1"]}}},{"id":3,"required":1,"data":{"type":1,"value":"Smilewanted sponsor"}},{"id":4,"required":1,"data":{"type":2,"value":"Smilewanted Description"}}]}');
+ expect(bid.width).to.equal(300);
+ expect(bid.height).to.equal(250);
+ expect(bid.creativeId).to.equal('crea_sw_1');
+ expect(bid.currency).to.equal('EUR');
+ expect(bid.netRevenue).to.equal(true);
+ expect(bid.ttl).to.equal(300);
+ expect(bid.requestId).to.equal(NATIVE_REQUEST[0].bidId);
+
+ expect(function () {
+ spec.interpretResponse(BID_RESPONSE_NATIVE, {
+ data: 'invalid Json'
+ })
+ }).to.not.throw();
+ });
+
it('SmileWanted - Verify bidder code', function () {
expect(spec.code).to.equal('smilewanted');
});
diff --git a/test/spec/modules/snigelBidAdapter_spec.js b/test/spec/modules/snigelBidAdapter_spec.js
index 7fe2387ca6c..828aec9491c 100644
--- a/test/spec/modules/snigelBidAdapter_spec.js
+++ b/test/spec/modules/snigelBidAdapter_spec.js
@@ -2,6 +2,8 @@ import {expect} from 'chai';
import {spec} from 'modules/snigelBidAdapter.js';
import {config} from 'src/config.js';
import {isValid} from 'src/adapters/bidderFactory.js';
+import {registerActivityControl} from 'src/activities/rules.js';
+import {ACTIVITY_ACCESS_DEVICE} from 'src/activities/activities.js';
const BASE_BID_REQUEST = {
adUnitCode: 'top_leaderboard',
@@ -23,6 +25,7 @@ const BASE_BIDDER_REQUEST = {
auctionId: 'test',
bidderRequestId: 'test',
refererInfo: {
+ page: 'https://localhost',
canonicalUrl: 'https://localhost',
},
};
@@ -343,5 +346,67 @@ describe('snigelBidAdapter', function () {
expect(sync).to.have.property('url');
expect(sync.url).to.equal(`https://somesyncurl?gdpr=1&gdpr_consent=${DUMMY_GDPR_CONSENT_STRING}`);
});
+
+ it('should omit session ID if no device access', function() {
+ const bidderRequest = makeBidderRequest();
+ const unregisterRule = registerActivityControl(ACTIVITY_ACCESS_DEVICE, 'denyAccess', () => {
+ return {allow: false, reason: 'no consent'};
+ });
+
+ try {
+ const request = spec.buildRequests([], bidderRequest);
+ expect(request).to.have.property('data');
+ const data = JSON.parse(request.data);
+ expect(data.sessionId).to.be.undefined;
+ } finally {
+ unregisterRule();
+ }
+ });
+
+ it('should determine full GDPR consent correctly', function () {
+ const baseBidderRequest = makeBidderRequest({
+ gdprConsent: {
+ gdprApplies: true,
+ vendorData: {
+ purpose: {
+ consents: {1: true, 2: true, 3: true, 4: true, 5: true},
+ },
+ vendor: {
+ consents: {[spec.gvlid]: true},
+ }
+ },
+ }
+ });
+ let request = spec.buildRequests([], baseBidderRequest);
+ expect(request).to.have.property('data');
+ let data = JSON.parse(request.data);
+ expect(data.gdprConsent).to.be.true;
+
+ let bidderRequest = {...baseBidderRequest, ...{gdprConsent: {vendorData: {purpose: {consents: {1: false}}}}}};
+ request = spec.buildRequests([], bidderRequest);
+ expect(request).to.have.property('data');
+ data = JSON.parse(request.data);
+ expect(data.gdprConsent).to.be.false;
+
+ bidderRequest = {...baseBidderRequest, ...{gdprConsent: {vendorData: {vendor: {consents: {[spec.gvlid]: false}}}}}};
+ request = spec.buildRequests([], bidderRequest);
+ expect(request).to.have.property('data');
+ data = JSON.parse(request.data);
+ expect(data.gdprConsent).to.be.false;
+ });
+
+ it('should increment auction counter upon every request', function() {
+ const bidderRequest = makeBidderRequest({});
+
+ let request = spec.buildRequests([], bidderRequest);
+ expect(request).to.have.property('data');
+ let data = JSON.parse(request.data);
+ const previousCounter = data.counter;
+
+ request = spec.buildRequests([], bidderRequest);
+ expect(request).to.have.property('data');
+ data = JSON.parse(request.data);
+ expect(data.counter).to.equal(previousCounter + 1);
+ });
});
});
diff --git a/test/spec/modules/sonobiAnalyticsAdapter_spec.js b/test/spec/modules/sonobiAnalyticsAdapter_spec.js
index 76ff88836d4..ed8ccd22eea 100644
--- a/test/spec/modules/sonobiAnalyticsAdapter_spec.js
+++ b/test/spec/modules/sonobiAnalyticsAdapter_spec.js
@@ -1,4 +1,4 @@
-import sonobiAnalytics from 'modules/sonobiAnalyticsAdapter.js';
+import sonobiAnalytics, {DEFAULT_EVENT_URL} from 'modules/sonobiAnalyticsAdapter.js';
import {expect} from 'chai';
import {server} from 'test/mocks/xhr.js';
let events = require('src/events');
@@ -76,8 +76,8 @@ describe('Sonobi Prebid Analytic', function () {
events.emit(constants.EVENTS.AUCTION_END, {auctionId: '13', bidsReceived: [bid]});
clock.tick(5000);
- expect(server.requests).to.have.length(1);
- expect(JSON.parse(server.requests[0].requestBody)).to.have.length(3)
+ const req = server.requests.find(req => req.url.indexOf(DEFAULT_EVENT_URL) !== -1);
+ expect(JSON.parse(req.requestBody)).to.have.length(3)
done();
});
});
diff --git a/test/spec/modules/sonobiBidAdapter_spec.js b/test/spec/modules/sonobiBidAdapter_spec.js
index 164aa06d9b7..c7f954cfdcf 100644
--- a/test/spec/modules/sonobiBidAdapter_spec.js
+++ b/test/spec/modules/sonobiBidAdapter_spec.js
@@ -1,8 +1,8 @@
-import {expect} from 'chai';
-import {_getPlatform, spec} from 'modules/sonobiBidAdapter.js';
-import {newBidder} from 'src/adapters/bidderFactory.js';
-import {userSync} from '../../../src/userSync.js';
-import {config} from 'src/config.js';
+import { expect } from 'chai';
+import { _getPlatform, spec } from 'modules/sonobiBidAdapter.js';
+import { newBidder } from 'src/adapters/bidderFactory.js';
+import { userSync } from '../../../src/userSync.js';
+import { config } from 'src/config.js';
import * as gptUtils from '../../../libraries/gptUtils/gptUtils.js';
describe('SonobiBidAdapter', function () {
@@ -359,7 +359,9 @@ describe('SonobiBidAdapter', function () {
'page': 'https://example.com',
'stack': ['https://example.com']
},
- uspConsent: 'someCCPAString'
+ uspConsent: 'someCCPAString',
+ ortb2: {}
+
};
it('should set fpd if there is any data in ortb2', function () {
@@ -493,6 +495,12 @@ describe('SonobiBidAdapter', function () {
expect(bidRequests.data.hfa).to.equal('hfakey')
})
+ it('should return a properly formatted request with experianRtidData and exexperianRtidKeypKey omitted from fpd', function () {
+ const bidRequests = spec.buildRequests(bidRequest, bidderRequests)
+ expect(bidRequests.data.fpd.indexOf('experianRtidData')).to.equal(-1);
+ expect(bidRequests.data.fpd.indexOf('exexperianRtidKeypKey')).to.equal(-1);
+ });
+
it('should return null if there is nothing to bid on', function () {
const bidRequests = spec.buildRequests([{ params: {} }], bidderRequests)
expect(bidRequests).to.equal(null);
diff --git a/test/spec/modules/sovrnAnalyticsAdapter_spec.js b/test/spec/modules/sovrnAnalyticsAdapter_spec.js
index 68552eb3d8a..d0363eab144 100644
--- a/test/spec/modules/sovrnAnalyticsAdapter_spec.js
+++ b/test/spec/modules/sovrnAnalyticsAdapter_spec.js
@@ -12,8 +12,8 @@ let constants = require('src/constants.json');
/**
* Emit analytics events
- * @param {array} eventArr - array of objects to define the events that will fire
- * @param {object} eventObj - key is eventType, value is event
+ * @param {Array} eventType - array of objects to define the events that will fire
+ * @param {object} event - key is eventType, value is event
* @param {string} auctionId - the auction id to attached to the events
*/
function emitEvent(eventType, event, auctionId) {
diff --git a/test/spec/modules/sovrnBidAdapter_spec.js b/test/spec/modules/sovrnBidAdapter_spec.js
index 90913c6f130..274192d14a7 100644
--- a/test/spec/modules/sovrnBidAdapter_spec.js
+++ b/test/spec/modules/sovrnBidAdapter_spec.js
@@ -64,6 +64,29 @@ describe('sovrnBidAdapter', function() {
expect(spec.isBidRequestValid(bidRequest)).to.equal(false)
})
+
+ it('should return true when minduration is not passed', function() {
+ const width = 300
+ const height = 250
+ const mimes = ['video/mp4', 'application/javascript']
+ const protocols = [2, 5]
+ const maxduration = 60
+ const startdelay = 0
+ const videoBidRequest = {
+ ...baseBidRequest,
+ mediaTypes: {
+ video: {
+ mimes,
+ protocols,
+ playerSize: [[width, height], [360, 240]],
+ maxduration,
+ startdelay
+ }
+ }
+ }
+
+ expect(spec.isBidRequestValid(videoBidRequest)).to.equal(true)
+ })
})
describe('buildRequests', function () {
@@ -295,6 +318,41 @@ describe('sovrnBidAdapter', function() {
expect(data.regs.ext['us_privacy']).to.equal(bidderRequest.uspConsent)
})
+ it('should not set coppa when coppa is undefined', function () {
+ const bidderRequest = {
+ ...baseBidderRequest,
+ bidderCode: 'sovrn',
+ auctionId: '1d1a030790a475',
+ bidderRequestId: '22edbae2733bf6',
+ timeout: 3000,
+ bids: [baseBidRequest],
+ gdprConsent: {
+ consentString: 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A==',
+ gdprApplies: true
+ },
+ }
+ const {regs} = JSON.parse(spec.buildRequests([baseBidRequest], bidderRequest).data)
+ expect(regs.coppa).to.be.undefined
+ })
+
+ it('should set coppa to 1 when coppa is provided with value true', function () {
+ const bidderRequest = {
+ ...baseBidderRequest,
+ ortb2: {
+ regs: {
+ coppa: true
+ }
+ },
+ bidderCode: 'sovrn',
+ auctionId: '1d1a030790a475',
+ bidderRequestId: '22edbae2733bf6',
+ timeout: 3000,
+ bids: [baseBidRequest]
+ }
+ const {regs} = JSON.parse(spec.buildRequests([baseBidRequest], bidderRequest).data)
+ expect(regs.coppa).to.equal(1)
+ })
+
it('should send gpp info in OpenRTB 2.6 location when gppConsent defined', function () {
const bidderRequest = {
...baseBidderRequest,
@@ -472,6 +530,45 @@ describe('sovrnBidAdapter', function() {
expect(impression.bidfloor).to.equal(2.00)
})
+ it('floor should be undefined if there is no floor from the floor module and params', function() {
+ const floorBid = {
+ ...baseBidRequest
+ }
+ floorBid.params = {
+ tagid: 1234
+ }
+ const request = spec.buildRequests([floorBid], baseBidderRequest)
+ const impression = JSON.parse(request.data).imp[0]
+
+ expect(impression.bidfloor).to.be.undefined
+ })
+ it('floor should be undefined if there is incorrect floor value from the floor module', function() {
+ const floorBid = {
+ ...baseBidRequest,
+ getFloor: () => ({currency: 'USD', floor: 'incorrect_value'}),
+ params: {
+ tagid: 1234
+ }
+ }
+ const request = spec.buildRequests([floorBid], baseBidderRequest)
+ const impression = JSON.parse(request.data).imp[0]
+
+ expect(impression.bidfloor).to.be.undefined
+ })
+ it('floor should be undefined if there is incorrect floor value from the params', function() {
+ const floorBid = {
+ ...baseBidRequest,
+ getFloor: () => ({})
+ }
+ floorBid.params = {
+ tagid: 1234,
+ bidfloor: 'incorrect_value'
+ }
+ const request = spec.buildRequests([floorBid], baseBidderRequest)
+ const impression = JSON.parse(request.data).imp[0]
+
+ expect(impression.bidfloor).to.be.undefined
+ })
describe('First Party Data', function () {
it('should provide first party data if provided', function() {
const ortb2 = {
diff --git a/test/spec/modules/sparteoBidAdapter_spec.js b/test/spec/modules/sparteoBidAdapter_spec.js
new file mode 100644
index 00000000000..293f7da30a1
--- /dev/null
+++ b/test/spec/modules/sparteoBidAdapter_spec.js
@@ -0,0 +1,467 @@
+import {expect} from 'chai';
+import { deepClone, mergeDeep } from 'src/utils';
+import {spec as adapter} from 'modules/sparteoBidAdapter';
+
+const CURRENCY = 'EUR';
+const TTL = 60;
+const HTTP_METHOD = 'POST';
+const REQUEST_URL = 'https://bid.sparteo.com/auction';
+const USER_SYNC_URL_IFRAME = 'https://sync.sparteo.com/sync/iframe.html?from=prebidjs';
+
+const VALID_BID_BANNER = {
+ bidder: 'sparteo',
+ bidId: '1a2b3c4d',
+ adUnitCode: 'id-1234',
+ params: {
+ networkId: '1234567a-eb1b-1fae-1d23-e1fbaef234cf',
+ formats: ['corner']
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [1, 1]
+ ]
+ }
+ }
+};
+
+const VALID_BID_VIDEO = {
+ bidder: 'sparteo',
+ bidId: '5e6f7g8h',
+ adUnitCode: 'id-5678',
+ params: {
+ networkId: '1234567a-eb1b-1fae-1d23-e1fbaef234cf'
+ },
+ mediaTypes: {
+ video: {
+ playerSize: [640, 360],
+ protocols: [1, 2, 3, 4, 5, 6, 7, 8],
+ api: [1, 2],
+ mimes: ['video/mp4'],
+ skip: 1,
+ startdelay: 0,
+ placement: 1,
+ linearity: 1,
+ minduration: 5,
+ maxduration: 30,
+ context: 'instream'
+ }
+ },
+ ortb2Imp: {
+ ext: {
+ pbadslot: 'video'
+ }
+ }
+};
+
+const VALID_REQUEST_BANNER = {
+ method: HTTP_METHOD,
+ url: REQUEST_URL,
+ data: {
+ 'imp': [{
+ 'id': '1a2b3c4d',
+ 'banner': {
+ 'format': [{
+ 'h': 1,
+ 'w': 1
+ }],
+ 'topframe': 0
+ },
+ 'ext': {
+ 'sparteo': {
+ 'params': {
+ 'networkId': '1234567a-eb1b-1fae-1d23-e1fbaef234cf',
+ 'formats': ['corner']
+ }
+ }
+ }
+ }],
+ 'site': {
+ 'publisher': {
+ 'ext': {
+ 'params': {
+ 'networkId': '1234567a-eb1b-1fae-1d23-e1fbaef234cf'
+ }
+ }
+ }
+ },
+ 'test': 0
+ }
+};
+
+const VALID_REQUEST_VIDEO = {
+ method: HTTP_METHOD,
+ url: REQUEST_URL,
+ data: {
+ 'imp': [{
+ 'id': '5e6f7g8h',
+ 'video': {
+ 'w': 640,
+ 'h': 360,
+ 'protocols': [1, 2, 3, 4, 5, 6, 7, 8],
+ 'api': [1, 2],
+ 'mimes': ['video/mp4'],
+ 'skip': 1,
+ 'startdelay': 0,
+ 'placement': 1,
+ 'linearity': 1,
+ 'minduration': 5,
+ 'maxduration': 30,
+ },
+ 'ext': {
+ 'pbadslot': 'video',
+ 'sparteo': {
+ 'params': {
+ 'networkId': '1234567a-eb1b-1fae-1d23-e1fbaef234cf'
+ }
+ }
+ }
+ }],
+ 'site': {
+ 'publisher': {
+ 'ext': {
+ 'params': {
+ 'networkId': '1234567a-eb1b-1fae-1d23-e1fbaef234cf'
+ }
+ }
+ }
+ },
+ 'test': 0
+ }
+};
+
+const VALID_REQUEST = {
+ method: HTTP_METHOD,
+ url: REQUEST_URL,
+ data: {
+ 'imp': [{
+ 'id': '1a2b3c4d',
+ 'banner': {
+ 'format': [{
+ 'h': 1,
+ 'w': 1
+ }],
+ 'topframe': 0
+ },
+ 'ext': {
+ 'sparteo': {
+ 'params': {
+ 'networkId': '1234567a-eb1b-1fae-1d23-e1fbaef234cf',
+ 'formats': ['corner']
+ }
+ }
+ }
+ }, {
+ 'id': '5e6f7g8h',
+ 'video': {
+ 'w': 640,
+ 'h': 360,
+ 'protocols': [1, 2, 3, 4, 5, 6, 7, 8],
+ 'api': [1, 2],
+ 'mimes': ['video/mp4'],
+ 'skip': 1,
+ 'startdelay': 0,
+ 'placement': 1,
+ 'linearity': 1,
+ 'minduration': 5,
+ 'maxduration': 30,
+ },
+ 'ext': {
+ 'pbadslot': 'video',
+ 'sparteo': {
+ 'params': {
+ 'networkId': '1234567a-eb1b-1fae-1d23-e1fbaef234cf'
+ }
+ }
+ }
+ }],
+ 'site': {
+ 'publisher': {
+ 'ext': {
+ 'params': {
+ 'networkId': '1234567a-eb1b-1fae-1d23-e1fbaef234cf'
+ }
+ }
+ }
+ },
+ 'test': 0
+ }
+};
+
+const BIDDER_REQUEST = {
+ bids: [VALID_BID_BANNER, VALID_BID_VIDEO]
+}
+
+const BIDDER_REQUEST_BANNER = {
+ bids: [VALID_BID_BANNER]
+}
+
+const BIDDER_REQUEST_VIDEO = {
+ bids: [VALID_BID_VIDEO]
+}
+
+describe('SparteoAdapter', function () {
+ describe('isBidRequestValid', function () {
+ describe('Check method return', function () {
+ it('should return true', function () {
+ expect(adapter.isBidRequestValid(VALID_BID_BANNER)).to.equal(true);
+ expect(adapter.isBidRequestValid(VALID_BID_VIDEO)).to.equal(true);
+ });
+
+ it('should return false because the networkId is missing', function () {
+ let wrongBid = deepClone(VALID_BID_BANNER);
+ delete wrongBid.params.networkId;
+
+ expect(adapter.isBidRequestValid(wrongBid)).to.equal(false);
+ });
+
+ it('should return false because the banner size is missing', function () {
+ let wrongBid = deepClone(VALID_BID_BANNER);
+
+ wrongBid.mediaTypes.banner.sizes = '123456';
+ expect(adapter.isBidRequestValid(wrongBid)).to.equal(false);
+
+ delete wrongBid.mediaTypes.banner.sizes;
+ expect(adapter.isBidRequestValid(wrongBid)).to.equal(false);
+ });
+
+ it('should return false because the video player size paramater is missing', function () {
+ let wrongBid = deepClone(VALID_BID_VIDEO);
+
+ wrongBid.mediaTypes.video.playerSize = '123456';
+ expect(adapter.isBidRequestValid(wrongBid)).to.equal(false);
+
+ delete wrongBid.mediaTypes.video.playerSize;
+ expect(adapter.isBidRequestValid(wrongBid)).to.equal(false);
+ });
+ });
+ });
+
+ describe('buildRequests', function () {
+ describe('Check method return', function () {
+ if (FEATURES.VIDEO) {
+ it('should return the right formatted requests', function() {
+ const request = adapter.buildRequests([VALID_BID_BANNER, VALID_BID_VIDEO], BIDDER_REQUEST);
+ delete request.data.id;
+
+ expect(request).to.deep.equal(VALID_REQUEST);
+ });
+ }
+
+ it('should return the right formatted banner requests', function() {
+ const request = adapter.buildRequests([VALID_BID_BANNER], BIDDER_REQUEST_BANNER);
+ delete request.data.id;
+
+ expect(request).to.deep.equal(VALID_REQUEST_BANNER);
+ });
+
+ if (FEATURES.VIDEO) {
+ it('should return the right formatted video requests', function() {
+ const request = adapter.buildRequests([VALID_BID_VIDEO], BIDDER_REQUEST_VIDEO);
+ delete request.data.id;
+
+ expect(request).to.deep.equal(VALID_REQUEST_VIDEO);
+ });
+ }
+
+ it('should return the right formatted request with endpoint test', function() {
+ let endpoint = 'https://bid-test.sparteo.com/auction';
+
+ let bids = mergeDeep(deepClone([VALID_BID_BANNER, VALID_BID_VIDEO]), {
+ params: {
+ endpoint: endpoint
+ }
+ });
+
+ let requests = mergeDeep(deepClone(VALID_REQUEST));
+
+ const request = adapter.buildRequests(bids, BIDDER_REQUEST);
+ requests.url = endpoint;
+ delete request.data.id;
+
+ expect(requests).to.deep.equal(requests);
+ });
+ });
+ });
+
+ describe('interpretResponse', function() {
+ describe('Check method return', function () {
+ it('should return the right formatted response', function() {
+ let response = {
+ body: {
+ 'id': '63f4d300-6896-4bdc-8561-0932f73148b1',
+ 'cur': 'EUR',
+ 'seatbid': [
+ {
+ 'seat': 'sparteo',
+ 'group': 0,
+ 'bid': [
+ {
+ 'id': 'cdbb6982-a269-40c7-84e5-04797f11d87a',
+ 'impid': '1a2b3c4d',
+ 'price': 4.5,
+ 'ext': {
+ 'prebid': {
+ 'type': 'banner'
+ }
+ },
+ 'adm': 'script',
+ 'crid': 'crid',
+ 'w': 1,
+ 'h': 1,
+ 'nurl': 'https://t.bidder.sparteo.com/img'
+ }
+ ]
+ }
+ ]
+ }
+ };
+
+ if (FEATURES.VIDEO) {
+ response.body.seatbid[0].bid.push({
+ 'id': 'cdbb6982-a269-40c7-84e5-04797f11d87b',
+ 'impid': '5e6f7g8h',
+ 'price': 5,
+ 'ext': {
+ 'prebid': {
+ 'type': 'video',
+ 'cache': {
+ 'vastXml': {
+ 'url': 'https://pbs.tet.com/cache?uuid=1234'
+ }
+ }
+ }
+ },
+ 'adm': 'tag',
+ 'crid': 'crid',
+ 'w': 640,
+ 'h': 480,
+ 'nurl': 'https://t.bidder.sparteo.com/img'
+ });
+ }
+
+ let formattedReponse = [
+ {
+ requestId: '1a2b3c4d',
+ seatBidId: 'cdbb6982-a269-40c7-84e5-04797f11d87a',
+ cpm: 4.5,
+ width: 1,
+ height: 1,
+ creativeId: 'crid',
+ creative_id: 'crid',
+ currency: CURRENCY,
+ netRevenue: true,
+ ttl: TTL,
+ mediaType: 'banner',
+ meta: {},
+ ad: 'script
'
+ }
+ ];
+
+ if (FEATURES.VIDEO) {
+ formattedReponse.push({
+ requestId: '5e6f7g8h',
+ seatBidId: 'cdbb6982-a269-40c7-84e5-04797f11d87b',
+ cpm: 5,
+ width: 640,
+ height: 480,
+ playerWidth: 640,
+ playerHeight: 360,
+ creativeId: 'crid',
+ creative_id: 'crid',
+ currency: CURRENCY,
+ netRevenue: true,
+ ttl: TTL,
+ mediaType: 'video',
+ meta: {},
+ nurl: 'https://t.bidder.sparteo.com/img',
+ vastUrl: 'https://pbs.tet.com/cache?uuid=1234',
+ vastXml: 'tag'
+ });
+ }
+
+ if (FEATURES.VIDEO) {
+ const request = adapter.buildRequests([VALID_BID_BANNER, VALID_BID_VIDEO], BIDDER_REQUEST);
+ expect(adapter.interpretResponse(response, request)).to.deep.equal(formattedReponse);
+ } else {
+ const request = adapter.buildRequests([VALID_BID_BANNER], BIDDER_REQUEST_BANNER);
+ expect(adapter.interpretResponse(response, request)).to.deep.equal(formattedReponse);
+ }
+ });
+ });
+ });
+
+ describe('onBidWon', function() {
+ describe('Check methods succeed', function () {
+ it('should not throw error', function() {
+ let bids = [
+ {
+ requestId: '1a2b3c4d',
+ seatBidId: 'cdbb6982-a269-40c7-84e5-04797f11d87a',
+ cpm: 4.5,
+ width: 1,
+ height: 1,
+ creativeId: 'crid',
+ creative_id: 'crid',
+ currency: CURRENCY,
+ netRevenue: true,
+ ttl: TTL,
+ mediaType: 'banner',
+ meta: {},
+ ad: 'script
',
+ nurl: [
+ 'win.domain.com'
+ ]
+ },
+ {
+ requestId: '2570',
+ seatBidId: 'cdbb6982-a269-40c7-84e5-04797f11d87b',
+ id: 'id-5678',
+ cpm: 5,
+ width: 640,
+ height: 480,
+ creativeId: 'crid',
+ currency: CURRENCY,
+ netRevenue: true,
+ ttl: TTL,
+ mediaType: 'video',
+ meta: {},
+ vastXml: 'vast xml',
+ nurl: [
+ 'win.domain2.com'
+ ]
+ }
+ ];
+
+ bids.forEach(function(bid) {
+ expect(adapter.onBidWon.bind(adapter, bid)).to.not.throw();
+ });
+ });
+ });
+ });
+
+ describe('getUserSyncs', function() {
+ describe('Check methods succeed', function () {
+ it('should return the sync url', function() {
+ const syncOptions = {
+ 'iframeEnabled': true,
+ 'pixelEnabled': false
+ };
+ const gdprConsent = {
+ gdprApplies: 1,
+ consentString: 'tcfv2'
+ };
+ const uspConsent = {
+ consentString: '1Y---'
+ };
+
+ const syncUrls = [{
+ type: 'iframe',
+ url: USER_SYNC_URL_IFRAME + '&gdpr=1&gdpr_consent=tcfv2&usp_consent=1Y---'
+ }];
+
+ expect(adapter.getUserSyncs(syncOptions, null, gdprConsent, uspConsent)).to.deep.equal(syncUrls);
+ });
+ });
+ });
+});
diff --git a/test/spec/modules/sspBCBidAdapter_spec.js b/test/spec/modules/sspBCBidAdapter_spec.js
index 71619424e4b..2f5fe104eb1 100644
--- a/test/spec/modules/sspBCBidAdapter_spec.js
+++ b/test/spec/modules/sspBCBidAdapter_spec.js
@@ -638,7 +638,7 @@ describe('SSPBC adapter', function () {
expect(adcode).to.be.a('string');
expect(adcode).to.contain('window.rekid');
expect(adcode).to.contain('window.mcad');
- expect(adcode).to.contain('window.gdpr');
+ expect(adcode).to.contain('window.tcString');
expect(adcode).to.contain('window.page');
expect(adcode).to.contain('window.requestPVID');
});
diff --git a/test/spec/modules/stnBidAdapter_spec.js b/test/spec/modules/stnBidAdapter_spec.js
new file mode 100644
index 00000000000..deba87baac2
--- /dev/null
+++ b/test/spec/modules/stnBidAdapter_spec.js
@@ -0,0 +1,625 @@
+import { expect } from 'chai';
+import { spec } from 'modules/stnBidAdapter.js';
+import { newBidder } from 'src/adapters/bidderFactory.js';
+import { config } from 'src/config.js';
+import { BANNER, VIDEO } from '../../../src/mediaTypes.js';
+import * as utils from 'src/utils.js';
+
+const ENDPOINT = 'https://hb.stngo.com/hb-multi';
+const TEST_ENDPOINT = 'https://hb.stngo.com/hb-multi-test';
+const TTL = 360;
+/* eslint no-console: ["error", { allow: ["log", "warn", "error"] }] */
+
+describe('stnAdapter', function () {
+ const adapter = newBidder(spec);
+
+ describe('inherited functions', function () {
+ it('exists and is a function', function () {
+ expect(adapter.callBids).to.exist.and.to.be.a('function');
+ });
+ });
+
+ describe('isBidRequestValid', function () {
+ const bid = {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [['640', '480']],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ }
+ };
+
+ it('should return true when required params are passed', function () {
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+
+ it('should return false when required params are not found', function () {
+ const newBid = Object.assign({}, bid);
+ delete newBid.params;
+ newBid.params = {
+ 'org': null
+ };
+ expect(spec.isBidRequestValid(newBid)).to.equal(false);
+ });
+ });
+
+ describe('buildRequests', function () {
+ const bidRequests = [
+ {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[640, 480]],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ },
+ 'bidId': '299ffc8cca0b87',
+ 'loop': 1,
+ 'bidderRequestId': '1144f487e563f9',
+ 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d',
+ 'mediaTypes': {
+ 'video': {
+ 'playerSize': [[640, 480]],
+ 'context': 'instream',
+ 'plcmt': 1
+ }
+ },
+ 'vastXml': '"
... "'
+ },
+ {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[300, 250]],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ },
+ 'bidId': '299ffc8cca0b87',
+ 'loop': 1,
+ 'bidderRequestId': '1144f487e563f9',
+ 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d',
+ 'mediaTypes': {
+ 'banner': {
+ }
+ },
+ 'ad': '"
"'
+ }
+ ];
+
+ const testModeBidRequests = [
+ {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [[640, 480]],
+ 'params': {
+ 'org': 'jdye8weeyirk00000001',
+ 'testMode': true
+ },
+ 'bidId': '299ffc8cca0b87',
+ 'loop': 2,
+ 'bidderRequestId': '1144f487e563f9',
+ 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d',
+ }
+ ];
+
+ const bidderRequest = {
+ bidderCode: 'stn',
+ }
+ const placementId = '12345678';
+ const api = [1, 2];
+ const mimes = ['application/javascript', 'video/mp4', 'video/quicktime'];
+ const protocols = [2, 3, 5, 6];
+
+ it('sends the placementId to ENDPOINT via POST', function () {
+ bidRequests[0].params.placementId = placementId;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].placementId).to.equal(placementId);
+ });
+
+ it('sends the plcmt to ENDPOINT via POST', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].plcmt).to.equal(1);
+ });
+
+ it('sends the is_wrapper parameter to ENDPOINT via POST', function() {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('is_wrapper');
+ expect(request.data.params.is_wrapper).to.equal(false);
+ });
+
+ it('sends bid request to ENDPOINT via POST', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.url).to.equal(ENDPOINT);
+ expect(request.method).to.equal('POST');
+ });
+
+ it('sends bid request to TEST ENDPOINT via POST', function () {
+ const request = spec.buildRequests(testModeBidRequests, bidderRequest);
+ expect(request.url).to.equal(TEST_ENDPOINT);
+ expect(request.method).to.equal('POST');
+ });
+
+ it('should send the correct bid Id', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].bidId).to.equal('299ffc8cca0b87');
+ });
+
+ it('should send the correct supported api array', function () {
+ bidRequests[0].mediaTypes.video.api = api;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].api).to.be.an('array');
+ expect(request.data.bids[0].api).to.eql([1, 2]);
+ });
+
+ it('should send the correct mimes array', function () {
+ bidRequests[1].mediaTypes.banner.mimes = mimes;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[1].mimes).to.be.an('array');
+ expect(request.data.bids[1].mimes).to.eql(['application/javascript', 'video/mp4', 'video/quicktime']);
+ });
+
+ it('should send the correct protocols array', function () {
+ bidRequests[0].mediaTypes.video.protocols = protocols;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].protocols).to.be.an('array');
+ expect(request.data.bids[0].protocols).to.eql([2, 3, 5, 6]);
+ });
+
+ it('should send the correct sizes array', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].sizes).to.be.an('array');
+ expect(request.data.bids[0].sizes).to.equal(bidRequests[0].sizes)
+ expect(request.data.bids[1].sizes).to.be.an('array');
+ expect(request.data.bids[1].sizes).to.equal(bidRequests[1].sizes)
+ });
+
+ it('should send the correct media type', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].mediaType).to.equal(VIDEO)
+ expect(request.data.bids[1].mediaType).to.equal(BANNER)
+ });
+
+ it('should send the correct currency in bid request', function () {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.params = {
+ 'currency': 'EUR'
+ };
+ const expectedCurrency = bid.params.currency;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0].currency).to.equal(expectedCurrency);
+ });
+
+ it('should respect syncEnabled option', function() {
+ config.setConfig({
+ userSync: {
+ syncEnabled: false,
+ filterSettings: {
+ all: {
+ bidders: '*',
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('cs_method');
+ });
+
+ it('should respect "iframe" filter settings', function () {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ iframe: {
+ bidders: [spec.code],
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'iframe');
+ });
+
+ it('should respect "all" filter settings', function () {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ all: {
+ bidders: [spec.code],
+ filter: 'include'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'iframe');
+ });
+
+ it('should send the pixel user sync param if userSync is enabled and no "iframe" or "all" configs are present', function () {
+ config.resetConfig();
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('cs_method', 'pixel');
+ });
+
+ it('should respect total exclusion', function() {
+ config.setConfig({
+ userSync: {
+ syncEnabled: true,
+ filterSettings: {
+ image: {
+ bidders: [spec.code],
+ filter: 'exclude'
+ },
+ iframe: {
+ bidders: [spec.code],
+ filter: 'exclude'
+ }
+ }
+ }
+ });
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('cs_method');
+ });
+
+ it('should have us_privacy param if usPrivacy is available in the bidRequest', function () {
+ const bidderRequestWithUSP = Object.assign({uspConsent: '1YNN'}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithUSP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('us_privacy', '1YNN');
+ });
+
+ it('should have an empty us_privacy param if usPrivacy is missing in the bidRequest', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('us_privacy');
+ });
+
+ it('should not send the gdpr param if gdprApplies is false in the bidRequest', function () {
+ const bidderRequestWithGDPR = Object.assign({gdprConsent: {gdprApplies: false}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('gdpr');
+ expect(request.data.params).to.not.have.property('gdpr_consent');
+ });
+
+ it('should send the gdpr param if gdprApplies is true in the bidRequest', function () {
+ const bidderRequestWithGDPR = Object.assign({gdprConsent: {gdprApplies: true, consentString: 'test-consent-string'}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('gdpr', true);
+ expect(request.data.params).to.have.property('gdpr_consent', 'test-consent-string');
+ });
+
+ it('should not send the gpp param if gppConsent is false in the bidRequest', function () {
+ const bidderRequestWithGPP = Object.assign({gppConsent: false}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGPP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.not.have.property('gpp');
+ expect(request.data.params).to.not.have.property('gpp_sid');
+ });
+
+ it('should send the gpp param if gppConsent is true in the bidRequest', function () {
+ const bidderRequestWithGPP = Object.assign({gppConsent: {gppString: 'test-consent-string', applicableSections: [7]}}, bidderRequest);
+ const request = spec.buildRequests(bidRequests, bidderRequestWithGPP);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('gpp', 'test-consent-string');
+ expect(request.data.params.gpp_sid[0]).to.be.equal(7);
+ });
+
+ it('should have schain param if it is available in the bidRequest', () => {
+ const schain = {
+ ver: '1.0',
+ complete: 1,
+ nodes: [{ asi: 'indirectseller.com', sid: '00001', hp: 1 }],
+ };
+ bidRequests[0].schain = schain;
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.params).to.be.an('object');
+ expect(request.data.params).to.have.property('schain', '1.0,1!indirectseller.com,00001,1,,,');
+ });
+
+ it('should set flooPrice to getFloor.floor value if it is greater than params.floorPrice', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.getFloor = () => {
+ return {
+ currency: 'USD',
+ floor: 3.32
+ }
+ }
+ bid.params.floorPrice = 0.64;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0]).to.be.an('object');
+ expect(request.data.bids[0]).to.have.property('floorPrice', 3.32);
+ });
+
+ it('should set floorPrice to params.floorPrice value if it is greater than getFloor.floor', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.getFloor = () => {
+ return {
+ currency: 'USD',
+ floor: 0.8
+ }
+ }
+ bid.params.floorPrice = 1.5;
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0]).to.be.an('object');
+ expect(request.data.bids[0]).to.have.property('floorPrice', 1.5);
+ });
+
+ it('should check sua param in bid request', function() {
+ const sua = {
+ 'platform': {
+ 'brand': 'macOS',
+ 'version': ['12', '4', '0']
+ },
+ 'browsers': [
+ {
+ 'brand': 'Chromium',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Google Chrome',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Not;A=Brand',
+ 'version': [ '99', '0', '0', '0' ]
+ }
+ ],
+ 'mobile': 0,
+ 'model': '',
+ 'bitness': '64',
+ 'architecture': 'x86'
+ }
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.ortb2 = {
+ 'device': {
+ 'sua': {
+ 'platform': {
+ 'brand': 'macOS',
+ 'version': [ '12', '4', '0' ]
+ },
+ 'browsers': [
+ {
+ 'brand': 'Chromium',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Google Chrome',
+ 'version': [ '106', '0', '5249', '119' ]
+ },
+ {
+ 'brand': 'Not;A=Brand',
+ 'version': [ '99', '0', '0', '0' ]
+ }
+ ],
+ 'mobile': 0,
+ 'model': '',
+ 'bitness': '64',
+ 'architecture': 'x86'
+ }
+ }
+ }
+ const requestWithSua = spec.buildRequests([bid], bidderRequest);
+ const data = requestWithSua.data;
+ expect(data.bids[0].sua).to.exist;
+ expect(data.bids[0].sua).to.deep.equal(sua);
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].sua).to.not.exist;
+ });
+
+ describe('COPPA Param', function() {
+ it('should set coppa equal 0 in bid request if coppa is set to false', function() {
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+ expect(request.data.bids[0].coppa).to.be.equal(0);
+ });
+
+ it('should set coppa equal 1 in bid request if coppa is set to true', function() {
+ const bid = utils.deepClone(bidRequests[0]);
+ bid.ortb2 = {
+ 'regs': {
+ 'coppa': true,
+ }
+ };
+ const request = spec.buildRequests([bid], bidderRequest);
+ expect(request.data.bids[0].coppa).to.be.equal(1);
+ });
+ });
+ });
+
+ describe('interpretResponse', function () {
+ const response = {
+ params: {
+ currency: 'USD',
+ netRevenue: true,
+ },
+ bids: [{
+ cpm: 12.5,
+ vastXml: '
',
+ width: 640,
+ height: 480,
+ requestId: '21e12606d47ba7',
+ adomain: ['abc.com'],
+ mediaType: VIDEO
+ },
+ {
+ cpm: 12.5,
+ ad: '"
"',
+ width: 300,
+ height: 250,
+ requestId: '21e12606d47ba7',
+ adomain: ['abc.com'],
+ mediaType: BANNER
+ }]
+ };
+
+ const expectedVideoResponse = {
+ requestId: '21e12606d47ba7',
+ cpm: 12.5,
+ currency: 'USD',
+ width: 640,
+ height: 480,
+ ttl: TTL,
+ creativeId: '21e12606d47ba7',
+ netRevenue: true,
+ nurl: 'http://example.com/win/1234',
+ mediaType: VIDEO,
+ meta: {
+ mediaType: VIDEO,
+ advertiserDomains: ['abc.com']
+ },
+ vastXml: '
',
+ };
+
+ const expectedBannerResponse = {
+ requestId: '21e12606d47ba7',
+ cpm: 12.5,
+ currency: 'USD',
+ width: 640,
+ height: 480,
+ ttl: TTL,
+ creativeId: '21e12606d47ba7',
+ netRevenue: true,
+ nurl: 'http://example.com/win/1234',
+ mediaType: BANNER,
+ meta: {
+ mediaType: BANNER,
+ advertiserDomains: ['abc.com']
+ },
+ ad: '"
"'
+ };
+
+ it('should get correct bid response', function () {
+ const result = spec.interpretResponse({ body: response });
+ expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedVideoResponse));
+ expect(Object.keys(result[1])).to.deep.equal(Object.keys(expectedBannerResponse));
+ });
+
+ it('video type should have vastXml key', function () {
+ const result = spec.interpretResponse({ body: response });
+ expect(result[0].vastXml).to.equal(expectedVideoResponse.vastXml)
+ });
+
+ it('banner type should have ad key', function () {
+ const result = spec.interpretResponse({ body: response });
+ expect(result[1].ad).to.equal(expectedBannerResponse.ad)
+ });
+ })
+
+ describe('getUserSyncs', function() {
+ const imageSyncResponse = {
+ body: {
+ params: {
+ userSyncPixels: [
+ 'https://image-sync-url.test/1',
+ 'https://image-sync-url.test/2',
+ 'https://image-sync-url.test/3'
+ ]
+ }
+ }
+ };
+
+ const iframeSyncResponse = {
+ body: {
+ params: {
+ userSyncURL: 'https://iframe-sync-url.test'
+ }
+ }
+ };
+
+ it('should register all img urls from the response', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: true }, [imageSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/1'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/2'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/3'
+ }
+ ]);
+ });
+
+ it('should register the iframe url from the response', function() {
+ const syncs = spec.getUserSyncs({ iframeEnabled: true }, [iframeSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'iframe',
+ url: 'https://iframe-sync-url.test'
+ }
+ ]);
+ });
+
+ it('should register both image and iframe urls from the responses', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: true, iframeEnabled: true }, [iframeSyncResponse, imageSyncResponse]);
+ expect(syncs).to.deep.equal([
+ {
+ type: 'iframe',
+ url: 'https://iframe-sync-url.test'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/1'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/2'
+ },
+ {
+ type: 'image',
+ url: 'https://image-sync-url.test/3'
+ }
+ ]);
+ });
+
+ it('should handle an empty response', function() {
+ const syncs = spec.getUserSyncs({ iframeEnabled: true }, []);
+ expect(syncs).to.deep.equal([]);
+ });
+
+ it('should handle when user syncs are disabled', function() {
+ const syncs = spec.getUserSyncs({ pixelEnabled: false }, [imageSyncResponse]);
+ expect(syncs).to.deep.equal([]);
+ });
+ })
+
+ describe('onBidWon', function() {
+ beforeEach(function() {
+ sinon.stub(utils, 'triggerPixel');
+ });
+ afterEach(function() {
+ utils.triggerPixel.restore();
+ });
+
+ it('Should trigger pixel if bid nurl', function() {
+ const bid = {
+ 'bidder': spec.code,
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [['640', '480']],
+ 'nurl': 'http://example.com/win/1234',
+ 'params': {
+ 'org': 'jdye8weeyirk00000001'
+ }
+ };
+
+ spec.onBidWon(bid);
+ expect(utils.triggerPixel.callCount).to.equal(1)
+ })
+ })
+});
diff --git a/test/spec/modules/stroeerCoreBidAdapter_spec.js b/test/spec/modules/stroeerCoreBidAdapter_spec.js
index 2ed5f80f152..66e0da6ddf8 100644
--- a/test/spec/modules/stroeerCoreBidAdapter_spec.js
+++ b/test/spec/modules/stroeerCoreBidAdapter_spec.js
@@ -844,6 +844,39 @@ describe('stroeerCore bid adapter', function () {
assert.nestedPropertyVal(bid, 'ban.fp.cur', 'EUR');
assert.deepNestedPropertyVal(bid, 'ban.fp.siz', [{w: 160, h: 60, p: 2.7}]);
});
+
+ it('should add the DSA signals', () => {
+ const bidReq = buildBidderRequest();
+ const dsa = {
+ dsarequired: 3,
+ pubrender: 0,
+ datatopub: 2,
+ transparency: [
+ {
+ domain: 'testplatform.com',
+ dsaparams: [1],
+ },
+ {
+ domain: 'testdomain.com',
+ dsaparams: [1, 2]
+ }
+ ]
+ }
+ const ortb2 = {
+ regs: {
+ ext: {
+ dsa
+ }
+ }
+ }
+
+ bidReq.ortb2 = utils.deepClone(ortb2);
+
+ const serverRequestInfo = spec.buildRequests(bidReq.bids, bidReq);
+ const sentOrtb2 = serverRequestInfo.data.ortb2;
+
+ assert.deepEqual(sentOrtb2, ortb2);
+ });
});
});
});
@@ -882,13 +915,32 @@ describe('stroeerCore bid adapter', function () {
assertStandardFieldsOnVideoBid(videoBidResponse, 'bid1', '
video ', 800, 250, 4);
})
- it('should add data to meta object', () => {
+ it('should add advertiser domains to meta object', () => {
const response = buildBidderResponse();
response.bids[0] = Object.assign(response.bids[0], {adomain: ['website.org', 'domain.com']});
const result = spec.interpretResponse({body: response});
- assert.deepPropertyVal(result[0], 'meta', {advertiserDomains: ['website.org', 'domain.com']});
- // nothing provided for the second bid
- assert.deepPropertyVal(result[1], 'meta', {advertiserDomains: undefined});
+ assert.deepPropertyVal(result[0].meta, 'advertiserDomains', ['website.org', 'domain.com']);
+ assert.propertyVal(result[1].meta, 'advertiserDomains', undefined);
+ });
+
+ it('should add dsa info to meta object', () => {
+ const dsaResponse = {
+ behalf: 'AdvertiserA',
+ paid: 'AdvertiserB',
+ transparency: [{
+ domain: 'dspexample.com',
+ dsaparams: [1, 2],
+ }],
+ adrender: 1
+ };
+
+ const response = buildBidderResponse();
+ response.bids[0] = Object.assign(response.bids[0], {dsa: utils.deepClone(dsaResponse)});
+
+ const result = spec.interpretResponse({body: response});
+
+ assert.deepPropertyVal(result[0].meta, 'dsa', dsaResponse);
+ assert.propertyVal(result[1].meta, 'dsa', undefined);
});
});
diff --git a/test/spec/modules/stvBidAdapter_spec.js b/test/spec/modules/stvBidAdapter_spec.js
index 41f29cced34..3ef865ed2f1 100644
--- a/test/spec/modules/stvBidAdapter_spec.js
+++ b/test/spec/modules/stvBidAdapter_spec.js
@@ -71,6 +71,24 @@ describe('stvAdapter', function() {
'hp': 1
}
]
+ },
+ 'userId': {
+ 'id5id': {
+ 'uid': '1234',
+ 'ext': {
+ 'linkType': 'abc'
+ }
+ },
+ 'netId': '2345',
+ 'uid2': {
+ 'id': '3456',
+ },
+ 'sharedid': {
+ 'id': '4567',
+ },
+ 'idl_env': '5678',
+ 'criteoId': '6789',
+ 'utiq': '7890',
}
},
{
@@ -84,7 +102,27 @@ describe('stvAdapter', function() {
],
'bidId': '30b31c1838de1e2',
'bidderRequestId': '22edbae2733bf62',
- 'auctionId': '1d1a030790a476'
+ 'auctionId': '1d1a030790a476',
+ 'userId': { // with other utiq variant
+ 'id5id': {
+ 'uid': '1234',
+ 'ext': {
+ 'linkType': 'abc'
+ }
+ },
+ 'netId': '2345',
+ 'uid2': {
+ 'id': '3456',
+ },
+ 'sharedid': {
+ 'id': '4567',
+ },
+ 'idl_env': '5678',
+ 'criteoId': '6789',
+ 'utiq': {
+ 'id': '7890'
+ },
+ }
}, {
'bidder': 'stv',
'params': {
@@ -181,7 +219,7 @@ describe('stvAdapter', function() {
expect(request1.method).to.equal('GET');
expect(request1.url).to.equal(ENDPOINT_URL);
let data = request1.data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid').replace(/pbver=.*?&/g, 'pbver=test&');
- expect(data).to.equal('_f=html&alternative=prebid_js&_ps=6682&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e1&pbver=test&schain=1.0,0!reseller.com,aaaaa,1,BidRequest4,,,&pfilter%5Bfloorprice%5D=1000000&pfilter%5Bgeo%5D%5Bcountry%5D=DE&gdpr_consent=BOJ%2FP2HOJ%2FP2HABABMAAAAAZ%2BA%3D%3D&gdpr=true&bcat=IAB2%2CIAB4&dvt=desktop&pbcode=testDiv1&media_types%5Bbanner%5D=300x250');
+ expect(data).to.equal('_f=html&alternative=prebid_js&_ps=6682&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e1&pbver=test&schain=1.0,0!reseller.com,aaaaa,1,BidRequest4,,&uids=id5%3A1234,id5_linktype%3Aabc,netid%3A2345,uid2%3A3456,sharedid%3A4567,liverampid%3A5678,criteoid%3A6789,utiq%3A7890&pfilter%5Bfloorprice%5D=1000000&pfilter%5Bgeo%5D%5Bcountry%5D=DE&gdpr_consent=BOJ%2FP2HOJ%2FP2HABABMAAAAAZ%2BA%3D%3D&gdpr=true&bcat=IAB2%2CIAB4&dvt=desktop&pbcode=testDiv1&media_types%5Bbanner%5D=300x250');
});
var request2 = spec.buildRequests([bidRequests[1]], bidderRequest)[0];
@@ -189,7 +227,7 @@ describe('stvAdapter', function() {
expect(request2.method).to.equal('GET');
expect(request2.url).to.equal(ENDPOINT_URL);
let data = request2.data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid').replace(/pbver=.*?&/g, 'pbver=test&');
- expect(data).to.equal('_f=html&alternative=prebid_js&_ps=101&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e2&pbver=test&gdpr_consent=BOJ%2FP2HOJ%2FP2HABABMAAAAAZ%2BA%3D%3D&gdpr=true&prebidDevMode=1&media_types%5Bbanner%5D=300x250');
+ expect(data).to.equal('_f=html&alternative=prebid_js&_ps=101&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e2&pbver=test&uids=id5%3A1234,id5_linktype%3Aabc,netid%3A2345,uid2%3A3456,sharedid%3A4567,liverampid%3A5678,criteoid%3A6789,utiq%3A7890&gdpr_consent=BOJ%2FP2HOJ%2FP2HABABMAAAAAZ%2BA%3D%3D&gdpr=true&prebidDevMode=1&media_types%5Bbanner%5D=300x250');
});
// Without gdprConsent
diff --git a/test/spec/modules/taboolaBidAdapter_spec.js b/test/spec/modules/taboolaBidAdapter_spec.js
index 16bbb525ee7..ca09fbbbcc9 100644
--- a/test/spec/modules/taboolaBidAdapter_spec.js
+++ b/test/spec/modules/taboolaBidAdapter_spec.js
@@ -1,11 +1,15 @@
import {expect} from 'chai';
-import {spec, internal, END_POINT_URL, userData} from 'modules/taboolaBidAdapter.js';
+import {spec, internal, END_POINT_URL, userData, EVENT_ENDPOINT} from 'modules/taboolaBidAdapter.js';
import {config} from '../../../src/config'
import * as utils from '../../../src/utils'
import {server} from '../../mocks/xhr'
describe('Taboola Adapter', function () {
let sandbox, hasLocalStorage, cookiesAreEnabled, getDataFromLocalStorage, localStorageIsEnabled, getCookie, commonBidRequest;
+ const COOKIE_KEY = 'trc_cookie_storage';
+ const TGID_COOKIE_KEY = 't_gid';
+ const TGID_PT_COOKIE_KEY = 't_pt_gid';
+ const TBLA_ID_COOKIE_KEY = 'tbla_id';
beforeEach(() => {
sandbox = sinon.sandbox.create();
@@ -113,6 +117,50 @@ describe('Taboola Adapter', function () {
});
});
+ describe('onTimeout', function () {
+ it('onTimeout exist as a function', () => {
+ expect(spec.onTimeout).to.exist.and.to.be.a('function');
+ });
+ it('should send timeout', function () {
+ const timeoutData = [{
+ bidder: 'taboola',
+ bidId: 'da43860a-4644-442a-b5e0-93f268cf8d19',
+ params: [{
+ publisherId: 'publisherId'
+ }],
+ adUnitCode: 'adUnit-code',
+ timeout: 3000,
+ auctionId: '12a34b56c'
+ }]
+ spec.onTimeout(timeoutData);
+ expect(server.requests[0].method).to.equal('POST');
+ expect(server.requests[0].url).to.equal(EVENT_ENDPOINT + '/timeout');
+ expect(JSON.parse(server.requests[0].requestBody)).to.deep.equal(timeoutData);
+ });
+ });
+
+ describe('onBidderError', function () {
+ it('onBidderError exist as a function', () => {
+ expect(spec.onBidderError).to.exist.and.to.be.a('function');
+ });
+ it('should send bidder error', function () {
+ const error = {
+ status: 204,
+ statusText: 'No Content'
+ };
+ const bidderRequest = {
+ bidder: 'taboola',
+ params: {
+ publisherId: 'publisherId'
+ }
+ }
+ spec.onBidderError({error, bidderRequest});
+ expect(server.requests[0].method).to.equal('POST');
+ expect(server.requests[0].url).to.equal(EVENT_ENDPOINT + '/bidError');
+ expect(JSON.parse(server.requests[0].requestBody)).to.deep.equal({error, bidderRequest});
+ });
+ });
+
describe('buildRequests', function () {
const defaultBidRequest = {
...createBidRequest(),
@@ -129,10 +177,10 @@ describe('Taboola Adapter', function () {
}
it('should build display request', function () {
+ const res = spec.buildRequests([defaultBidRequest], commonBidderRequest);
const expectedData = {
- id: 'mock-uuid',
'imp': [{
- 'id': 1,
+ 'id': res.data.imp[0].id,
'banner': {
format: [{
w: displayBidRequestParams.sizes[0][0],
@@ -149,6 +197,8 @@ describe('Taboola Adapter', function () {
'bidfloorcur': 'USD',
'ext': {}
}],
+ id: 'mock-uuid',
+ 'test': 0,
'site': {
'id': commonBidRequest.params.publisherId,
'name': commonBidRequest.params.publisherId,
@@ -168,13 +218,15 @@ describe('Taboola Adapter', function () {
'ext': {},
},
'regs': {'coppa': 0, 'ext': {}},
- 'ext': {}
+ 'ext': {
+ 'prebid': {
+ 'version': '$prebid.version$'
+ }
+ }
};
- const res = spec.buildRequests([defaultBidRequest], commonBidderRequest);
-
expect(res.url).to.equal(`${END_POINT_URL}?publisher=${commonBidRequest.params.publisherId}`);
- expect(res.data).to.deep.equal(JSON.stringify(expectedData));
+ expect(JSON.stringify(res.data)).to.deep.equal(JSON.stringify(expectedData));
});
it('should pass optional parameters in request', function () {
@@ -189,9 +241,8 @@ describe('Taboola Adapter', function () {
};
const res = spec.buildRequests([bidRequest], commonBidderRequest);
- const resData = JSON.parse(res.data);
- expect(resData.imp[0].bidfloor).to.deep.equal(0.25);
- expect(resData.imp[0].bidfloorcur).to.deep.equal('EUR');
+ expect(res.data.imp[0].bidfloor).to.deep.equal(0.25);
+ expect(res.data.imp[0].bidfloorcur).to.deep.equal('EUR');
});
it('should pass bid floor', function () {
@@ -206,9 +257,8 @@ describe('Taboola Adapter', function () {
}
};
const res = spec.buildRequests([bidRequest], commonBidderRequest);
- const resData = JSON.parse(res.data);
- expect(resData.imp[0].bidfloor).to.deep.equal(2.7);
- expect(resData.imp[0].bidfloorcur).to.deep.equal('USD');
+ expect(res.data.imp[0].bidfloor).to.deep.equal(2.7);
+ expect(res.data.imp[0].bidfloorcur).to.deep.equal('USD');
});
it('should pass bid floor even if it is a bid floor param', function () {
@@ -228,9 +278,8 @@ describe('Taboola Adapter', function () {
}
};
const res = spec.buildRequests([bidRequest], commonBidderRequest);
- const resData = JSON.parse(res.data);
- expect(resData.imp[0].bidfloor).to.deep.equal(2.7);
- expect(resData.imp[0].bidfloorcur).to.deep.equal('USD');
+ expect(res.data.imp[0].bidfloor).to.deep.equal(2.7);
+ expect(res.data.imp[0].bidfloorcur).to.deep.equal('USD');
});
it('should pass impression position', function () {
@@ -244,8 +293,7 @@ describe('Taboola Adapter', function () {
};
const res = spec.buildRequests([bidRequest], commonBidderRequest);
- const resData = JSON.parse(res.data);
- expect(resData.imp[0].banner.pos).to.deep.equal(2);
+ expect(res.data.imp[0].banner.pos).to.deep.equal(2);
});
it('should pass gpid if configured', function () {
@@ -261,8 +309,23 @@ describe('Taboola Adapter', function () {
};
const res = spec.buildRequests([bidRequest], commonBidderRequest);
- const resData = JSON.parse(res.data);
- expect(resData.imp[0].ext.gpid).to.deep.equal('/homepage/#1');
+ expect(res.data.imp[0].ext.gpid).to.deep.equal('/homepage/#1');
+ });
+
+ it('should pass new parameter to imp ext', function () {
+ const ortb2Imp = {
+ ext: {
+ example: 'example'
+ }
+ }
+ const bidRequest = {
+ ...defaultBidRequest,
+ ortb2Imp: ortb2Imp,
+ params: {...commonBidRequest.params}
+ };
+
+ const res = spec.buildRequests([bidRequest], commonBidderRequest);
+ expect(res.data.imp[0].ext.example).to.deep.equal('example');
});
it('should pass bidder timeout', function () {
@@ -271,8 +334,25 @@ describe('Taboola Adapter', function () {
timeout: 500
}
const res = spec.buildRequests([defaultBidRequest], bidderRequest);
- const resData = JSON.parse(res.data);
- expect(resData.tmax).to.equal(500);
+ expect(res.data.tmax).to.equal(500);
+ });
+
+ it('should pass bidder tmax as int', function () {
+ const bidderRequest = {
+ ...commonBidderRequest,
+ timeout: '500'
+ }
+ const res = spec.buildRequests([defaultBidRequest], bidderRequest);
+ expect(res.data.tmax).to.equal(500);
+ });
+
+ it('should pass bidder timeout as null', function () {
+ const bidderRequest = {
+ ...commonBidderRequest,
+ timeout: null
+ }
+ const res = spec.buildRequests([defaultBidRequest], bidderRequest);
+ expect(res.data.tmax).to.equal(undefined);
});
describe('first party data', function () {
@@ -286,10 +366,9 @@ describe('Taboola Adapter', function () {
}
}
const res = spec.buildRequests([defaultBidRequest], bidderRequest);
- const resData = JSON.parse(res.data);
- expect(resData.bcat).to.deep.equal(bidderRequest.ortb2.bcat)
- expect(resData.badv).to.deep.equal(bidderRequest.ortb2.badv)
- expect(resData.wlang).to.deep.equal(bidderRequest.ortb2.wlang)
+ expect(res.data.bcat).to.deep.equal(bidderRequest.ortb2.bcat)
+ expect(res.data.badv).to.deep.equal(bidderRequest.ortb2.badv)
+ expect(res.data.wlang).to.deep.equal(bidderRequest.ortb2.wlang)
});
it('should pass pageType if exists in ortb2', function () {
@@ -304,8 +383,44 @@ describe('Taboola Adapter', function () {
}
}
const res = spec.buildRequests([defaultBidRequest], bidderRequest);
- const resData = JSON.parse(res.data);
- expect(resData.ext.pageType).to.deep.equal(bidderRequest.ortb2.ext.data.pageType);
+ expect(res.data.ext.pageType).to.deep.equal(bidderRequest.ortb2.ext.data.pageType);
+ });
+
+ it('should pass additional parameter in request', function () {
+ const bidderRequest = {
+ ...commonBidderRequest,
+ ortb2: {
+ ext: {
+ example: 'example'
+ }
+ }
+ }
+ const res = spec.buildRequests([defaultBidRequest], bidderRequest);
+ expect(res.data.ext.example).to.deep.equal(bidderRequest.ortb2.ext.example);
+ });
+
+ it('should pass additional parameter in request for topics', function () {
+ const ortb2 = {
+ ...commonBidderRequest,
+ ortb2: {
+ user: {
+ data: {
+ segment: [
+ {
+ id: '243'
+ }
+ ],
+ name: 'pa.taboola.com',
+ ext: {
+ segclass: '4',
+ segtax: 601
+ }
+ }
+ }
+ }
+ }
+ const res = spec.buildRequests([defaultBidRequest], {...ortb2})
+ expect(res.data.user.data).to.deep.equal(ortb2.ortb2.user.data);
});
});
@@ -322,9 +437,8 @@ describe('Taboola Adapter', function () {
};
const res = spec.buildRequests([defaultBidRequest], bidderRequest)
- const resData = JSON.parse(res.data)
- expect(resData.user.ext.consent).to.equal('consentString')
- expect(resData.regs.ext.gdpr).to.equal(1)
+ expect(res.data.user.ext.consent).to.equal('consentString')
+ expect(res.data.regs.ext.gdpr).to.equal(1)
});
it('should pass GPP consent if exist in ortb2', function () {
@@ -336,9 +450,8 @@ describe('Taboola Adapter', function () {
}
const res = spec.buildRequests([defaultBidRequest], {...commonBidderRequest, ortb2})
- const resData = JSON.parse(res.data)
- expect(resData.regs.ext.gpp).to.equal('testGpp')
- expect(resData.regs.ext.gpp_sid).to.deep.equal([1, 2, 3])
+ expect(res.data.regs.ext.gpp).to.equal('testGpp')
+ expect(res.data.regs.ext.gpp_sid).to.deep.equal([1, 2, 3])
});
it('should pass us privacy consent', function () {
@@ -349,16 +462,14 @@ describe('Taboola Adapter', function () {
uspConsent: 'consentString'
}
const res = spec.buildRequests([defaultBidRequest], bidderRequest);
- const resData = JSON.parse(res.data);
- expect(resData.regs.ext.us_privacy).to.equal('consentString');
+ expect(res.data.regs.ext.us_privacy).to.equal('consentString');
});
it('should pass coppa consent', function () {
config.setConfig({coppa: true})
const res = spec.buildRequests([defaultBidRequest], commonBidderRequest)
- const resData = JSON.parse(res.data);
- expect(resData.regs.coppa).to.equal(1)
+ expect(res.data.regs.coppa).to.equal(1)
config.resetConfig()
});
@@ -375,8 +486,7 @@ describe('Taboola Adapter', function () {
timeout: 500
}
const res = spec.buildRequests([defaultBidRequest], bidderRequest);
- const resData = JSON.parse(res.data);
- expect(resData.user.buyeruid).to.equal(51525152);
+ expect(res.data.user.buyeruid).to.equal(51525152);
});
it('should get user id from cookie if local storage isn`t defined', function () {
@@ -390,9 +500,106 @@ describe('Taboola Adapter', function () {
...commonBidderRequest
};
const res = spec.buildRequests([defaultBidRequest], bidderRequest);
- const resData = JSON.parse(res.data);
+ expect(res.data.user.buyeruid).to.equal('12121212');
+ });
+
+ it('should get user id from cookie if local storage isn`t defined, only TGID_COOKIE_KEY exists', function () {
+ getDataFromLocalStorage.returns(51525152);
+ hasLocalStorage.returns(false);
+ localStorageIsEnabled.returns(false);
+ cookiesAreEnabled.returns(true);
+ getCookie.callsFake(function (cookieKey) {
+ if (cookieKey === COOKIE_KEY) {
+ return 'should:not:return:this';
+ }
+ if (cookieKey === TGID_COOKIE_KEY) {
+ return 'user:12121212';
+ }
+ return undefined;
+ });
+ const bidderRequest = {
+ ...commonBidderRequest
+ };
+ const res = spec.buildRequests([defaultBidRequest], bidderRequest);
+ expect(res.data.user.buyeruid).to.equal('user:12121212');
+ });
+
+ it('should get user id from cookie if local storage isn`t defined, only TGID_PT_COOKIE_KEY exists', function () {
+ getDataFromLocalStorage.returns(51525152);
+ hasLocalStorage.returns(false);
+ localStorageIsEnabled.returns(false);
+ cookiesAreEnabled.returns(true);
+ getCookie.callsFake(function (cookieKey) {
+ if (cookieKey === TGID_PT_COOKIE_KEY) {
+ return 'user:12121212';
+ }
+ return undefined;
+ });
+ const bidderRequest = {
+ ...commonBidderRequest
+ };
+ const res = spec.buildRequests([defaultBidRequest], bidderRequest);
+ expect(res.data.user.buyeruid).to.equal('user:12121212');
+ });
+
+ it('should get user id from cookie if local storage isn`t defined, only TBLA_ID_COOKIE_KEY exists', function () {
+ getDataFromLocalStorage.returns(51525152);
+ hasLocalStorage.returns(false);
+ localStorageIsEnabled.returns(false);
+ cookiesAreEnabled.returns(true);
+ getCookie.callsFake(function (cookieKey) {
+ if (cookieKey === TBLA_ID_COOKIE_KEY) {
+ return 'user:tbla:12121212';
+ }
+ return undefined;
+ });
+ const bidderRequest = {
+ ...commonBidderRequest
+ };
+ const res = spec.buildRequests([defaultBidRequest], bidderRequest);
+ expect(res.data.user.buyeruid).to.equal('user:tbla:12121212');
+ });
+
+ it('should get user id from cookie if local storage isn`t defined, all cookie keys exist', function () {
+ getDataFromLocalStorage.returns(51525152);
+ hasLocalStorage.returns(false);
+ localStorageIsEnabled.returns(false);
+ cookiesAreEnabled.returns(true);
+ getCookie.callsFake(function (cookieKey) {
+ if (cookieKey === COOKIE_KEY) {
+ return 'taboola%20global%3Auser-id=cookie:1';
+ }
+ if (cookieKey === TGID_COOKIE_KEY) {
+ return 'cookie:2';
+ }
+ if (cookieKey === TGID_PT_COOKIE_KEY) {
+ return 'cookie:3';
+ }
+ if (cookieKey === TBLA_ID_COOKIE_KEY) {
+ return 'cookie:4';
+ }
+ return undefined;
+ });
+ const bidderRequest = {
+ ...commonBidderRequest
+ };
+ const res = spec.buildRequests([defaultBidRequest], bidderRequest);
+ expect(res.data.user.buyeruid).to.equal('cookie:1');
+ });
+
+ it('should get user id from tgid cookie if local storage isn`t defined', function () {
+ getDataFromLocalStorage.returns(51525152);
+ hasLocalStorage.returns(false);
+ localStorageIsEnabled.returns(false);
+ cookiesAreEnabled.returns(true);
+ getCookie.returns('d966c5be-c49f-4f73-8cd1-37b6b5790653-tuct9f7bf10');
+
+ const bidderRequest = {
+ ...commonBidderRequest
+ };
+ const res = spec.buildRequests([defaultBidRequest], bidderRequest);
- expect(resData.user.buyeruid).to.equal('12121212');
+ expect(res.data.user.buyeruid).to.equal('d966c5be-c49f-4f73-8cd1-37b6b5790653-tuct9f7bf10');
});
it('should get user id from TRC if local storage and cookie isn`t defined', function () {
@@ -408,8 +615,7 @@ describe('Taboola Adapter', function () {
...commonBidderRequest
}
const res = spec.buildRequests([defaultBidRequest], bidderRequest);
- const resData = JSON.parse(res.data);
- expect(resData.user.buyeruid).to.equal(window.TRC.user_id);
+ expect(res.data.user.buyeruid).to.equal(window.TRC.user_id);
delete window.TRC;
});
@@ -422,8 +628,7 @@ describe('Taboola Adapter', function () {
...commonBidderRequest
}
const res = spec.buildRequests([defaultBidRequest], bidderRequest);
- const resData = JSON.parse(res.data);
- expect(resData.user.buyeruid).to.equal(0);
+ expect(res.data.user.buyeruid).to.equal(0);
});
it('should set buyeruid to be 0 if it`s a new user', function () {
@@ -431,13 +636,29 @@ describe('Taboola Adapter', function () {
...commonBidderRequest
}
const res = spec.buildRequests([defaultBidRequest], bidderRequest);
- const resData = JSON.parse(res.data);
- expect(resData.user.buyeruid).to.equal(0);
+ expect(res.data.user.buyeruid).to.equal(0);
});
});
})
describe('interpretResponse', function () {
+ const defaultBidRequest = {
+ ...createBidRequest(),
+ ...displayBidRequestParams,
+ };
+ const commonBidderRequest = {
+ bidderRequestId: 'mock-uuid',
+ refererInfo: {
+ page: 'https://example.com/ref',
+ ref: 'https://ref',
+ domain: 'example.com',
+ }
+ };
+ const bidderRequest = {
+ ...commonBidderRequest
+ };
+ const request = spec.buildRequests([defaultBidRequest], bidderRequest);
+
const serverResponse = {
body: {
'id': '49ffg4d58ef9a163a69fhgfghd4fad03621b9e036f24f7_15',
@@ -446,7 +667,7 @@ describe('Taboola Adapter', function () {
'bid': [
{
'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
- 'impid': '1',
+ 'impid': request.data.imp[0].id,
'price': 0.342068,
'adid': '2785119545551083381',
'adm': '\u003chtml\u003e\n\u003chead\u003e\n\u003cmeta charset\u003d"UTF-8"\u003e\n\u003cmeta http-equiv\u003d"Content-Type" content\u003d"text/html; charset\u003dutf-8"/\u003e\u003c/head\u003e\n\u003cbody style\u003d"margin: 0px; overflow:hidden;"\u003e \n\u003cscript type\u003d"text/javascript"\u003e\nwindow.tbl_trc_domain \u003d \u0027us-trc.taboola.com\u0027;\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({article:\u0027auto\u0027});\n!function (e, f, u, i) {\nif (!document.getElementById(i)){\ne.async \u003d 1;\ne.src \u003d u;\ne.id \u003d i;\nf.parentNode.insertBefore(e, f);\n}\n}(document.createElement(\u0027script\u0027),\ndocument.getElementsByTagName(\u0027script\u0027)[0],\n\u0027//cdn.taboola.com/libtrc/wattpad-placement-255/loader.js\u0027,\n\u0027tb_loader_script\u0027);\nif(window.performance \u0026\u0026 typeof window.performance.mark \u003d\u003d \u0027function\u0027)\n{window.performance.mark(\u0027tbl_ic\u0027);}\n\u003c/script\u003e\n\n\u003cdiv id\u003d"taboola-below-article-thumbnails" style\u003d"height: 250px; width: 300px;"\u003e\u003c/div\u003e\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({\nmode: \u0027Rbox_300x250_1x1\u0027,\ncontainer: \u0027taboola-below-article-thumbnails\u0027,\nplacement: \u0027wattpad.com_P18694_S257846_W300_H250_N1_TB\u0027,\ntarget_type: \u0027mix\u0027,\n"rtb-win":{ \nbi:\u002749ff4d58ef9a163a696d4fad03621b9e036f24f7_15\u0027,\ncu:\u0027USD\u0027,\nwp:\u0027${AUCTION_PRICE:BF}\u0027,\nwcb:\u0027~!audex-display-impression!~\u0027,\nrt:\u00271643227025284\u0027,\nrdc:\u0027us.taboolasyndication.com\u0027,\nti:\u00274212\u0027,\nex:\u0027MagniteSCoD\u0027,\nbs:\u0027xapi:257846:lvvSm6Ak7_wE\u0027,\nbp:\u002718694\u0027,\nbd:\u0027wattpad.com\u0027,\nsi:\u00279964\u0027\n} \n,\nrec: {"trc":{"si":"a69c7df43b2334f0aa337c37e2d80c21","sd":"v2_a69c7df43b2334f0aa337c37e2d80c21_3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD_1643227025_1643227025_CJS1tQEQ5NdWGPLA0d76xo-9ngEgASgEMCY4iegHQIroB0iB09kDUKPPB1gAYABop-G2i_Hl-eVucAA","ui":"3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD","plc":"PHON","wi":"-643136642229425433","cc":"CA","route":"US:US:V","el2r":["bulk-metrics","debug","social","metrics","perf"],"uvpw":"1","pi":"1420260","cpb":"GNO629MGIJz__________wEqGXVzLnRhYm9vbGFzeW5kaWNhdGlvbi5jb20yC3RyYy1zY29kMTI5OIDwmrUMQInoB0iK6AdQgdPZA1ijzwdjCN3__________wEQ3f__________ARgjZGMI3AoQoBAYFmRjCNIDEOAGGAhkYwiWFBCcHBgYZGMI9AUQiwoYC2RjCNkUEPkcGB1kYwj0FBCeHRgfZGorNDlmZjRkNThlZjlhMTYzYTY5NmQ0ZmFkMDM2MjFiOWUwMzZmMjRmN18xNXgCgAHpbIgBrPvTxQE","dcga":{"pubConfigOverride":{"border-color":"black","font-weight":"bold","inherit-title-color":"true","module-name":"cta-lazy-module","enable-call-to-action-creative-component":"true","disable-cta-on-custom-module":"true"}},"tslt":{"p-video-overlay":{"cancel":"ץ××ר","goto":"×ĸ××ר ×××Ŗ"},"read-more":{"DEFAULT_CAPTION":"%D7%A7%D7%A8%D7%90%20%D7%A2%D7%95%D7%93"},"next-up":{"BTN_TEXT":"×קר×××Ē ××Ē××× ×××"},"time-ago":{"now":"×ĸ×׊××","today":"××××","yesterday":"××Ē×××","minutes":"××¤× × {0} ×ק××Ē","hour":"××¤× × ×Š×ĸ×","hours":"××¤× × {0} ׊×ĸ××Ē","days":"××¤× × {0} ××××"},"explore-more":{"TITLE_TEXT":"××׊××× ×קר××","POPUP_TEXT":"×× ×Ē×¤×Ą×¤×Ą× ××××× ××Ē ×קר×× ×ĸ×× ×Ē××× ××ĸ×××, ר××ĸ ××¤× × ×Š×Ē×ĸ×××"}},"evh":"-1964913910","vl":[{"ri":"185db6d274ce94b27caaabd9eed7915b","uip":"wattpad.com_P18694_S257846_W300_H250_N1_TB","ppb":"COIF","estimation_method":"EcpmEstimationMethodType_ESTIMATION","baseline_variant":"false","original_ecpm":"0.4750949889421463","v":[{"thumbnail":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg","all-thumbnails":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg!-#@1600x1000","origin":"default","thumb-size":"1600x1000","title":"Get Roofing Services At Prices You Can Afford In Edmonton","type":"text","published-date":"1641997069","branding-text":"Roofing Services | Search Ads","url":"https://inneth-conded.xyz/9ad2e613-8777-4fe7-9a52-386c88879289?site\u003dwattpad-placement-255\u0026site_id\u003d1420260\u0026title\u003dGet+Roofing+Services+At+Prices+You+Can+Afford+In+Edmonton\u0026platform\u003dSmartphone\u0026campaign_id\u003d15573949\u0026campaign_item_id\u003d3108610633\u0026thumbnail\u003dhttp%3A%2F%2Fcdn.taboola.com%2Flibtrc%2Fstatic%2Fthumbnails%2Fa2b272be514ca3ebe3f97a4a32a41db5.jpg\u0026cpc\u003d{cpc}\u0026click_id\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1\u0026tblci\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1#tblciGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1","duration":"0","sig":"328243c4127ff16e3fdcd7270bab908f6f3fc5b4c98d","item-id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","uploader":"","is-syndicated":"true","publisher":"search","id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","category":"home","views":"0","itp":[{"u":"https://trc.taboola.com/1326786/log/3/unip?en\u003dclickersusa","t":"c"}],"description":""}]}],"cpcud":{"upc":"0.0","upr":"0.0"}}}\n});\n\u003c/script\u003e\n\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({flush: true});\n\u003c/script\u003e\n\n\u003c/body\u003e\n\u003c/html\u003e',
@@ -471,14 +692,180 @@ describe('Taboola Adapter', function () {
}
};
- const request = {
- bids: [
- {
- ...commonBidRequest,
- ...displayBidRequestParams
+ const serverResponseWithPa = {
+ body: {
+ 'id': '49ffg4d58ef9a163a69fhgfghd4fad03621b9e036f24f7_15',
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
+ 'impid': request.data.imp[0].id,
+ 'price': 0.342068,
+ 'adid': '2785119545551083381',
+ 'adm': '\u003chtml\u003e\n\u003chead\u003e\n\u003cmeta charset\u003d"UTF-8"\u003e\n\u003cmeta http-equiv\u003d"Content-Type" content\u003d"text/html; charset\u003dutf-8"/\u003e\u003c/head\u003e\n\u003cbody style\u003d"margin: 0px; overflow:hidden;"\u003e \n\u003cscript type\u003d"text/javascript"\u003e\nwindow.tbl_trc_domain \u003d \u0027us-trc.taboola.com\u0027;\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({article:\u0027auto\u0027});\n!function (e, f, u, i) {\nif (!document.getElementById(i)){\ne.async \u003d 1;\ne.src \u003d u;\ne.id \u003d i;\nf.parentNode.insertBefore(e, f);\n}\n}(document.createElement(\u0027script\u0027),\ndocument.getElementsByTagName(\u0027script\u0027)[0],\n\u0027//cdn.taboola.com/libtrc/wattpad-placement-255/loader.js\u0027,\n\u0027tb_loader_script\u0027);\nif(window.performance \u0026\u0026 typeof window.performance.mark \u003d\u003d \u0027function\u0027)\n{window.performance.mark(\u0027tbl_ic\u0027);}\n\u003c/script\u003e\n\n\u003cdiv id\u003d"taboola-below-article-thumbnails" style\u003d"height: 250px; width: 300px;"\u003e\u003c/div\u003e\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({\nmode: \u0027Rbox_300x250_1x1\u0027,\ncontainer: \u0027taboola-below-article-thumbnails\u0027,\nplacement: \u0027wattpad.com_P18694_S257846_W300_H250_N1_TB\u0027,\ntarget_type: \u0027mix\u0027,\n"rtb-win":{ \nbi:\u002749ff4d58ef9a163a696d4fad03621b9e036f24f7_15\u0027,\ncu:\u0027USD\u0027,\nwp:\u0027${AUCTION_PRICE:BF}\u0027,\nwcb:\u0027~!audex-display-impression!~\u0027,\nrt:\u00271643227025284\u0027,\nrdc:\u0027us.taboolasyndication.com\u0027,\nti:\u00274212\u0027,\nex:\u0027MagniteSCoD\u0027,\nbs:\u0027xapi:257846:lvvSm6Ak7_wE\u0027,\nbp:\u002718694\u0027,\nbd:\u0027wattpad.com\u0027,\nsi:\u00279964\u0027\n} \n,\nrec: {"trc":{"si":"a69c7df43b2334f0aa337c37e2d80c21","sd":"v2_a69c7df43b2334f0aa337c37e2d80c21_3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD_1643227025_1643227025_CJS1tQEQ5NdWGPLA0d76xo-9ngEgASgEMCY4iegHQIroB0iB09kDUKPPB1gAYABop-G2i_Hl-eVucAA","ui":"3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD","plc":"PHON","wi":"-643136642229425433","cc":"CA","route":"US:US:V","el2r":["bulk-metrics","debug","social","metrics","perf"],"uvpw":"1","pi":"1420260","cpb":"GNO629MGIJz__________wEqGXVzLnRhYm9vbGFzeW5kaWNhdGlvbi5jb20yC3RyYy1zY29kMTI5OIDwmrUMQInoB0iK6AdQgdPZA1ijzwdjCN3__________wEQ3f__________ARgjZGMI3AoQoBAYFmRjCNIDEOAGGAhkYwiWFBCcHBgYZGMI9AUQiwoYC2RjCNkUEPkcGB1kYwj0FBCeHRgfZGorNDlmZjRkNThlZjlhMTYzYTY5NmQ0ZmFkMDM2MjFiOWUwMzZmMjRmN18xNXgCgAHpbIgBrPvTxQE","dcga":{"pubConfigOverride":{"border-color":"black","font-weight":"bold","inherit-title-color":"true","module-name":"cta-lazy-module","enable-call-to-action-creative-component":"true","disable-cta-on-custom-module":"true"}},"tslt":{"p-video-overlay":{"cancel":"ץ××ר","goto":"×ĸ××ר ×××Ŗ"},"read-more":{"DEFAULT_CAPTION":"%D7%A7%D7%A8%D7%90%20%D7%A2%D7%95%D7%93"},"next-up":{"BTN_TEXT":"×קר×××Ē ××Ē××× ×××"},"time-ago":{"now":"×ĸ×׊××","today":"××××","yesterday":"××Ē×××","minutes":"××¤× × {0} ×ק××Ē","hour":"××¤× × ×Š×ĸ×","hours":"××¤× × {0} ׊×ĸ××Ē","days":"××¤× × {0} ××××"},"explore-more":{"TITLE_TEXT":"××׊××× ×קר××","POPUP_TEXT":"×× ×Ē×¤×Ą×¤×Ą× ××××× ××Ē ×קר×× ×ĸ×× ×Ē××× ××ĸ×××, ר××ĸ ××¤× × ×Š×Ē×ĸ×××"}},"evh":"-1964913910","vl":[{"ri":"185db6d274ce94b27caaabd9eed7915b","uip":"wattpad.com_P18694_S257846_W300_H250_N1_TB","ppb":"COIF","estimation_method":"EcpmEstimationMethodType_ESTIMATION","baseline_variant":"false","original_ecpm":"0.4750949889421463","v":[{"thumbnail":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg","all-thumbnails":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg!-#@1600x1000","origin":"default","thumb-size":"1600x1000","title":"Get Roofing Services At Prices You Can Afford In Edmonton","type":"text","published-date":"1641997069","branding-text":"Roofing Services | Search Ads","url":"https://inneth-conded.xyz/9ad2e613-8777-4fe7-9a52-386c88879289?site\u003dwattpad-placement-255\u0026site_id\u003d1420260\u0026title\u003dGet+Roofing+Services+At+Prices+You+Can+Afford+In+Edmonton\u0026platform\u003dSmartphone\u0026campaign_id\u003d15573949\u0026campaign_item_id\u003d3108610633\u0026thumbnail\u003dhttp%3A%2F%2Fcdn.taboola.com%2Flibtrc%2Fstatic%2Fthumbnails%2Fa2b272be514ca3ebe3f97a4a32a41db5.jpg\u0026cpc\u003d{cpc}\u0026click_id\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1\u0026tblci\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1#tblciGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1","duration":"0","sig":"328243c4127ff16e3fdcd7270bab908f6f3fc5b4c98d","item-id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","uploader":"","is-syndicated":"true","publisher":"search","id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","category":"home","views":"0","itp":[{"u":"https://trc.taboola.com/1326786/log/3/unip?en\u003dclickersusa","t":"c"}],"description":""}]}],"cpcud":{"upc":"0.0","upr":"0.0"}}}\n});\n\u003c/script\u003e\n\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({flush: true});\n\u003c/script\u003e\n\n\u003c/body\u003e\n\u003c/html\u003e',
+ 'adomain': [
+ 'example.xyz'
+ ],
+ 'cid': '15744349',
+ 'crid': '278195503434041083381',
+ 'w': 300,
+ 'h': 250,
+ 'exp': 60,
+ 'lurl': 'http://us-trc.taboola.com/sample',
+ 'nurl': 'http://win.example.com/',
+
+ }
+ ],
+ 'seat': '14204545260'
+ }
+ ],
+ 'bidid': 'da43860a-4644-442a-b5e0-93f268cf8d19',
+ 'cur': 'USD',
+ 'ext': {
+ 'igbid': [
+ {
+ 'impid': request.data.imp[0].id,
+ 'igbuyer': [
+ {
+ 'origin': 'https://pa.taboola.com',
+ 'buyerdata': '{\"seller\":\"pa.taboola.com\",\"resolveToConfig\":false,\"perBuyerSignals\":{\"https://pa.taboola.com\":{\"country\":\"US\",\"route\":\"AM\",\"cct\":[0.02241223,-0.8686833,0.96153843],\"vct\":\"-1967600173\",\"ccv\":null,\"ect\":[-0.13584597,2.5825605],\"ri\":\"100fb73d4064bc\",\"vcv\":\"165229814\",\"ecv\":[-0.39882636,-0.05216012],\"publisher\":\"test-headerbidding\",\"platform\":\"DESK\"}},\"decisionLogicUrl\":\"https://pa.taboola.com/score/decisionLogic.js\",\"sellerTimeout\":100,\"interestGroupBuyers\":[\"https://pa.taboola.com\"],\"perBuyerTimeouts\":{\"*\":50}}'
+ }
+ ]
+ }
+ ]
}
- ]
- }
+ }
+ };
+
+ const serverResponseWithPartialPa = {
+ body: {
+ 'id': '49ffg4d58ef9a163a69fhgfghd4fad03621b9e036f24f7_15',
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
+ 'impid': request.data.imp[0].id,
+ 'price': 0.342068,
+ 'adid': '2785119545551083381',
+ 'adm': '\u003chtml\u003e\n\u003chead\u003e\n\u003cmeta charset\u003d"UTF-8"\u003e\n\u003cmeta http-equiv\u003d"Content-Type" content\u003d"text/html; charset\u003dutf-8"/\u003e\u003c/head\u003e\n\u003cbody style\u003d"margin: 0px; overflow:hidden;"\u003e \n\u003cscript type\u003d"text/javascript"\u003e\nwindow.tbl_trc_domain \u003d \u0027us-trc.taboola.com\u0027;\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({article:\u0027auto\u0027});\n!function (e, f, u, i) {\nif (!document.getElementById(i)){\ne.async \u003d 1;\ne.src \u003d u;\ne.id \u003d i;\nf.parentNode.insertBefore(e, f);\n}\n}(document.createElement(\u0027script\u0027),\ndocument.getElementsByTagName(\u0027script\u0027)[0],\n\u0027//cdn.taboola.com/libtrc/wattpad-placement-255/loader.js\u0027,\n\u0027tb_loader_script\u0027);\nif(window.performance \u0026\u0026 typeof window.performance.mark \u003d\u003d \u0027function\u0027)\n{window.performance.mark(\u0027tbl_ic\u0027);}\n\u003c/script\u003e\n\n\u003cdiv id\u003d"taboola-below-article-thumbnails" style\u003d"height: 250px; width: 300px;"\u003e\u003c/div\u003e\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({\nmode: \u0027Rbox_300x250_1x1\u0027,\ncontainer: \u0027taboola-below-article-thumbnails\u0027,\nplacement: \u0027wattpad.com_P18694_S257846_W300_H250_N1_TB\u0027,\ntarget_type: \u0027mix\u0027,\n"rtb-win":{ \nbi:\u002749ff4d58ef9a163a696d4fad03621b9e036f24f7_15\u0027,\ncu:\u0027USD\u0027,\nwp:\u0027${AUCTION_PRICE:BF}\u0027,\nwcb:\u0027~!audex-display-impression!~\u0027,\nrt:\u00271643227025284\u0027,\nrdc:\u0027us.taboolasyndication.com\u0027,\nti:\u00274212\u0027,\nex:\u0027MagniteSCoD\u0027,\nbs:\u0027xapi:257846:lvvSm6Ak7_wE\u0027,\nbp:\u002718694\u0027,\nbd:\u0027wattpad.com\u0027,\nsi:\u00279964\u0027\n} \n,\nrec: {"trc":{"si":"a69c7df43b2334f0aa337c37e2d80c21","sd":"v2_a69c7df43b2334f0aa337c37e2d80c21_3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD_1643227025_1643227025_CJS1tQEQ5NdWGPLA0d76xo-9ngEgASgEMCY4iegHQIroB0iB09kDUKPPB1gAYABop-G2i_Hl-eVucAA","ui":"3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD","plc":"PHON","wi":"-643136642229425433","cc":"CA","route":"US:US:V","el2r":["bulk-metrics","debug","social","metrics","perf"],"uvpw":"1","pi":"1420260","cpb":"GNO629MGIJz__________wEqGXVzLnRhYm9vbGFzeW5kaWNhdGlvbi5jb20yC3RyYy1zY29kMTI5OIDwmrUMQInoB0iK6AdQgdPZA1ijzwdjCN3__________wEQ3f__________ARgjZGMI3AoQoBAYFmRjCNIDEOAGGAhkYwiWFBCcHBgYZGMI9AUQiwoYC2RjCNkUEPkcGB1kYwj0FBCeHRgfZGorNDlmZjRkNThlZjlhMTYzYTY5NmQ0ZmFkMDM2MjFiOWUwMzZmMjRmN18xNXgCgAHpbIgBrPvTxQE","dcga":{"pubConfigOverride":{"border-color":"black","font-weight":"bold","inherit-title-color":"true","module-name":"cta-lazy-module","enable-call-to-action-creative-component":"true","disable-cta-on-custom-module":"true"}},"tslt":{"p-video-overlay":{"cancel":"ץ××ר","goto":"×ĸ××ר ×××Ŗ"},"read-more":{"DEFAULT_CAPTION":"%D7%A7%D7%A8%D7%90%20%D7%A2%D7%95%D7%93"},"next-up":{"BTN_TEXT":"×קר×××Ē ××Ē××× ×××"},"time-ago":{"now":"×ĸ×׊××","today":"××××","yesterday":"××Ē×××","minutes":"××¤× × {0} ×ק××Ē","hour":"××¤× × ×Š×ĸ×","hours":"××¤× × {0} ׊×ĸ××Ē","days":"××¤× × {0} ××××"},"explore-more":{"TITLE_TEXT":"××׊××× ×קר××","POPUP_TEXT":"×× ×Ē×¤×Ą×¤×Ą× ××××× ××Ē ×קר×× ×ĸ×× ×Ē××× ××ĸ×××, ר××ĸ ××¤× × ×Š×Ē×ĸ×××"}},"evh":"-1964913910","vl":[{"ri":"185db6d274ce94b27caaabd9eed7915b","uip":"wattpad.com_P18694_S257846_W300_H250_N1_TB","ppb":"COIF","estimation_method":"EcpmEstimationMethodType_ESTIMATION","baseline_variant":"false","original_ecpm":"0.4750949889421463","v":[{"thumbnail":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg","all-thumbnails":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg!-#@1600x1000","origin":"default","thumb-size":"1600x1000","title":"Get Roofing Services At Prices You Can Afford In Edmonton","type":"text","published-date":"1641997069","branding-text":"Roofing Services | Search Ads","url":"https://inneth-conded.xyz/9ad2e613-8777-4fe7-9a52-386c88879289?site\u003dwattpad-placement-255\u0026site_id\u003d1420260\u0026title\u003dGet+Roofing+Services+At+Prices+You+Can+Afford+In+Edmonton\u0026platform\u003dSmartphone\u0026campaign_id\u003d15573949\u0026campaign_item_id\u003d3108610633\u0026thumbnail\u003dhttp%3A%2F%2Fcdn.taboola.com%2Flibtrc%2Fstatic%2Fthumbnails%2Fa2b272be514ca3ebe3f97a4a32a41db5.jpg\u0026cpc\u003d{cpc}\u0026click_id\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1\u0026tblci\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1#tblciGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1","duration":"0","sig":"328243c4127ff16e3fdcd7270bab908f6f3fc5b4c98d","item-id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","uploader":"","is-syndicated":"true","publisher":"search","id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","category":"home","views":"0","itp":[{"u":"https://trc.taboola.com/1326786/log/3/unip?en\u003dclickersusa","t":"c"}],"description":""}]}],"cpcud":{"upc":"0.0","upr":"0.0"}}}\n});\n\u003c/script\u003e\n\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({flush: true});\n\u003c/script\u003e\n\n\u003c/body\u003e\n\u003c/html\u003e',
+ 'adomain': [
+ 'example.xyz'
+ ],
+ 'cid': '15744349',
+ 'crid': '278195503434041083381',
+ 'w': 300,
+ 'h': 250,
+ 'exp': 60,
+ 'lurl': 'http://us-trc.taboola.com/sample',
+ 'nurl': 'http://win.example.com/',
+
+ }
+ ],
+ 'seat': '14204545260'
+ }
+ ],
+ 'bidid': 'da43860a-4644-442a-b5e0-93f268cf8d19',
+ 'cur': 'USD',
+ 'ext': {
+ 'igbid': [
+ {
+ 'impid': request.data.imp[0].id,
+ 'igbuyer': [
+ {
+ 'origin': 'https://pa.taboola.com',
+ 'buyerdata': '{}'
+ }
+ ]
+ }
+ ]
+ }
+ }
+ };
+
+ const serverResponseWithWrongPa = {
+ body: {
+ 'id': '49ffg4d58ef9a163a69fhgfghd4fad03621b9e036f24f7_15',
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
+ 'impid': request.data.imp[0].id,
+ 'price': 0.342068,
+ 'adid': '2785119545551083381',
+ 'adm': '\u003chtml\u003e\n\u003chead\u003e\n\u003cmeta charset\u003d"UTF-8"\u003e\n\u003cmeta http-equiv\u003d"Content-Type" content\u003d"text/html; charset\u003dutf-8"/\u003e\u003c/head\u003e\n\u003cbody style\u003d"margin: 0px; overflow:hidden;"\u003e \n\u003cscript type\u003d"text/javascript"\u003e\nwindow.tbl_trc_domain \u003d \u0027us-trc.taboola.com\u0027;\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({article:\u0027auto\u0027});\n!function (e, f, u, i) {\nif (!document.getElementById(i)){\ne.async \u003d 1;\ne.src \u003d u;\ne.id \u003d i;\nf.parentNode.insertBefore(e, f);\n}\n}(document.createElement(\u0027script\u0027),\ndocument.getElementsByTagName(\u0027script\u0027)[0],\n\u0027//cdn.taboola.com/libtrc/wattpad-placement-255/loader.js\u0027,\n\u0027tb_loader_script\u0027);\nif(window.performance \u0026\u0026 typeof window.performance.mark \u003d\u003d \u0027function\u0027)\n{window.performance.mark(\u0027tbl_ic\u0027);}\n\u003c/script\u003e\n\n\u003cdiv id\u003d"taboola-below-article-thumbnails" style\u003d"height: 250px; width: 300px;"\u003e\u003c/div\u003e\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({\nmode: \u0027Rbox_300x250_1x1\u0027,\ncontainer: \u0027taboola-below-article-thumbnails\u0027,\nplacement: \u0027wattpad.com_P18694_S257846_W300_H250_N1_TB\u0027,\ntarget_type: \u0027mix\u0027,\n"rtb-win":{ \nbi:\u002749ff4d58ef9a163a696d4fad03621b9e036f24f7_15\u0027,\ncu:\u0027USD\u0027,\nwp:\u0027${AUCTION_PRICE:BF}\u0027,\nwcb:\u0027~!audex-display-impression!~\u0027,\nrt:\u00271643227025284\u0027,\nrdc:\u0027us.taboolasyndication.com\u0027,\nti:\u00274212\u0027,\nex:\u0027MagniteSCoD\u0027,\nbs:\u0027xapi:257846:lvvSm6Ak7_wE\u0027,\nbp:\u002718694\u0027,\nbd:\u0027wattpad.com\u0027,\nsi:\u00279964\u0027\n} \n,\nrec: {"trc":{"si":"a69c7df43b2334f0aa337c37e2d80c21","sd":"v2_a69c7df43b2334f0aa337c37e2d80c21_3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD_1643227025_1643227025_CJS1tQEQ5NdWGPLA0d76xo-9ngEgASgEMCY4iegHQIroB0iB09kDUKPPB1gAYABop-G2i_Hl-eVucAA","ui":"3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD","plc":"PHON","wi":"-643136642229425433","cc":"CA","route":"US:US:V","el2r":["bulk-metrics","debug","social","metrics","perf"],"uvpw":"1","pi":"1420260","cpb":"GNO629MGIJz__________wEqGXVzLnRhYm9vbGFzeW5kaWNhdGlvbi5jb20yC3RyYy1zY29kMTI5OIDwmrUMQInoB0iK6AdQgdPZA1ijzwdjCN3__________wEQ3f__________ARgjZGMI3AoQoBAYFmRjCNIDEOAGGAhkYwiWFBCcHBgYZGMI9AUQiwoYC2RjCNkUEPkcGB1kYwj0FBCeHRgfZGorNDlmZjRkNThlZjlhMTYzYTY5NmQ0ZmFkMDM2MjFiOWUwMzZmMjRmN18xNXgCgAHpbIgBrPvTxQE","dcga":{"pubConfigOverride":{"border-color":"black","font-weight":"bold","inherit-title-color":"true","module-name":"cta-lazy-module","enable-call-to-action-creative-component":"true","disable-cta-on-custom-module":"true"}},"tslt":{"p-video-overlay":{"cancel":"ץ××ר","goto":"×ĸ××ר ×××Ŗ"},"read-more":{"DEFAULT_CAPTION":"%D7%A7%D7%A8%D7%90%20%D7%A2%D7%95%D7%93"},"next-up":{"BTN_TEXT":"×קר×××Ē ××Ē××× ×××"},"time-ago":{"now":"×ĸ×׊××","today":"××××","yesterday":"××Ē×××","minutes":"××¤× × {0} ×ק××Ē","hour":"××¤× × ×Š×ĸ×","hours":"××¤× × {0} ׊×ĸ××Ē","days":"××¤× × {0} ××××"},"explore-more":{"TITLE_TEXT":"××׊××× ×קר××","POPUP_TEXT":"×× ×Ē×¤×Ą×¤×Ą× ××××× ××Ē ×קר×× ×ĸ×× ×Ē××× ××ĸ×××, ר××ĸ ××¤× × ×Š×Ē×ĸ×××"}},"evh":"-1964913910","vl":[{"ri":"185db6d274ce94b27caaabd9eed7915b","uip":"wattpad.com_P18694_S257846_W300_H250_N1_TB","ppb":"COIF","estimation_method":"EcpmEstimationMethodType_ESTIMATION","baseline_variant":"false","original_ecpm":"0.4750949889421463","v":[{"thumbnail":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg","all-thumbnails":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg!-#@1600x1000","origin":"default","thumb-size":"1600x1000","title":"Get Roofing Services At Prices You Can Afford In Edmonton","type":"text","published-date":"1641997069","branding-text":"Roofing Services | Search Ads","url":"https://inneth-conded.xyz/9ad2e613-8777-4fe7-9a52-386c88879289?site\u003dwattpad-placement-255\u0026site_id\u003d1420260\u0026title\u003dGet+Roofing+Services+At+Prices+You+Can+Afford+In+Edmonton\u0026platform\u003dSmartphone\u0026campaign_id\u003d15573949\u0026campaign_item_id\u003d3108610633\u0026thumbnail\u003dhttp%3A%2F%2Fcdn.taboola.com%2Flibtrc%2Fstatic%2Fthumbnails%2Fa2b272be514ca3ebe3f97a4a32a41db5.jpg\u0026cpc\u003d{cpc}\u0026click_id\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1\u0026tblci\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1#tblciGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1","duration":"0","sig":"328243c4127ff16e3fdcd7270bab908f6f3fc5b4c98d","item-id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","uploader":"","is-syndicated":"true","publisher":"search","id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","category":"home","views":"0","itp":[{"u":"https://trc.taboola.com/1326786/log/3/unip?en\u003dclickersusa","t":"c"}],"description":""}]}],"cpcud":{"upc":"0.0","upr":"0.0"}}}\n});\n\u003c/script\u003e\n\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({flush: true});\n\u003c/script\u003e\n\n\u003c/body\u003e\n\u003c/html\u003e',
+ 'adomain': [
+ 'example.xyz'
+ ],
+ 'cid': '15744349',
+ 'crid': '278195503434041083381',
+ 'w': 300,
+ 'h': 250,
+ 'exp': 60,
+ 'lurl': 'http://us-trc.taboola.com/sample',
+ 'nurl': 'http://win.example.com/',
+
+ }
+ ],
+ 'seat': '14204545260'
+ }
+ ],
+ 'bidid': 'da43860a-4644-442a-b5e0-93f268cf8d19',
+ 'cur': 'USD',
+ 'ext': {
+ 'igbid': [
+ {
+ 'impid': request.data.imp[0].id,
+ 'igbuyer': [
+ {
+ }
+ ]
+ }
+ ]
+ }
+ }
+ };
+
+ const serverResponseWithEmptyIgbidWIthWrongPa = {
+ body: {
+ 'id': '49ffg4d58ef9a163a69fhgfghd4fad03621b9e036f24f7_15',
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
+ 'impid': request.data.imp[0].id,
+ 'price': 0.342068,
+ 'adid': '2785119545551083381',
+ 'adm': '\u003chtml\u003e\n\u003chead\u003e\n\u003cmeta charset\u003d"UTF-8"\u003e\n\u003cmeta http-equiv\u003d"Content-Type" content\u003d"text/html; charset\u003dutf-8"/\u003e\u003c/head\u003e\n\u003cbody style\u003d"margin: 0px; overflow:hidden;"\u003e \n\u003cscript type\u003d"text/javascript"\u003e\nwindow.tbl_trc_domain \u003d \u0027us-trc.taboola.com\u0027;\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({article:\u0027auto\u0027});\n!function (e, f, u, i) {\nif (!document.getElementById(i)){\ne.async \u003d 1;\ne.src \u003d u;\ne.id \u003d i;\nf.parentNode.insertBefore(e, f);\n}\n}(document.createElement(\u0027script\u0027),\ndocument.getElementsByTagName(\u0027script\u0027)[0],\n\u0027//cdn.taboola.com/libtrc/wattpad-placement-255/loader.js\u0027,\n\u0027tb_loader_script\u0027);\nif(window.performance \u0026\u0026 typeof window.performance.mark \u003d\u003d \u0027function\u0027)\n{window.performance.mark(\u0027tbl_ic\u0027);}\n\u003c/script\u003e\n\n\u003cdiv id\u003d"taboola-below-article-thumbnails" style\u003d"height: 250px; width: 300px;"\u003e\u003c/div\u003e\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({\nmode: \u0027Rbox_300x250_1x1\u0027,\ncontainer: \u0027taboola-below-article-thumbnails\u0027,\nplacement: \u0027wattpad.com_P18694_S257846_W300_H250_N1_TB\u0027,\ntarget_type: \u0027mix\u0027,\n"rtb-win":{ \nbi:\u002749ff4d58ef9a163a696d4fad03621b9e036f24f7_15\u0027,\ncu:\u0027USD\u0027,\nwp:\u0027${AUCTION_PRICE:BF}\u0027,\nwcb:\u0027~!audex-display-impression!~\u0027,\nrt:\u00271643227025284\u0027,\nrdc:\u0027us.taboolasyndication.com\u0027,\nti:\u00274212\u0027,\nex:\u0027MagniteSCoD\u0027,\nbs:\u0027xapi:257846:lvvSm6Ak7_wE\u0027,\nbp:\u002718694\u0027,\nbd:\u0027wattpad.com\u0027,\nsi:\u00279964\u0027\n} \n,\nrec: {"trc":{"si":"a69c7df43b2334f0aa337c37e2d80c21","sd":"v2_a69c7df43b2334f0aa337c37e2d80c21_3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD_1643227025_1643227025_CJS1tQEQ5NdWGPLA0d76xo-9ngEgASgEMCY4iegHQIroB0iB09kDUKPPB1gAYABop-G2i_Hl-eVucAA","ui":"3c70f7c7d64a65b15e4a4175c9a2cfa51072f04bMagniteSCoD","plc":"PHON","wi":"-643136642229425433","cc":"CA","route":"US:US:V","el2r":["bulk-metrics","debug","social","metrics","perf"],"uvpw":"1","pi":"1420260","cpb":"GNO629MGIJz__________wEqGXVzLnRhYm9vbGFzeW5kaWNhdGlvbi5jb20yC3RyYy1zY29kMTI5OIDwmrUMQInoB0iK6AdQgdPZA1ijzwdjCN3__________wEQ3f__________ARgjZGMI3AoQoBAYFmRjCNIDEOAGGAhkYwiWFBCcHBgYZGMI9AUQiwoYC2RjCNkUEPkcGB1kYwj0FBCeHRgfZGorNDlmZjRkNThlZjlhMTYzYTY5NmQ0ZmFkMDM2MjFiOWUwMzZmMjRmN18xNXgCgAHpbIgBrPvTxQE","dcga":{"pubConfigOverride":{"border-color":"black","font-weight":"bold","inherit-title-color":"true","module-name":"cta-lazy-module","enable-call-to-action-creative-component":"true","disable-cta-on-custom-module":"true"}},"tslt":{"p-video-overlay":{"cancel":"ץ××ר","goto":"×ĸ××ר ×××Ŗ"},"read-more":{"DEFAULT_CAPTION":"%D7%A7%D7%A8%D7%90%20%D7%A2%D7%95%D7%93"},"next-up":{"BTN_TEXT":"×קר×××Ē ××Ē××× ×××"},"time-ago":{"now":"×ĸ×׊××","today":"××××","yesterday":"××Ē×××","minutes":"××¤× × {0} ×ק××Ē","hour":"××¤× × ×Š×ĸ×","hours":"××¤× × {0} ׊×ĸ××Ē","days":"××¤× × {0} ××××"},"explore-more":{"TITLE_TEXT":"××׊××× ×קר××","POPUP_TEXT":"×× ×Ē×¤×Ą×¤×Ą× ××××× ××Ē ×קר×× ×ĸ×× ×Ē××× ××ĸ×××, ר××ĸ ××¤× × ×Š×Ē×ĸ×××"}},"evh":"-1964913910","vl":[{"ri":"185db6d274ce94b27caaabd9eed7915b","uip":"wattpad.com_P18694_S257846_W300_H250_N1_TB","ppb":"COIF","estimation_method":"EcpmEstimationMethodType_ESTIMATION","baseline_variant":"false","original_ecpm":"0.4750949889421463","v":[{"thumbnail":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg","all-thumbnails":"https://cdn.taboola.com/libtrc/static/thumbnails/a2b272be514ca3ebe3f97a4a32a41db5.jpg!-#@1600x1000","origin":"default","thumb-size":"1600x1000","title":"Get Roofing Services At Prices You Can Afford In Edmonton","type":"text","published-date":"1641997069","branding-text":"Roofing Services | Search Ads","url":"https://inneth-conded.xyz/9ad2e613-8777-4fe7-9a52-386c88879289?site\u003dwattpad-placement-255\u0026site_id\u003d1420260\u0026title\u003dGet+Roofing+Services+At+Prices+You+Can+Afford+In+Edmonton\u0026platform\u003dSmartphone\u0026campaign_id\u003d15573949\u0026campaign_item_id\u003d3108610633\u0026thumbnail\u003dhttp%3A%2F%2Fcdn.taboola.com%2Flibtrc%2Fstatic%2Fthumbnails%2Fa2b272be514ca3ebe3f97a4a32a41db5.jpg\u0026cpc\u003d{cpc}\u0026click_id\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1\u0026tblci\u003dGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1#tblciGiCIypnAQogsMTFL3e_mPaVM2qLvK3KRU6LWzEMUgeB6piCit1Uox6CNr5v5n-x1","duration":"0","sig":"328243c4127ff16e3fdcd7270bab908f6f3fc5b4c98d","item-id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","uploader":"","is-syndicated":"true","publisher":"search","id":"~~V1~~2785119550041083381~~PnBkfBE9JnQxpahv0adkcuIcmMhroRAHXwLZd-7zhunTxvAnL2wqac4MyzR7uD46gj3kUkbS3FhelBtnsiJV6MhkDZRZzzIqDobN6rWmCPA3hYz5D3PLat6nhIftiT1lwdxwdlxkeV_Mfb3eos_TQavImGhxk0e7psNAZxHJ9RKL2w3lppALGgQJoy2o6lkf-pOqODtX1VkgWpEEM4WsVoWOnUTAwdyGd-8yrze8CWNp752y28hl7lleicyO1vByRdbgwlJdnqyroTPEQNNEn1JRxBOSYSWt-Xm3vkPm-G4","category":"home","views":"0","itp":[{"u":"https://trc.taboola.com/1326786/log/3/unip?en\u003dclickersusa","t":"c"}],"description":""}]}],"cpcud":{"upc":"0.0","upr":"0.0"}}}\n});\n\u003c/script\u003e\n\n\u003cscript type\u003d"text/javascript"\u003e\nwindow._taboola \u003d window._taboola || [];\n_taboola.push({flush: true});\n\u003c/script\u003e\n\n\u003c/body\u003e\n\u003c/html\u003e',
+ 'adomain': [
+ 'example.xyz'
+ ],
+ 'cid': '15744349',
+ 'crid': '278195503434041083381',
+ 'w': 300,
+ 'h': 250,
+ 'exp': 60,
+ 'lurl': 'http://us-trc.taboola.com/sample',
+ 'nurl': 'http://win.example.com/',
+
+ }
+ ],
+ 'seat': '14204545260'
+ }
+ ],
+ 'bidid': 'da43860a-4644-442a-b5e0-93f268cf8d19',
+ 'cur': 'USD',
+ 'ext': {
+ 'igbid': [
+ {
+ }
+ ]
+ }
+ }
+ };
it('should return empty array if no valid bids', function () {
const res = spec.interpretResponse(serverResponse, [])
@@ -513,18 +900,7 @@ describe('Taboola Adapter', function () {
});
it('should interpret multi impression request', function () {
- const multiRequest = {
- bids: [
- {
- ...createBidRequest(),
- ...displayBidRequestParams
- },
- {
- ...createBidRequest(),
- ...displayBidRequestParams
- }
- ]
- }
+ const multiRequest = spec.buildRequests([defaultBidRequest, defaultBidRequest], bidderRequest);
const multiServerResponse = {
body: {
@@ -534,7 +910,7 @@ describe('Taboola Adapter', function () {
'bid': [
{
'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
- 'impid': '2',
+ 'impid': multiRequest.data.imp[0].id,
'price': 0.342068,
'adid': '2785119545551083381',
'adm': 'ADM2',
@@ -551,7 +927,7 @@ describe('Taboola Adapter', function () {
},
{
'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
- 'impid': '1',
+ 'impid': multiRequest.data.imp[1].id,
'price': 0.342068,
'adid': '2785119545551083381',
'adm': 'ADM1',
@@ -582,6 +958,8 @@ describe('Taboola Adapter', function () {
requestId: multiRequest.bids[1].bidId,
cpm: bid.price,
creativeId: bid.crid,
+ creative_id: bid.crid,
+ seatBidId: multiServerResponse.body.seatbid[0].bid[0].id,
ttl: 60,
netRevenue: true,
currency: multiServerResponse.body.cur,
@@ -598,6 +976,8 @@ describe('Taboola Adapter', function () {
requestId: multiRequest.bids[0].bidId,
cpm: bid.price,
creativeId: bid.crid,
+ creative_id: bid.crid,
+ seatBidId: multiServerResponse.body.seatbid[0].bid[1].id,
ttl: 60,
netRevenue: true,
currency: multiServerResponse.body.cur,
@@ -621,8 +1001,10 @@ describe('Taboola Adapter', function () {
const expectedRes = [
{
requestId: request.bids[0].bidId,
+ seatBidId: serverResponse.body.seatbid[0].bid[0].id,
cpm: bid.price,
creativeId: bid.crid,
+ creative_id: bid.crid,
ttl: 60,
netRevenue: true,
currency: serverResponse.body.cur,
@@ -641,6 +1023,181 @@ describe('Taboola Adapter', function () {
expect(res).to.deep.equal(expectedRes)
});
+ it('should interpret display response with PA', function () {
+ const [bid] = serverResponse.body.seatbid[0].bid;
+
+ const expectedRes = {
+ 'bids': [
+ {
+ requestId: request.bids[0].bidId,
+ seatBidId: serverResponse.body.seatbid[0].bid[0].id,
+ cpm: bid.price,
+ creativeId: bid.crid,
+ creative_id: bid.crid,
+ ttl: 60,
+ netRevenue: true,
+ currency: serverResponse.body.cur,
+ mediaType: 'banner',
+ ad: bid.adm,
+ width: bid.w,
+ height: bid.h,
+ nurl: 'http://win.example.com/',
+ meta: {
+ 'advertiserDomains': bid.adomain
+ },
+ }
+ ],
+ 'fledgeAuctionConfigs': [
+ {
+ 'impId': request.bids[0].bidId,
+ 'config': {
+ 'seller': 'pa.taboola.com',
+ 'resolveToConfig': false,
+ 'sellerSignals': {},
+ 'sellerTimeout': 100,
+ 'perBuyerSignals': {
+ 'https://pa.taboola.com': {
+ 'country': 'US',
+ 'route': 'AM',
+ 'cct': [
+ 0.02241223,
+ -0.8686833,
+ 0.96153843
+ ],
+ 'vct': '-1967600173',
+ 'ccv': null,
+ 'ect': [
+ -0.13584597,
+ 2.5825605
+ ],
+ 'ri': '100fb73d4064bc',
+ 'vcv': '165229814',
+ 'ecv': [
+ -0.39882636,
+ -0.05216012
+ ],
+ 'publisher': 'test-headerbidding',
+ 'platform': 'DESK'
+ }
+ },
+ 'auctionSignals': {},
+ 'decisionLogicUrl': 'https://pa.taboola.com/score/decisionLogic.js',
+ 'interestGroupBuyers': [
+ 'https://pa.taboola.com'
+ ],
+ 'perBuyerTimeouts': {
+ '*': 50
+ }
+ }
+ }
+ ]
+ }
+
+ const res = spec.interpretResponse(serverResponseWithPa, request)
+ expect(res).to.deep.equal(expectedRes)
+ });
+
+ it('should interpret display response with partialPA', function () {
+ const [bid] = serverResponse.body.seatbid[0].bid;
+ const expectedRes = {
+ 'bids': [
+ {
+ requestId: request.bids[0].bidId,
+ seatBidId: serverResponse.body.seatbid[0].bid[0].id,
+ cpm: bid.price,
+ creativeId: bid.crid,
+ creative_id: bid.crid,
+ ttl: 60,
+ netRevenue: true,
+ currency: serverResponse.body.cur,
+ mediaType: 'banner',
+ ad: bid.adm,
+ width: bid.w,
+ height: bid.h,
+ nurl: 'http://win.example.com/',
+ meta: {
+ 'advertiserDomains': bid.adomain
+ },
+ }
+ ],
+ 'fledgeAuctionConfigs': [
+ {
+ 'impId': request.bids[0].bidId,
+ 'config': {
+ 'seller': undefined,
+ 'resolveToConfig': undefined,
+ 'sellerSignals': {},
+ 'sellerTimeout': undefined,
+ 'perBuyerSignals': {},
+ 'auctionSignals': {},
+ 'decisionLogicUrl': undefined,
+ 'interestGroupBuyers': undefined,
+ 'perBuyerTimeouts': undefined
+ }
+ }
+ ]
+ }
+
+ const res = spec.interpretResponse(serverResponseWithPartialPa, request)
+ expect(res).to.deep.equal(expectedRes)
+ });
+
+ it('should interpret display response with wrong PA', function () {
+ const [bid] = serverResponse.body.seatbid[0].bid;
+
+ const expectedRes = [
+ {
+ requestId: request.bids[0].bidId,
+ seatBidId: serverResponse.body.seatbid[0].bid[0].id,
+ cpm: bid.price,
+ creativeId: bid.crid,
+ creative_id: bid.crid,
+ ttl: 60,
+ netRevenue: true,
+ currency: serverResponse.body.cur,
+ mediaType: 'banner',
+ ad: bid.adm,
+ width: bid.w,
+ height: bid.h,
+ nurl: 'http://win.example.com/',
+ meta: {
+ 'advertiserDomains': bid.adomain
+ },
+ }
+ ]
+
+ const res = spec.interpretResponse(serverResponseWithWrongPa, request)
+ expect(res).to.deep.equal(expectedRes)
+ });
+
+ it('should interpret display response with empty igbid wrong PA', function () {
+ const [bid] = serverResponse.body.seatbid[0].bid;
+
+ const expectedRes = [
+ {
+ requestId: request.bids[0].bidId,
+ seatBidId: serverResponse.body.seatbid[0].bid[0].id,
+ cpm: bid.price,
+ creativeId: bid.crid,
+ creative_id: bid.crid,
+ ttl: 60,
+ netRevenue: true,
+ currency: serverResponse.body.cur,
+ mediaType: 'banner',
+ ad: bid.adm,
+ width: bid.w,
+ height: bid.h,
+ nurl: 'http://win.example.com/',
+ meta: {
+ 'advertiserDomains': bid.adomain
+ },
+ }
+ ]
+
+ const res = spec.interpretResponse(serverResponseWithEmptyIgbidWIthWrongPa, request)
+ expect(res).to.deep.equal(expectedRes)
+ });
+
it('should set the correct ttl form the response', function () {
// set exp-ttl to be 125
const [bid] = serverResponse.body.seatbid[0].bid;
@@ -648,8 +1205,10 @@ describe('Taboola Adapter', function () {
const expectedRes = [
{
requestId: request.bids[0].bidId,
+ seatBidId: serverResponse.body.seatbid[0].bid[0].id,
cpm: bid.price,
creativeId: bid.crid,
+ creative_id: bid.crid,
ttl: 125,
netRevenue: true,
currency: serverResponse.body.cur,
@@ -668,18 +1227,7 @@ describe('Taboola Adapter', function () {
});
it('should replace AUCTION_PRICE macro in adm', function () {
- const multiRequest = {
- bids: [
- {
- ...createBidRequest(),
- ...displayBidRequestParams
- },
- {
- ...createBidRequest(),
- ...displayBidRequestParams
- }
- ]
- }
+ const multiRequest = spec.buildRequests([defaultBidRequest, defaultBidRequest], bidderRequest);
const multiServerResponseWithMacro = {
body: {
'id': '49ffg4d58ef9a163a69fhgfghd4fad03621b9e036f24f7_15',
@@ -688,7 +1236,7 @@ describe('Taboola Adapter', function () {
'bid': [
{
'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
- 'impid': '2',
+ 'impid': multiRequest.data.imp[0].id,
'price': 0.34,
'adid': '2785119545551083381',
'adm': 'ADM2,\\nwp:\'${AUCTION_PRICE}\'',
@@ -705,7 +1253,7 @@ describe('Taboola Adapter', function () {
},
{
'id': '0b3dd94348-134b-435f-8db5-6bf5afgfc39e86c',
- 'impid': '1',
+ 'impid': multiRequest.data.imp[1].id,
'price': 0.35,
'adid': '2785119545551083381',
'adm': 'ADM2,\\nwp:\'${AUCTION_PRICE}\'',
@@ -735,6 +1283,8 @@ describe('Taboola Adapter', function () {
requestId: multiRequest.bids[1].bidId,
cpm: multiServerResponseWithMacro.body.seatbid[0].bid[0].price,
creativeId: bid.crid,
+ creative_id: bid.crid,
+ seatBidId: multiServerResponseWithMacro.body.seatbid[0].bid[0].id,
ttl: 60,
netRevenue: true,
currency: multiServerResponseWithMacro.body.cur,
@@ -751,6 +1301,8 @@ describe('Taboola Adapter', function () {
requestId: multiRequest.bids[0].bidId,
cpm: multiServerResponseWithMacro.body.seatbid[0].bid[1].price,
creativeId: bid.crid,
+ creative_id: bid.crid,
+ seatBidId: multiServerResponseWithMacro.body.seatbid[0].bid[1].id,
ttl: 60,
netRevenue: true,
currency: multiServerResponseWithMacro.body.cur,
@@ -771,17 +1323,28 @@ describe('Taboola Adapter', function () {
describe('getUserSyncs', function () {
const usersyncUrl = 'https://trc.taboola.com/sg/prebidJS/1/cm';
+ const iframeUrl = 'https://cdn.taboola.com/scripts/prebid_iframe_sync.html';
- it('should not return user sync if pixelEnabled is false', function () {
- const res = spec.getUserSyncs({pixelEnabled: false});
+ it('should not return user sync if pixelEnabled is false and iframe disabled', function () {
+ const res = spec.getUserSyncs({pixelEnabled: false, iframeEnabled: false});
expect(res).to.be.an('array').that.is.empty;
});
it('should return user sync if pixelEnabled is true', function () {
- const res = spec.getUserSyncs({pixelEnabled: true});
+ const res = spec.getUserSyncs({pixelEnabled: true, iframeEnabled: false});
expect(res).to.deep.equal([{type: 'image', url: usersyncUrl}]);
});
+ it('should return user sync if iframeEnabled is true', function () {
+ const res = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: false});
+ expect(res).to.deep.equal([{type: 'iframe', url: iframeUrl}]);
+ });
+
+ it('should return both user syncs if iframeEnabled is true and pixelEnabled is true', function () {
+ const res = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true});
+ expect(res).to.deep.equal([{type: 'iframe', url: iframeUrl}, {type: 'image', url: usersyncUrl}]);
+ });
+
it('should pass consent tokens values', function() {
expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {gdprApplies: true, consentString: 'GDPR_CONSENT'}, 'USP_CONSENT')).to.deep.equal([{
type: 'image', url: `${usersyncUrl}?gdpr=1&gdpr_consent=GDPR_CONSENT&us_privacy=USP_CONSENT`
@@ -795,8 +1358,11 @@ describe('Taboola Adapter', function () {
expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined, 'USP_CONSENT')).to.deep.equal([{
type: 'image', url: `${usersyncUrl}?us_privacy=USP_CONSENT`
}]);
- expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined, 'USP_CONSENT', 'GPP_STRING')).to.deep.equal([{
- type: 'image', url: `${usersyncUrl}?us_privacy=USP_CONSENT&gpp=GPP_STRING`
+ expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined, 'USP_CONSENT', {gppString: 'GPP_STRING', applicableSections: []})).to.deep.equal([{
+ type: 'image', url: `${usersyncUrl}?us_privacy=USP_CONSENT&gpp=GPP_STRING&gpp_sid=`
+ }]);
+ expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined, 'USP_CONSENT', {gppString: 'GPP_STRING', applicableSections: [32, 51]})).to.deep.equal([{
+ type: 'image', url: `${usersyncUrl}?us_privacy=USP_CONSENT&gpp=GPP_STRING&gpp_sid=32%2C51`
}]);
});
})
diff --git a/test/spec/modules/tagorasBidAdapter_spec.js b/test/spec/modules/tagorasBidAdapter_spec.js
new file mode 100644
index 00000000000..7559567dcff
--- /dev/null
+++ b/test/spec/modules/tagorasBidAdapter_spec.js
@@ -0,0 +1,651 @@
+import {expect} from 'chai';
+import {
+ spec as adapter,
+ createDomain,
+ hashCode,
+ extractPID,
+ extractCID,
+ extractSubDomain,
+ getStorageItem,
+ setStorageItem,
+ tryParseJSON,
+ getUniqueDealId,
+} from 'modules/tagorasBidAdapter';
+import * as utils from 'src/utils.js';
+import {version} from 'package.json';
+import {useFakeTimers} from 'sinon';
+import {BANNER, VIDEO} from '../../../src/mediaTypes';
+import {config} from '../../../src/config';
+
+export const TEST_ID_SYSTEMS = ['britepoolid', 'criteoId', 'id5id', 'idl_env', 'lipb', 'netId', 'parrableId', 'pubcid', 'tdid', 'pubProvidedId'];
+
+const SUB_DOMAIN = 'exchange';
+
+const BID = {
+ 'bidId': '2d52001cabd527',
+ 'adUnitCode': 'div-gpt-ad-12345-0',
+ 'params': {
+ 'subDomain': SUB_DOMAIN,
+ 'cId': '59db6b3b4ffaa70004f45cdc',
+ 'pId': '59ac17c192832d0011283fe3',
+ 'bidFloor': 0.1,
+ 'ext': {
+ 'param1': 'loremipsum',
+ 'param2': 'dolorsitamet'
+ }
+ },
+ 'placementCode': 'div-gpt-ad-1460505748561-0',
+ 'sizes': [[300, 250], [300, 600]],
+ 'bidderRequestId': '1fdb5ff1b6eaa7',
+ 'bidRequestsCount': 4,
+ 'bidderRequestsCount': 3,
+ 'bidderWinsCount': 1,
+ 'requestId': 'b0777d85-d061-450e-9bc7-260dd54bbb7a',
+ 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc',
+ 'mediaTypes': [BANNER],
+ 'ortb2Imp': {
+ 'ext': {
+ 'gpid': '0123456789',
+ 'tid': 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf'
+ }
+ }
+};
+
+const VIDEO_BID = {
+ 'bidId': '2d52001cabd527',
+ 'adUnitCode': '63550ad1ff6642d368cba59dh5884270560',
+ 'bidderRequestId': '12a8ae9ada9c13',
+ 'transactionId': '56e184c6-bde9-497b-b9b9-cf47a61381ee',
+ 'bidRequestsCount': 4,
+ 'bidderRequestsCount': 3,
+ 'bidderWinsCount': 1,
+ 'schain': 'a0819c69-005b-41ed-af06-1be1e0aefefc',
+ 'params': {
+ 'subDomain': SUB_DOMAIN,
+ 'cId': '635509f7ff6642d368cb9837',
+ 'pId': '59ac17c192832d0011283fe3',
+ 'bidFloor': 0.1
+ },
+ 'sizes': [[545, 307]],
+ 'mediaTypes': {
+ 'video': {
+ 'playerSize': [[545, 307]],
+ 'context': 'instream',
+ 'mimes': [
+ 'video/mp4',
+ 'application/javascript'
+ ],
+ 'protocols': [2, 3, 5, 6],
+ 'maxduration': 60,
+ 'minduration': 0,
+ 'startdelay': 0,
+ 'linearity': 1,
+ 'api': [2],
+ 'placement': 1
+ }
+ },
+ 'ortb2Imp': {
+ 'ext': {
+ 'tid': '56e184c6-bde9-497b-b9b9-cf47a61381ee'
+ }
+ }
+}
+
+const BIDDER_REQUEST = {
+ 'gdprConsent': {
+ 'consentString': 'consent_string',
+ 'gdprApplies': true
+ },
+ 'gppString': 'gpp_string',
+ 'gppSid': [7],
+ 'uspConsent': 'consent_string',
+ 'refererInfo': {
+ 'page': 'https://www.greatsite.com',
+ 'ref': 'https://www.somereferrer.com'
+ },
+ 'ortb2': {
+ 'regs': {
+ 'gpp': 'gpp_string',
+ 'gpp_sid': [7]
+ },
+ 'device': {
+ 'sua': {
+ 'source': 2,
+ 'platform': {
+ 'brand': 'Android',
+ 'version': ['8', '0', '0']
+ },
+ 'browsers': [
+ {'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']},
+ {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']},
+ {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']}
+ ],
+ 'mobile': 1,
+ 'model': 'SM-G955U',
+ 'bitness': '64',
+ 'architecture': ''
+ }
+ }
+ }
+};
+
+const SERVER_RESPONSE = {
+ body: {
+ cid: 'testcid123',
+ results: [{
+ 'ad': '
',
+ 'price': 0.8,
+ 'creativeId': '12610997325162499419',
+ 'exp': 30,
+ 'width': 300,
+ 'height': 250,
+ 'advertiserDomains': ['securepubads.g.doubleclick.net'],
+ 'cookies': [{
+ 'src': 'https://sync.com',
+ 'type': 'iframe'
+ }, {
+ 'src': 'https://sync.com',
+ 'type': 'img'
+ }]
+ }]
+ }
+};
+
+const VIDEO_SERVER_RESPONSE = {
+ body: {
+ 'cid': '635509f7ff6642d368cb9837',
+ 'results': [{
+ 'ad': '
',
+ 'advertiserDomains': ['tagoras.io'],
+ 'exp': 60,
+ 'width': 545,
+ 'height': 307,
+ 'mediaType': 'video',
+ 'creativeId': '12610997325162499419',
+ 'price': 2,
+ 'cookies': []
+ }]
+ }
+};
+
+const REQUEST = {
+ data: {
+ width: 300,
+ height: 250,
+ bidId: '2d52001cabd527'
+ }
+};
+
+function getTopWindowQueryParams() {
+ try {
+ const parsedUrl = utils.parseUrl(window.top.document.URL, {decodeSearchAsString: true});
+ return parsedUrl.search;
+ } catch (e) {
+ return '';
+ }
+}
+
+describe('TagorasBidAdapter', function () {
+ describe('validtae spec', function () {
+ it('exists and is a function', function () {
+ expect(adapter.isBidRequestValid).to.exist.and.to.be.a('function');
+ });
+
+ it('exists and is a function', function () {
+ expect(adapter.buildRequests).to.exist.and.to.be.a('function');
+ });
+
+ it('exists and is a function', function () {
+ expect(adapter.interpretResponse).to.exist.and.to.be.a('function');
+ });
+
+ it('exists and is a function', function () {
+ expect(adapter.getUserSyncs).to.exist.and.to.be.a('function');
+ });
+
+ it('exists and is a string', function () {
+ expect(adapter.code).to.exist.and.to.be.a('string');
+ });
+
+ it('exists and contains media types', function () {
+ expect(adapter.supportedMediaTypes).to.exist.and.to.be.an('array').with.length(2);
+ expect(adapter.supportedMediaTypes).to.contain.members([BANNER, VIDEO]);
+ });
+ });
+
+ describe('validate bid requests', function () {
+ it('should require cId', function () {
+ const isValid = adapter.isBidRequestValid({
+ params: {
+ pId: 'pid'
+ }
+ });
+ expect(isValid).to.be.false;
+ });
+
+ it('should require pId', function () {
+ const isValid = adapter.isBidRequestValid({
+ params: {
+ cId: 'cid'
+ }
+ });
+ expect(isValid).to.be.false;
+ });
+
+ it('should validate correctly', function () {
+ const isValid = adapter.isBidRequestValid({
+ params: {
+ cId: 'cid',
+ pId: 'pid'
+ }
+ });
+ expect(isValid).to.be.true;
+ });
+ });
+
+ describe('build requests', function () {
+ let sandbox;
+ before(function () {
+ $$PREBID_GLOBAL$$.bidderSettings = {
+ tagoras: {
+ storageAllowed: true
+ }
+ };
+ sandbox = sinon.sandbox.create();
+ sandbox.stub(Date, 'now').returns(1000);
+ });
+
+ it('should build video request', function () {
+ const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page);
+ config.setConfig({
+ bidderTimeout: 3000
+ });
+ const requests = adapter.buildRequests([VIDEO_BID], BIDDER_REQUEST);
+ expect(requests).to.have.length(1);
+ expect(requests[0]).to.deep.equal({
+ method: 'POST',
+ url: `${createDomain(SUB_DOMAIN)}/prebid/multi/635509f7ff6642d368cb9837`,
+ data: {
+ adUnitCode: '63550ad1ff6642d368cba59dh5884270560',
+ bidFloor: 0.1,
+ bidId: '2d52001cabd527',
+ bidderVersion: adapter.version,
+ bidderRequestId: '12a8ae9ada9c13',
+ cb: 1000,
+ gdpr: 1,
+ gdprConsent: 'consent_string',
+ usPrivacy: 'consent_string',
+ gppString: 'gpp_string',
+ gppSid: [7],
+ prebidVersion: version,
+ transactionId: '56e184c6-bde9-497b-b9b9-cf47a61381ee',
+ bidRequestsCount: 4,
+ bidderRequestsCount: 3,
+ bidderWinsCount: 1,
+ bidderTimeout: 3000,
+ publisherId: '59ac17c192832d0011283fe3',
+ url: 'https%3A%2F%2Fwww.greatsite.com',
+ referrer: 'https://www.somereferrer.com',
+ res: `${window.top.screen.width}x${window.top.screen.height}`,
+ schain: VIDEO_BID.schain,
+ sizes: ['545x307'],
+ sua: {
+ 'source': 2,
+ 'platform': {
+ 'brand': 'Android',
+ 'version': ['8', '0', '0']
+ },
+ 'browsers': [
+ {'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']},
+ {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']},
+ {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']}
+ ],
+ 'mobile': 1,
+ 'model': 'SM-G955U',
+ 'bitness': '64',
+ 'architecture': ''
+ },
+ uniqueDealId: `${hashUrl}_${Date.now().toString()}`,
+ uqs: getTopWindowQueryParams(),
+ mediaTypes: {
+ video: {
+ api: [2],
+ context: 'instream',
+ linearity: 1,
+ maxduration: 60,
+ mimes: [
+ 'video/mp4',
+ 'application/javascript'
+ ],
+ minduration: 0,
+ placement: 1,
+ playerSize: [[545, 307]],
+ protocols: [2, 3, 5, 6],
+ startdelay: 0
+ }
+ },
+ gpid: ''
+ }
+ });
+ });
+
+ it('should build banner request for each size', function () {
+ const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.page);
+ config.setConfig({
+ bidderTimeout: 3000
+ });
+ const requests = adapter.buildRequests([BID], BIDDER_REQUEST);
+ expect(requests).to.have.length(1);
+ expect(requests[0]).to.deep.equal({
+ method: 'POST',
+ url: `${createDomain(SUB_DOMAIN)}/prebid/multi/59db6b3b4ffaa70004f45cdc`,
+ data: {
+ gdprConsent: 'consent_string',
+ gdpr: 1,
+ gppString: 'gpp_string',
+ gppSid: [7],
+ usPrivacy: 'consent_string',
+ transactionId: 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf',
+ bidRequestsCount: 4,
+ bidderRequestsCount: 3,
+ bidderWinsCount: 1,
+ bidderTimeout: 3000,
+ bidderRequestId: '1fdb5ff1b6eaa7',
+ sizes: ['300x250', '300x600'],
+ sua: {
+ 'source': 2,
+ 'platform': {
+ 'brand': 'Android',
+ 'version': ['8', '0', '0']
+ },
+ 'browsers': [
+ {'brand': 'Not_A Brand', 'version': ['99', '0', '0', '0']},
+ {'brand': 'Google Chrome', 'version': ['109', '0', '5414', '119']},
+ {'brand': 'Chromium', 'version': ['109', '0', '5414', '119']}
+ ],
+ 'mobile': 1,
+ 'model': 'SM-G955U',
+ 'bitness': '64',
+ 'architecture': ''
+ },
+ url: 'https%3A%2F%2Fwww.greatsite.com',
+ referrer: 'https://www.somereferrer.com',
+ cb: 1000,
+ bidFloor: 0.1,
+ bidId: '2d52001cabd527',
+ adUnitCode: 'div-gpt-ad-12345-0',
+ publisherId: '59ac17c192832d0011283fe3',
+ uniqueDealId: `${hashUrl}_${Date.now().toString()}`,
+ bidderVersion: adapter.version,
+ prebidVersion: version,
+ schain: BID.schain,
+ res: `${window.top.screen.width}x${window.top.screen.height}`,
+ mediaTypes: [BANNER],
+ gpid: '0123456789',
+ uqs: getTopWindowQueryParams(),
+ 'ext.param1': 'loremipsum',
+ 'ext.param2': 'dolorsitamet',
+ }
+ });
+ });
+
+ after(function () {
+ $$PREBID_GLOBAL$$.bidderSettings = {};
+ sandbox.restore();
+ });
+ });
+ describe('getUserSyncs', function () {
+ it('should have valid user sync with iframeEnabled', function () {
+ const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]);
+
+ expect(result).to.deep.equal([{
+ type: 'iframe',
+ url: 'https://sync.tagoras.io/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy='
+ }]);
+ });
+
+ it('should have valid user sync with cid on response', function () {
+ const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]);
+ expect(result).to.deep.equal([{
+ type: 'iframe',
+ url: 'https://sync.tagoras.io/api/sync/iframe/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy='
+ }]);
+ });
+
+ it('should have valid user sync with pixelEnabled', function () {
+ const result = adapter.getUserSyncs({pixelEnabled: true}, [SERVER_RESPONSE]);
+
+ expect(result).to.deep.equal([{
+ 'url': 'https://sync.tagoras.io/api/sync/image/?cid=testcid123&gdpr=0&gdpr_consent=&us_privacy=',
+ 'type': 'image'
+ }]);
+ });
+
+ it('should generate url with consent data', function () {
+ const gdprConsent = {
+ gdprApplies: true,
+ consentString: 'consent_string'
+ };
+ const uspConsent = 'usp_string';
+ const gppConsent = {
+ gppString: 'gpp_string',
+ applicableSections: [7]
+ }
+
+ const result = adapter.getUserSyncs({pixelEnabled: true}, [SERVER_RESPONSE], gdprConsent, uspConsent, gppConsent);
+
+ expect(result).to.deep.equal([{
+ 'url': 'https://sync.tagoras.io/api/sync/image/?cid=testcid123&gdpr=1&gdpr_consent=consent_string&us_privacy=usp_string&gpp=gpp_string&gpp_sid=7',
+ 'type': 'image'
+ }]);
+ });
+ });
+
+ describe('interpret response', function () {
+ it('should return empty array when there is no response', function () {
+ const responses = adapter.interpretResponse(null);
+ expect(responses).to.be.empty;
+ });
+
+ it('should return empty array when there is no ad', function () {
+ const responses = adapter.interpretResponse({price: 1, ad: ''});
+ expect(responses).to.be.empty;
+ });
+
+ it('should return empty array when there is no price', function () {
+ const responses = adapter.interpretResponse({price: null, ad: 'great ad'});
+ expect(responses).to.be.empty;
+ });
+
+ it('should return an array of interpreted banner responses', function () {
+ const responses = adapter.interpretResponse(SERVER_RESPONSE, REQUEST);
+ expect(responses).to.have.length(1);
+ expect(responses[0]).to.deep.equal({
+ requestId: '2d52001cabd527',
+ cpm: 0.8,
+ width: 300,
+ height: 250,
+ creativeId: '12610997325162499419',
+ currency: 'USD',
+ netRevenue: true,
+ ttl: 30,
+ ad: '
',
+ meta: {
+ advertiserDomains: ['securepubads.g.doubleclick.net']
+ }
+ });
+ });
+
+ it('should get meta from response metaData', function () {
+ const serverResponse = utils.deepClone(SERVER_RESPONSE);
+ serverResponse.body.results[0].metaData = {
+ advertiserDomains: ['tagoras.io'],
+ agencyName: 'Agency Name',
+ };
+ const responses = adapter.interpretResponse(serverResponse, REQUEST);
+ expect(responses[0].meta).to.deep.equal({
+ advertiserDomains: ['tagoras.io'],
+ agencyName: 'Agency Name'
+ });
+ });
+
+ it('should return an array of interpreted video responses', function () {
+ const responses = adapter.interpretResponse(VIDEO_SERVER_RESPONSE, REQUEST);
+ expect(responses).to.have.length(1);
+ expect(responses[0]).to.deep.equal({
+ requestId: '2d52001cabd527',
+ cpm: 2,
+ width: 545,
+ height: 307,
+ mediaType: 'video',
+ creativeId: '12610997325162499419',
+ currency: 'USD',
+ netRevenue: true,
+ ttl: 60,
+ vastXml: '
',
+ meta: {
+ advertiserDomains: ['tagoras.io']
+ }
+ });
+ });
+
+ it('should take default TTL', function () {
+ const serverResponse = utils.deepClone(SERVER_RESPONSE);
+ delete serverResponse.body.results[0].exp;
+ const responses = adapter.interpretResponse(serverResponse, REQUEST);
+ expect(responses).to.have.length(1);
+ expect(responses[0].ttl).to.equal(300);
+ });
+ });
+
+ describe('user id system', function () {
+ TEST_ID_SYSTEMS.forEach((idSystemProvider) => {
+ const id = Date.now().toString();
+ const bid = utils.deepClone(BID);
+
+ const userId = (function () {
+ switch (idSystemProvider) {
+ case 'lipb':
+ return {lipbid: id};
+ case 'parrableId':
+ return {eid: id};
+ case 'id5id':
+ return {uid: id};
+ default:
+ return id;
+ }
+ })();
+
+ bid.userId = {
+ [idSystemProvider]: userId
+ };
+
+ it(`should include 'uid.${idSystemProvider}' in request params`, function () {
+ const requests = adapter.buildRequests([bid], BIDDER_REQUEST);
+ expect(requests[0].data[`uid.${idSystemProvider}`]).to.equal(id);
+ });
+ });
+ });
+
+ describe('alternate param names extractors', function () {
+ it('should return undefined when param not supported', function () {
+ const cid = extractCID({'c_id': '1'});
+ const pid = extractPID({'p_id': '1'});
+ const subDomain = extractSubDomain({'sub_domain': 'prebid'});
+ expect(cid).to.be.undefined;
+ expect(pid).to.be.undefined;
+ expect(subDomain).to.be.undefined;
+ });
+
+ it('should return value when param supported', function () {
+ const cid = extractCID({'cID': '1'});
+ const pid = extractPID({'Pid': '2'});
+ const subDomain = extractSubDomain({'subDOMAIN': 'prebid'});
+ expect(cid).to.be.equal('1');
+ expect(pid).to.be.equal('2');
+ expect(subDomain).to.be.equal('prebid');
+ });
+ });
+
+ describe('unique deal id', function () {
+ before(function () {
+ $$PREBID_GLOBAL$$.bidderSettings = {
+ tagoras: {
+ storageAllowed: true
+ }
+ };
+ });
+ after(function () {
+ $$PREBID_GLOBAL$$.bidderSettings = {};
+ });
+ const key = 'myKey';
+ let uniqueDealId;
+ beforeEach(() => {
+ uniqueDealId = getUniqueDealId(key, 0);
+ })
+
+ it('should get current unique deal id', function (done) {
+ // waiting some time so `now` will become past
+ setTimeout(() => {
+ const current = getUniqueDealId(key);
+ expect(current).to.be.equal(uniqueDealId);
+ done();
+ }, 200);
+ });
+
+ it('should get new unique deal id on expiration', function (done) {
+ setTimeout(() => {
+ const current = getUniqueDealId(key, 100);
+ expect(current).to.not.be.equal(uniqueDealId);
+ done();
+ }, 200)
+ });
+ });
+
+ describe('storage utils', function () {
+ before(function () {
+ $$PREBID_GLOBAL$$.bidderSettings = {
+ tagoras: {
+ storageAllowed: true
+ }
+ };
+ });
+ after(function () {
+ $$PREBID_GLOBAL$$.bidderSettings = {};
+ });
+ it('should get value from storage with create param', function () {
+ const now = Date.now();
+ const clock = useFakeTimers({
+ shouldAdvanceTime: true,
+ now
+ });
+ setStorageItem('myKey', 2020);
+ const {value, created} = getStorageItem('myKey');
+ expect(created).to.be.equal(now);
+ expect(value).to.be.equal(2020);
+ expect(typeof value).to.be.equal('number');
+ expect(typeof created).to.be.equal('number');
+ clock.restore();
+ });
+
+ it('should get external stored value', function () {
+ const value = 'superman'
+ window.localStorage.setItem('myExternalKey', value);
+ const item = getStorageItem('myExternalKey');
+ expect(item).to.be.equal(value);
+ });
+
+ it('should parse JSON value', function () {
+ const data = JSON.stringify({event: 'send'});
+ const {event} = tryParseJSON(data);
+ expect(event).to.be.equal('send');
+ });
+
+ it('should get original value on parse fail', function () {
+ const value = 21;
+ const parsed = tryParseJSON(value);
+ expect(typeof parsed).to.be.equal('number');
+ expect(parsed).to.be.equal(value);
+ });
+ });
+});
diff --git a/test/spec/modules/teadsBidAdapter_spec.js b/test/spec/modules/teadsBidAdapter_spec.js
index b0d5f436e0b..1e044651315 100644
--- a/test/spec/modules/teadsBidAdapter_spec.js
+++ b/test/spec/modules/teadsBidAdapter_spec.js
@@ -1,6 +1,7 @@
import {expect} from 'chai';
import {spec, storage} from 'modules/teadsBidAdapter.js';
import {newBidder} from 'src/adapters/bidderFactory.js';
+import * as autoplay from 'libraries/autoplayDetection/autoplay.js'
const ENDPOINT = 'https://a.teads.tv/hb/bid-request';
const AD_SCRIPT = '"';
@@ -254,6 +255,63 @@ describe('teadsBidAdapter', () => {
expect(payload.pageReferrer).to.deep.equal(document.referrer);
});
+ it('should add screenOrientation info to payload', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequestDefault);
+ const payload = JSON.parse(request.data);
+ const screenOrientation = window.top.screen.orientation?.type
+
+ if (screenOrientation) {
+ expect(payload.screenOrientation).to.exist;
+ expect(payload.screenOrientation).to.deep.equal(screenOrientation);
+ } else expect(payload.screenOrientation).to.not.exist;
+ });
+
+ it('should add historyLength info to payload', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequestDefault);
+ const payload = JSON.parse(request.data);
+
+ expect(payload.historyLength).to.exist;
+ expect(payload.historyLength).to.deep.equal(window.top.history.length);
+ });
+
+ it('should add viewportHeight info to payload', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequestDefault);
+ const payload = JSON.parse(request.data);
+
+ expect(payload.viewportHeight).to.exist;
+ expect(payload.viewportHeight).to.deep.equal(window.top.visualViewport.height);
+ });
+
+ it('should add viewportWidth info to payload', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequestDefault);
+ const payload = JSON.parse(request.data);
+
+ expect(payload.viewportWidth).to.exist;
+ expect(payload.viewportWidth).to.deep.equal(window.top.visualViewport.width);
+ });
+
+ it('should add hardwareConcurrency info to payload', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequestDefault);
+ const payload = JSON.parse(request.data);
+ const hardwareConcurrency = window.top.navigator?.hardwareConcurrency
+
+ if (hardwareConcurrency) {
+ expect(payload.hardwareConcurrency).to.exist;
+ expect(payload.hardwareConcurrency).to.deep.equal(hardwareConcurrency);
+ } else expect(payload.hardwareConcurrency).to.not.exist
+ });
+
+ it('should add deviceMemory info to payload', function () {
+ const request = spec.buildRequests(bidRequests, bidderRequestDefault);
+ const payload = JSON.parse(request.data);
+ const deviceMemory = window.top.navigator.deviceMemory
+
+ if (deviceMemory) {
+ expect(payload.deviceMemory).to.exist;
+ expect(payload.deviceMemory).to.deep.equal(deviceMemory);
+ } else expect(payload.deviceMemory).to.not.exist;
+ });
+
describe('pageTitle', function () {
it('should add pageTitle info to payload based on document title', function () {
const testText = 'This is a title';
@@ -947,6 +1005,45 @@ describe('teadsBidAdapter', () => {
}
});
}
+
+ it('should add dsa info to payload if available', function () {
+ const bidRequestWithDsa = Object.assign({}, bidderRequestDefault, {
+ ortb2: {
+ regs: {
+ ext: {
+ dsa: {
+ dsarequired: '1',
+ pubrender: '2',
+ datatopub: '3',
+ transparency: [{
+ domain: 'test.com',
+ dsaparams: [1, 2, 3]
+ }]
+ }
+ }
+ }
+ }
+ });
+
+ const requestWithDsa = spec.buildRequests(bidRequests, bidRequestWithDsa);
+ const payload = JSON.parse(requestWithDsa.data);
+
+ expect(payload.dsa).to.exist;
+ expect(payload.dsa).to.deep.equal(
+ {
+ dsarequired: '1',
+ pubrender: '2',
+ datatopub: '3',
+ transparency: [{
+ domain: 'test.com',
+ dsaparams: [1, 2, 3]
+ }]
+ }
+ );
+
+ const defaultRequest = spec.buildRequests(bidRequests, bidderRequestDefault);
+ expect(JSON.parse(defaultRequest.data).dsa).to.not.exist;
+ });
});
describe('interpretResponse', function() {
@@ -962,7 +1059,8 @@ describe('teadsBidAdapter', () => {
'ttl': 360,
'width': 300,
'creativeId': 'er2ee',
- 'placementId': 34
+ 'placementId': 34,
+ 'needAutoplay': true
}, {
'ad': AD_SCRIPT,
'cpm': 0.5,
@@ -973,7 +1071,19 @@ describe('teadsBidAdapter', () => {
'width': 350,
'creativeId': 'fs3ff',
'placementId': 34,
- 'dealId': 'ABC_123'
+ 'needAutoplay': false,
+ 'dealId': 'ABC_123',
+ 'ext': {
+ 'dsa': {
+ 'behalf': 'some-behalf',
+ 'paid': 'some-paid',
+ 'transparency': [{
+ 'domain': 'test.com',
+ 'dsaparams': [1, 2, 3]
+ }],
+ 'adrender': 1
+ }
+ }
}]
}
};
@@ -999,7 +1109,16 @@ describe('teadsBidAdapter', () => {
'currency': 'USD',
'netRevenue': true,
'meta': {
- advertiserDomains: []
+ advertiserDomains: [],
+ dsa: {
+ behalf: 'some-behalf',
+ paid: 'some-paid',
+ transparency: [{
+ domain: 'test.com',
+ dsaparams: [1, 2, 3]
+ }],
+ adrender: 1
+ }
},
'ttl': 360,
'ad': AD_SCRIPT,
@@ -1015,6 +1134,70 @@ describe('teadsBidAdapter', () => {
expect(result).to.eql(expectedResponse);
});
+ it('should filter bid responses with needAutoplay:true when autoplay is disabled', function() {
+ let bids = {
+ 'body': {
+ 'responses': [{
+ 'ad': AD_SCRIPT,
+ 'cpm': 0.5,
+ 'currency': 'USD',
+ 'height': 250,
+ 'bidId': '3ede2a3fa0db94',
+ 'ttl': 360,
+ 'width': 300,
+ 'creativeId': 'er2ee',
+ 'placementId': 34,
+ 'needAutoplay': true
+ }, {
+ 'ad': AD_SCRIPT,
+ 'cpm': 0.5,
+ 'currency': 'USD',
+ 'height': 200,
+ 'bidId': '4fef3b4gb1ec15',
+ 'ttl': 360,
+ 'width': 350,
+ 'creativeId': 'fs3ff',
+ 'placementId': 34,
+ 'needAutoplay': false
+ }, {
+ 'ad': AD_SCRIPT,
+ 'cpm': 0.7,
+ 'currency': 'USD',
+ 'height': 600,
+ 'bidId': 'a987fbc961d',
+ 'ttl': 12,
+ 'width': 300,
+ 'creativeId': 'awuygfd',
+ 'placementId': 12,
+ 'needAutoplay': true
+ }]
+ }
+ };
+ let expectedResponse = [{
+ 'cpm': 0.5,
+ 'width': 350,
+ 'height': 200,
+ 'currency': 'USD',
+ 'netRevenue': true,
+ 'meta': {
+ advertiserDomains: [],
+ },
+ 'ttl': 360,
+ 'ad': AD_SCRIPT,
+ 'requestId': '4fef3b4gb1ec15',
+ 'creativeId': 'fs3ff',
+ 'placementId': 34
+ }
+ ]
+ ;
+
+ const isAutoplayEnabledStub = sinon.stub(autoplay, 'isAutoplayEnabled');
+ isAutoplayEnabledStub.returns(false);
+ let result = spec.interpretResponse(bids);
+ isAutoplayEnabledStub.restore();
+ expect(result).to.eql(expectedResponse);
+ });
+
it('handles nobid responses', function() {
let bids = {
'body': {
diff --git a/test/spec/modules/theAdxBidAdapter_spec.js b/test/spec/modules/theAdxBidAdapter_spec.js
index 99e5156190c..eb00834421a 100644
--- a/test/spec/modules/theAdxBidAdapter_spec.js
+++ b/test/spec/modules/theAdxBidAdapter_spec.js
@@ -446,6 +446,78 @@ describe('TheAdxAdapter', function () {
expect(processedBid.currency).to.equal(responseCurrency);
});
+ it('returns a valid deal bid response on sucessful banner request with deal', function () {
+ let incomingRequestId = 'XXtestingXX';
+ let responsePrice = 3.14
+
+ let responseCreative = 'sample_creative&{FOR_COVARAGE}';
+
+ let responseCreativeId = '274';
+ let responseCurrency = 'TRY';
+
+ let responseWidth = 300;
+ let responseHeight = 250;
+ let responseTtl = 213;
+ let dealId = 'theadx_deal_id';
+
+ let sampleResponse = {
+ id: '66043f5ca44ecd8f8769093b1615b2d9',
+ seatbid: [{
+ bid: [{
+ id: 'c21bab0e-7668-4d8f-908a-63e094c09197',
+ dealid: 'theadx_deal_id',
+ impid: '1',
+ price: responsePrice,
+ adid: responseCreativeId,
+ crid: responseCreativeId,
+ adm: responseCreative,
+ adomain: [
+ 'www.domain.com'
+ ],
+ cid: '274',
+ attr: [],
+ w: responseWidth,
+ h: responseHeight,
+ ext: {
+ ttl: responseTtl
+ }
+ }],
+ seat: '201',
+ group: 0
+ }],
+ bidid: 'c21bab0e-7668-4d8f-908a-63e094c09197',
+ cur: responseCurrency
+ };
+
+ let sampleRequest = {
+ bidId: incomingRequestId,
+ mediaTypes: {
+ banner: {}
+ },
+ requestId: incomingRequestId,
+ deals: [{id: dealId}]
+ };
+ let serverResponse = {
+ body: sampleResponse
+ }
+ let result = spec.interpretResponse(serverResponse, sampleRequest);
+
+ expect(result.length).to.equal(1);
+
+ let processedBid = result[0];
+
+ // expect(processedBid.requestId).to.equal(incomingRequestId);
+ expect(processedBid.cpm).to.equal(responsePrice);
+ expect(processedBid.width).to.equal(responseWidth);
+ expect(processedBid.height).to.equal(responseHeight);
+ expect(processedBid.ad).to.equal(responseCreative);
+ expect(processedBid.ttl).to.equal(responseTtl);
+ expect(processedBid.creativeId).to.equal(responseCreativeId);
+ expect(processedBid.netRevenue).to.equal(true);
+ expect(processedBid.currency).to.equal(responseCurrency);
+ expect(processedBid.dealId).to.equal(dealId);
+ });
+
it('returns an valid bid response on sucessful video request', function () {
let incomingRequestId = 'XXtesting-275XX';
let responsePrice = 6
diff --git a/test/spec/modules/themoneytizerBidAdapter_spec.js b/test/spec/modules/themoneytizerBidAdapter_spec.js
new file mode 100644
index 00000000000..8cff7a57e69
--- /dev/null
+++ b/test/spec/modules/themoneytizerBidAdapter_spec.js
@@ -0,0 +1,289 @@
+import { spec } from '../../../modules/themoneytizerBidAdapter.js'
+
+const ENDPOINT_URL = 'https://ads.biddertmz.com/m/';
+
+const VALID_BID_BANNER = {
+ bidder: 'themoneytizer',
+ ortb2Imp: {
+ ext: {}
+ },
+ params: {
+ pid: 123456,
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[970, 250]]
+ }
+ },
+ adUnitCode: 'ad-unit-code',
+ bidId: '82376dbe72be72',
+ timeout: 3000,
+ ortb2: {},
+ userIdAsEids: [],
+ auctionId: '123456-abcdef-7890',
+ schain: {},
+}
+
+const VALID_TEST_BID_BANNER = {
+ bidder: 'themoneytizer',
+ ortb2Imp: {
+ ext: {}
+ },
+ params: {
+ pid: 123456,
+ test: 1,
+ baseUrl: 'https://custom-endpoint.biddertmz.com/m/'
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [[970, 250]]
+ }
+ },
+ adUnitCode: 'ad-unit-code',
+ bidId: '82376dbe72be72',
+ timeout: 3000,
+ ortb2: {},
+ userIdAsEids: [],
+ auctionId: '123456-abcdef-7890',
+ schain: {}
+}
+
+const BIDDER_REQUEST_BANNER = {
+ bids: [VALID_BID_BANNER, VALID_TEST_BID_BANNER],
+ refererInfo: {
+ topmostLocation: 'http://prebid.org/',
+ canonicalUrl: 'http://prebid.org/'
+ },
+ gdprConsent: {
+ gdprApplies: true,
+ consentString: 'abcdefghxyz'
+ }
+}
+
+const SERVER_RESPONSE = {
+ c_sync: {
+ status: 'ok',
+ bidder_status: [
+ {
+ bidder: 'bidder-A',
+ usersync: {
+ url: 'https://syncurl.com',
+ type: 'redirect'
+ }
+ },
+ {
+ bidder: 'bidder-B',
+ usersync: {
+ url: 'https://syncurl2.com',
+ type: 'image'
+ }
+ }
+ ]
+ },
+ bid: {
+ requestId: '17750222eb16825',
+ cpm: 0.098,
+ currency: 'USD',
+ width: 300,
+ height: 600,
+ creativeId: '44368852571075698202250',
+ dealId: '',
+ netRevenue: true,
+ ttl: 5,
+ ad: '
This is an ad
',
+ mediaType: 'banner',
+ }
+};
+
+describe('The Moneytizer Bidder Adapter', function () {
+ describe('codes', function () {
+ it('should return a bidder code of themoneytizer', function () {
+ expect(spec.code).to.equal('themoneytizer');
+ });
+ });
+
+ describe('gvlid', function () {
+ it('should expose gvlid', function () {
+ expect(spec.gvlid).to.equal(1265)
+ });
+ });
+
+ describe('isBidRequestValid', function () {
+ it('should return true for a bid with all required fields', function () {
+ const validBid = spec.isBidRequestValid(VALID_BID_BANNER);
+ expect(validBid).to.be.true;
+ });
+
+ it('should return false for an invalid bid', function () {
+ const invalidBid = spec.isBidRequestValid(null);
+ expect(invalidBid).to.be.false;
+ });
+
+ it('should return false when params are incomplete', function () {
+ const bidWithIncompleteParams = {
+ ...VALID_BID_BANNER,
+ params: {}
+ };
+ expect(spec.isBidRequestValid(bidWithIncompleteParams)).to.be.false;
+ });
+ });
+
+ describe('buildRequests', function () {
+ let requests, request, requests_test, request_test;
+
+ before(function () {
+ requests = spec.buildRequests([VALID_BID_BANNER], BIDDER_REQUEST_BANNER);
+ request = requests[0];
+
+ requests_test = spec.buildRequests([VALID_TEST_BID_BANNER], BIDDER_REQUEST_BANNER);
+ request_test = requests_test[0];
+ });
+
+ it('should build a request array for valid bids', function () {
+ expect(requests).to.be.an('array').that.is.not.empty;
+ });
+
+ it('should build a request array for valid test bids', function () {
+ expect(requests_test).to.be.an('array').that.is.not.empty;
+ });
+
+ it('should build a request with the correct method, URL, and data type', function () {
+ expect(request).to.include.keys(['method', 'url', 'data']);
+ expect(request.method).to.equal('POST');
+ expect(request.url).to.equal(ENDPOINT_URL);
+ expect(request.data).to.be.a('string');
+ });
+
+ it('should build a test request with the correct method, URL, and data type', function () {
+ expect(request_test).to.include.keys(['method', 'url', 'data']);
+ expect(request_test.method).to.equal('POST');
+ expect(request_test.url).to.equal(VALID_TEST_BID_BANNER.params.baseUrl);
+ expect(request_test.data).to.be.a('string');
+ });
+
+ describe('Payload structure', function () {
+ let payload;
+
+ before(function () {
+ payload = JSON.parse(request.data);
+ });
+
+ it('should have correct payload structure', function () {
+ expect(payload).to.be.an('object');
+ expect(payload.size).to.be.an('object');
+ expect(payload.params).to.be.an('object');
+ });
+ });
+
+ describe('Payload structure optional params', function () {
+ let payload;
+
+ before(function () {
+ payload = JSON.parse(request_test.data);
+ });
+
+ it('should have correct params', function () {
+ expect(payload.params.pid).to.equal(123456);
+ });
+
+ it('should have correct referer info', function () {
+ expect(payload.referer).to.equal(BIDDER_REQUEST_BANNER.refererInfo.topmostLocation);
+ expect(payload.referer_canonical).to.equal(BIDDER_REQUEST_BANNER.refererInfo.canonicalUrl);
+ });
+
+ it('should have correct GDPR consent', function () {
+ expect(payload.consent_string).to.equal(BIDDER_REQUEST_BANNER.gdprConsent.consentString);
+ expect(payload.consent_required).to.equal(BIDDER_REQUEST_BANNER.gdprConsent.gdprApplies);
+ });
+ });
+ });
+
+ describe('interpretResponse', function () {
+ let bidResponse, receivedBid;
+ const responseBody = SERVER_RESPONSE;
+
+ before(function () {
+ receivedBid = responseBody.bid;
+ const response = { body: responseBody };
+ bidResponse = spec.interpretResponse(response, null);
+ });
+
+ it('should not return an empty response', function () {
+ expect(bidResponse).to.not.be.empty;
+ });
+
+ describe('Parsed Bid Object', function () {
+ let bid;
+
+ before(function () {
+ bid = bidResponse[0];
+ });
+
+ it('should not be empty', function () {
+ expect(bid).to.not.be.empty;
+ });
+
+ it('should correctly interpret ad markup', function () {
+ expect(bid.ad).to.equal(receivedBid.ad);
+ });
+
+ it('should correctly interpret CPM', function () {
+ expect(bid.cpm).to.equal(receivedBid.cpm);
+ });
+
+ it('should correctly interpret dimensions', function () {
+ expect(bid.height).to.equal(receivedBid.height);
+ expect(bid.width).to.equal(receivedBid.width);
+ });
+
+ it('should correctly interpret request ID', function () {
+ expect(bid.requestId).to.equal(receivedBid.requestId);
+ });
+ });
+ });
+
+ describe('onTimeout', function () {
+ const timeoutData = [{
+ timeout: null
+ }];
+
+ it('should exists and be a function', () => {
+ expect(spec.onTimeout).to.exist.and.to.be.a('function');
+ });
+ it('should include timeoutData', function () {
+ expect(spec.onTimeout(timeoutData)).to.be.undefined;
+ })
+ });
+
+ describe('getUserSyncs', function () {
+ const response = { body: SERVER_RESPONSE };
+
+ it('should have empty user sync with iframeEnabled to false and pixelEnabled to false', function () {
+ const result = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: false }, [response]);
+
+ expect(result).to.be.empty;
+ });
+
+ it('should have user sync with iframeEnabled to true', function () {
+ const result = spec.getUserSyncs({ iframeEnabled: true }, [response]);
+
+ expect(result).to.not.be.empty;
+ expect(result[0].type).to.equal('image');
+ expect(result[0].url).to.equal(SERVER_RESPONSE.c_sync.bidder_status[0].usersync.url);
+ });
+
+ it('should have user sync with pixelEnabled to true', function () {
+ const result = spec.getUserSyncs({ pixelEnabled: true }, [response]);
+
+ expect(result).to.not.be.empty;
+ expect(result[0].type).to.equal('image');
+ expect(result[0].url).to.equal(SERVER_RESPONSE.c_sync.bidder_status[0].usersync.url);
+ });
+
+ it('should transform type redirect into image', function () {
+ const result = spec.getUserSyncs({ iframeEnabled: true }, [response]);
+
+ expect(result[1].type).to.equal('image');
+ });
+ });
+});
diff --git a/test/spec/modules/topicsFpdModule_spec.js b/test/spec/modules/topicsFpdModule_spec.js
index bc7df85db0d..4a79e7f77fd 100644
--- a/test/spec/modules/topicsFpdModule_spec.js
+++ b/test/spec/modules/topicsFpdModule_spec.js
@@ -384,6 +384,22 @@ describe('topics', () => {
});
describe('cross-frame messages', () => {
+ before(() => {
+ config.setConfig({
+ userSync: {
+ topics: {
+ maxTopicCaller: 3,
+ bidders: [
+ {
+ bidder: 'pubmatic',
+ iframeURL: 'https://ads.pubmatic.com/AdServer/js/topics/topics_frame.html'
+ }
+ ],
+ },
+ }
+ });
+ });
+
beforeEach(() => {
// init iframe logic so that the receiveMessage origin check passes
loadTopicsForBidders({
@@ -398,6 +414,10 @@ describe('topics', () => {
});
});
+ after(() => {
+ config.resetConfig();
+ })
+
it('should store segments if receiveMessage event is triggered with segment data', () => {
receiveMessage(evt);
let segments = new Map(safeJSONParse(storage.getDataFromLocalStorage(topicStorageName)));
@@ -421,11 +441,13 @@ describe('handles fetch request for topics api headers', () => {
beforeEach(() => {
stubbedFetch = sinon.stub(window, 'fetch');
+ reset();
});
afterEach(() => {
stubbedFetch.restore();
storage.removeDataFromLocalStorage(topicStorageName);
+ config.resetConfig();
});
it('should make a fetch call when a fetchUrl is present for a selected bidder', () => {
@@ -444,6 +466,7 @@ describe('handles fetch request for topics api headers', () => {
});
stubbedFetch.returns(Promise.resolve(true));
+
loadTopicsForBidders({
browsingTopics: true,
featurePolicy: {
diff --git a/test/spec/modules/tpmnBidAdapter_spec.js b/test/spec/modules/tpmnBidAdapter_spec.js
index e2b14b18f61..505bc9d878f 100644
--- a/test/spec/modules/tpmnBidAdapter_spec.js
+++ b/test/spec/modules/tpmnBidAdapter_spec.js
@@ -1,16 +1,130 @@
/* eslint-disable no-tabs */
-import {expect} from 'chai';
-import {spec, storage} from 'modules/tpmnBidAdapter.js';
-import {generateUUID} from '../../../src/utils.js';
-import {newBidder} from '../../../src/adapters/bidderFactory';
+import { spec, storage, VIDEO_RENDERER_URL, ADAPTER_VERSION } from 'modules/tpmnBidAdapter.js';
+import { generateUUID } from '../../../src/utils.js';
+import { expect } from 'chai';
+import * as utils from 'src/utils';
import * as sinon from 'sinon';
+import 'modules/consentManagement.js';
+import {syncAddFPDToBidderRequest} from '../../helpers/fpd.js';
+import {mockGdprConsent} from '../../helpers/consentData.js';
+
+const BIDDER_CODE = 'tpmn';
+const BANNER_BID = {
+ bidder: BIDDER_CODE,
+ params: {
+ inventoryId: 1
+ },
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [300, 250]
+ ],
+ },
+ },
+ adUnitCode: 'adUnitCode1',
+ bidId: 'bidId',
+ bidderRequestId: 'bidderRequestId',
+ auctionId: 'auctionId-56a2-4f71-9098-720a68f2f708',
+};
+
+const VIDEO_BID = {
+ bidder: BIDDER_CODE,
+ params: {
+ inventoryId: 1
+ },
+ mediaTypes: {
+ video: {
+ context: 'outstream',
+ api: [1, 2, 4, 6],
+ mimes: ['video/mp4'],
+ playbackmethod: [2, 4, 6],
+ playerSize: [[1024, 768]],
+ protocols: [3, 4, 7, 8, 10],
+ placement: 1,
+ plcmt: 1,
+ minduration: 0,
+ maxduration: 60,
+ startdelay: 0
+ },
+ },
+ adUnitCode: 'adUnitCode1',
+ bidId: 'bidId',
+ bidderRequestId: 'bidderRequestId',
+ auctionId: 'auctionId-56a2-4f71-9098-720a68f2f708',
+};
+
+const BIDDER_REQUEST = {
+ auctionId: 'auctionId-56a2-4f71-9098-720a68f2f708',
+ bidderRequestId: 'bidderRequestId',
+ timeout: 500,
+ refererInfo: {
+ page: 'https://hello-world-page.com/',
+ domain: 'hello-world-page.com',
+ ref: 'http://example-domain.com/foo',
+ }
+};
+
+const BANNER_BID_RESPONSE = {
+ 'id': 'bidderRequestId',
+ 'bidId': 'bidid',
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'id': 'id',
+ 'impid': 'bidId',
+ 'price': 0.18,
+ 'adm': '',
+ 'adid': '144762342',
+ 'burl': 'http://0.0.0.0:8181/burl',
+ 'adomain': [
+ 'https://dummydomain.com'
+ ],
+ 'cid': 'cid',
+ 'crid': 'crid',
+ 'iurl': 'iurl',
+ 'cat': [],
+ 'w': 300,
+ 'h': 250
+ }
+ ]
+ }
+ ],
+ 'cur': 'USD'
+};
+
+const VIDEO_BID_RESPONSE = {
+ 'id': 'bidderRequestId',
+ 'bidid': 'bidid',
+ 'seatbid': [
+ {
+ 'bid': [
+ {
+ 'id': 'id',
+ 'impid': 'bidId',
+ 'price': 1.09,
+ 'adid': '144762342',
+ 'burl': 'http://0.0.0.0:8181/burl',
+ 'adm': '
',
+ 'adomain': [
+ 'https://dummydomain.com'
+ ],
+ 'cid': 'cid',
+ 'crid': 'crid',
+ 'iurl': 'iurl',
+ 'cat': [],
+ 'h': 768,
+ 'w': 1024
+ }
+ ]
+ }
+ ],
+ 'cur': 'USD'
+};
describe('tpmnAdapterTests', function () {
- const adapter = newBidder(spec);
- const BIDDER_CODE = 'tpmn';
let sandbox = sinon.sandbox.create();
let getCookieStub;
-
beforeEach(function () {
$$PREBID_GLOBAL$$.bidderSettings = {
tpmn: {
@@ -27,152 +141,277 @@ describe('tpmnAdapterTests', function () {
$$PREBID_GLOBAL$$.bidderSettings = {};
});
- describe('inherited functions', function () {
- it('exists and is a function', function () {
- expect(adapter.callBids).to.exist.and.to.be.a('function')
- })
- });
-
- describe('isBidRequestValid', function () {
- let bid = {
- adUnitCode: 'temp-unitcode',
- bidder: 'tpmn',
- params: {
- inventoryId: '1',
- publisherId: 'TPMN'
- },
- bidId: '29092404798c9',
- bidderRequestId: 'a01',
- auctionId: 'da1d7a33-0260-4e83-a621-14674116f3f9',
- mediaTypes: {
- banner: {
- sizes: [[300, 250]]
- }
- }
- };
-
- it('should return true if a bid is valid banner bid request', function () {
- expect(spec.isBidRequestValid(bid)).to.be.equal(true);
- });
-
- it('should return false where requried param is missing', function () {
- let bid = Object.assign({}, bid);
- bid.params = {};
- expect(spec.isBidRequestValid(bid)).to.be.equal(false);
- });
-
- it('should return false when required param values have invalid type', function () {
- let bid = Object.assign({}, bid);
- bid.params = {
- 'inventoryId': null,
- 'publisherId': null
- };
- expect(spec.isBidRequestValid(bid)).to.be.equal(false);
- });
- });
-
- describe('buildRequests', function () {
- it('should return an empty list if there are no bid requests', function () {
- const emptyBidRequests = [];
- const bidderRequest = {};
- const request = spec.buildRequests(emptyBidRequests, bidderRequest);
- expect(request).to.be.an('array').that.is.empty;
- });
- it('should generate a POST server request with bidder API url, data', function () {
- const bid = {
- adUnitCode: 'temp-unitcode',
- bidder: 'tpmn',
+ describe('isBidRequestValid()', function () {
+ it('should accept request if placementId is passed', function () {
+ let bid = {
+ bidder: BIDDER_CODE,
params: {
- inventoryId: '1',
- publisherId: 'TPMN'
+ inventoryId: 123
},
- bidId: '29092404798c9',
- bidderRequestId: 'a01',
- auctionId: 'da1d7a33-0260-4e83-a621-14674116f3f9',
mediaTypes: {
banner: {
sizes: [[300, 250]]
}
}
};
- const tempBidRequests = [bid];
- const tempBidderRequest = {
- refererInfo: {
- page: 'http://localhost/test',
- site: {
- domain: 'localhost',
- page: 'http://localhost/test'
- }
- }
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+
+ it('should reject requests without params', function () {
+ let bid = {
+ bidder: BIDDER_CODE,
+ params: {}
};
- const builtRequest = spec.buildRequests(tempBidRequests, tempBidderRequest);
-
- expect(builtRequest).to.have.lengthOf(1);
- expect(builtRequest[0].method).to.equal('POST');
- expect(builtRequest[0].url).to.match(/ad.tpmn.co.kr\/prebidhb.tpmn/);
- const apiRequest = builtRequest[0].data;
- expect(apiRequest.site).to.deep.equal({
- domain: 'localhost',
- page: 'http://localhost/test'
- });
- expect(apiRequest.bids).to.have.lengthOf('1');
- expect(apiRequest.bids[0].inventoryId).to.equal('1');
- expect(apiRequest.bids[0].publisherId).to.equal('TPMN');
- expect(apiRequest.bids[0].bidId).to.equal('29092404798c9');
- expect(apiRequest.bids[0].adUnitCode).to.equal('temp-unitcode');
- expect(apiRequest.bids[0].auctionId).to.equal('da1d7a33-0260-4e83-a621-14674116f3f9');
- expect(apiRequest.bids[0].sizes).to.have.lengthOf('1');
- expect(apiRequest.bids[0].sizes[0]).to.deep.equal({
- width: 300,
- height: 250
- });
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+
+ it('should return true when required params found', () => {
+ expect(spec.isBidRequestValid(BANNER_BID)).to.equal(true);
+ expect(spec.isBidRequestValid(VIDEO_BID)).to.equal(true);
});
});
- describe('interpretResponse', function () {
- const bid = {
- adUnitCode: 'temp-unitcode',
- bidder: 'tpmn',
- params: {
- inventoryId: '1',
- publisherId: 'TPMN'
- },
- bidId: '29092404798c9',
- bidderRequestId: 'a01',
- auctionId: 'da1d7a33-0260-4e83-a621-14674116f3f9',
- mediaTypes: {
- banner: {
- sizes: [[300, 250]]
+ describe('buildRequests()', function () {
+ it('should have gdpr data if applicable', function () {
+ const bid = utils.deepClone(BANNER_BID);
+
+ const req = syncAddFPDToBidderRequest(Object.assign({}, BIDDER_REQUEST, {
+ gdprConsent: {
+ consentString: 'consentString',
+ gdprApplies: true,
}
+ }));
+ let request = spec.buildRequests([bid], req)[0];
+
+ const payload = request.data;
+ expect(payload.user.ext).to.have.property('consent', req.gdprConsent.consentString);
+ expect(payload.regs.ext).to.have.property('gdpr', 1);
+ });
+
+ it('should properly forward ORTB blocking params', function () {
+ let bid = utils.deepClone(BANNER_BID);
+ bid = utils.mergeDeep(bid, {
+ params: { bcat: ['IAB1-1'], badv: ['example.com'], bapp: ['com.example'], battr: [1] },
+ mediaTypes: { banner: { battr: [1] } }
+ });
+
+ let [request] = spec.buildRequests([bid], BIDDER_REQUEST);
+
+ expect(request).to.exist.and.to.be.an('object');
+ const payload = request.data;
+ expect(payload).to.have.deep.property('bcat', ['IAB1-1']);
+ expect(payload).to.have.deep.property('badv', ['example.com']);
+ expect(payload).to.have.deep.property('bapp', ['com.example']);
+ expect(payload.imp[0].banner).to.have.deep.property('battr', [1]);
+ });
+
+ context('when mediaType is banner', function () {
+ it('should build correct request for banner bid with both w, h', () => {
+ const bid = utils.deepClone(BANNER_BID);
+
+ const [request] = spec.buildRequests([bid], BIDDER_REQUEST);
+ const requestData = request.data;
+ // expect(requestData.imp[0].banner).to.equal(null);
+ expect(requestData.imp[0].banner.format[0].w).to.equal(300);
+ expect(requestData.imp[0].banner.format[0].h).to.equal(250);
+ });
+
+ it('should create request data', function () {
+ const bid = utils.deepClone(BANNER_BID);
+
+ let [request] = spec.buildRequests([bid], BIDDER_REQUEST);
+ expect(request).to.exist.and.to.be.a('object');
+ const payload = request.data;
+ expect(payload.imp[0]).to.have.property('id', bid.bidId);
+ });
+ });
+
+ context('when mediaType is video', function () {
+ if (FEATURES.VIDEO) {
+ it('should return false when there is no video in mediaTypes', () => {
+ const bid = utils.deepClone(VIDEO_BID);
+ delete bid.mediaTypes.video;
+
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
}
- };
- const tempBidRequests = [bid];
- it('should return an empty aray to indicate no valid bids', function () {
- const emptyServerResponse = {};
- const bidResponses = spec.interpretResponse(emptyServerResponse, tempBidRequests);
- expect(bidResponses).is.an('array').that.is.empty;
+ if (FEATURES.VIDEO) {
+ it('should reutrn false if player size is not set', () => {
+ const bid = utils.deepClone(VIDEO_BID);
+ delete bid.mediaTypes.video.playerSize;
+
+ expect(spec.isBidRequestValid(bid)).to.equal(false);
+ });
+ }
+ if (FEATURES.VIDEO) {
+ it('when mediaType is Video - check', () => {
+ const bid = utils.deepClone(VIDEO_BID);
+ const check = {
+ w: 1024,
+ h: 768,
+ mimes: ['video/mp4'],
+ playbackmethod: [2, 4, 6],
+ api: [1, 2, 4, 6],
+ protocols: [3, 4, 7, 8, 10],
+ placement: 1,
+ minduration: 0,
+ maxduration: 60,
+ startdelay: 0,
+ plcmt: 1
+ };
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ const requests = spec.buildRequests([bid], BIDDER_REQUEST);
+ const request = requests[0].data;
+ expect(request.imp[0].video).to.deep.include({...check});
+ });
+ }
+
+ if (FEATURES.VIDEO) {
+ it('when mediaType New Video', () => {
+ const NEW_VIDEO_BID = {
+ 'bidder': 'tpmn',
+ 'params': {'inventoryId': 2, 'bidFloor': 2},
+ 'userId': {'pubcid': '88a49ee6-beeb-4dd6-92ac-3b6060e127e1'},
+ 'mediaTypes': {
+ 'video': {
+ 'context': 'outstream',
+ 'mimes': ['video/mp4'],
+ 'playerSize': [[1024, 768]],
+ 'playbackmethod': [2, 4, 6],
+ 'protocols': [3, 4],
+ 'api': [1, 2, 3, 6],
+ 'placement': 1,
+ 'minduration': 0,
+ 'maxduration': 30,
+ 'startdelay': 0,
+ 'skip': 1,
+ 'plcmt': 4
+ }
+ },
+ };
+
+ const check = {
+ w: 1024,
+ h: 768,
+ mimes: [ 'video/mp4' ],
+ playbackmethod: [2, 4, 6],
+ api: [1, 2, 3, 6],
+ protocols: [3, 4],
+ placement: 1,
+ minduration: 0,
+ maxduration: 30,
+ startdelay: 0,
+ skip: 1,
+ plcmt: 4
+ }
+
+ expect(spec.isBidRequestValid(NEW_VIDEO_BID)).to.equal(true);
+ let requests = spec.buildRequests([NEW_VIDEO_BID], BIDDER_REQUEST);
+ const request = requests[0].data;
+ expect(request.imp[0].video.w).to.equal(check.w);
+ expect(request.imp[0].video.h).to.equal(check.h);
+ expect(request.imp[0].video.placement).to.equal(check.placement);
+ expect(request.imp[0].video.minduration).to.equal(check.minduration);
+ expect(request.imp[0].video.maxduration).to.equal(check.maxduration);
+ expect(request.imp[0].video.startdelay).to.equal(check.startdelay);
+ expect(request.imp[0].video.skip).to.equal(check.skip);
+ expect(request.imp[0].video.plcmt).to.equal(check.plcmt);
+ expect(request.imp[0].video.mimes).to.deep.have.same.members(check.mimes);
+ expect(request.imp[0].video.playbackmethod).to.deep.have.same.members(check.playbackmethod);
+ expect(request.imp[0].video.api).to.deep.have.same.members(check.api);
+ expect(request.imp[0].video.protocols).to.deep.have.same.members(check.protocols);
+ });
+ }
+
+ if (FEATURES.VIDEO) {
+ it('should use bidder video params if they are set', () => {
+ let bid = utils.deepClone(VIDEO_BID);
+ const check = {
+ api: [1, 2],
+ mimes: ['video/mp4', 'video/x-flv'],
+ playbackmethod: [3, 4],
+ protocols: [5, 6],
+ placement: 1,
+ plcmt: 1,
+ minduration: 0,
+ maxduration: 30,
+ startdelay: 0,
+ w: 640,
+ h: 480
+
+ };
+ bid.mediaTypes.video = {...check};
+ bid.mediaTypes.video.context = 'instream';
+ bid.mediaTypes.video.playerSize = [[640, 480]];
+
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ const requests = spec.buildRequests([bid], BIDDER_REQUEST);
+ const request = requests[0].data;
+ expect(request.imp[0].video).to.deep.include({...check});
+ });
+ }
});
- it('should return an empty array to indicate no valid bids', function () {
- const mockBidResult = {
- requestId: '9cf19229-34f6-4d06-bc1d-0e44e8d616c8',
- cpm: 10.0,
- creativeId: '1',
- width: 300,
- height: 250,
- netRevenue: true,
- currency: 'USD',
- ttl: 1800,
- ad: '
',
- adType: 'banner'
- };
- const testServerResponse = {
- headers: [],
- body: [mockBidResult]
- };
- const bidResponses = spec.interpretResponse(testServerResponse, tempBidRequests);
- expect(bidResponses).deep.equal([mockBidResult]);
+ });
+
+ describe('interpretResponse()', function () {
+ context('when mediaType is banner', function () {
+ it('should correctly interpret valid banner response', function () {
+ const bid = utils.deepClone(BANNER_BID);
+ const [request] = spec.buildRequests([bid], BIDDER_REQUEST);
+ const response = utils.deepClone(BANNER_BID_RESPONSE);
+
+ const bids = spec.interpretResponse({ body: response }, request);
+ expect(bids).to.be.an('array').that.is.not.empty;
+
+ expect(bids[0].mediaType).to.equal('banner');
+ expect(bids[0].burl).to.equal(BANNER_BID_RESPONSE.seatbid[0].bid[0].burl);
+ expect(bids[0].currency).to.equal('USD');
+ expect(bids[0].requestId).to.equal(BANNER_BID_RESPONSE.seatbid[0].bid[0].impid);
+ expect(bids[0].cpm).to.equal(BANNER_BID_RESPONSE.seatbid[0].bid[0].price);
+ expect(bids[0].width).to.equal(BANNER_BID_RESPONSE.seatbid[0].bid[0].w);
+ expect(bids[0].height).to.equal(BANNER_BID_RESPONSE.seatbid[0].bid[0].h);
+ expect(bids[0].ad).to.equal(BANNER_BID_RESPONSE.seatbid[0].bid[0].adm);
+ expect(bids[0].creativeId).to.equal(BANNER_BID_RESPONSE.seatbid[0].bid[0].crid);
+ expect(bids[0].meta.advertiserDomains[0]).to.equal('https://dummydomain.com');
+ expect(bids[0].ttl).to.equal(500);
+ expect(bids[0].netRevenue).to.equal(true);
+ });
+
+ it('should handle empty bid response', function () {
+ const bid = utils.deepClone(BANNER_BID);
+
+ let request = spec.buildRequests([bid], BIDDER_REQUEST)[0];
+ const EMPTY_RESP = Object.assign({}, BANNER_BID_RESPONSE, { 'body': {} });
+ const bids = spec.interpretResponse(EMPTY_RESP, request);
+ expect(bids).to.be.empty;
+ });
});
+ if (FEATURES.VIDEO) {
+ context('when mediaType is video', function () {
+ it('should correctly interpret valid instream video response', () => {
+ const bid = utils.deepClone(VIDEO_BID);
+
+ const [request] = spec.buildRequests([bid], BIDDER_REQUEST);
+ const bids = spec.interpretResponse({ body: VIDEO_BID_RESPONSE }, request);
+ expect(bids).to.be.an('array').that.is.not.empty;
+
+ expect(bids[0].mediaType).to.equal('video');
+ expect(bids[0].burl).to.equal(VIDEO_BID_RESPONSE.seatbid[0].bid[0].burl);
+ expect(bids[0].currency).to.equal('USD');
+ expect(bids[0].requestId).to.equal(VIDEO_BID_RESPONSE.seatbid[0].bid[0].impid);
+ expect(bids[0].cpm).to.equal(VIDEO_BID_RESPONSE.seatbid[0].bid[0].price);
+ expect(bids[0].width).to.equal(VIDEO_BID_RESPONSE.seatbid[0].bid[0].w);
+ expect(bids[0].height).to.equal(VIDEO_BID_RESPONSE.seatbid[0].bid[0].h);
+ expect(bids[0].vastXml).to.equal(VIDEO_BID_RESPONSE.seatbid[0].bid[0].adm);
+ expect(bids[0].rendererUrl).to.equal(VIDEO_RENDERER_URL);
+ expect(bids[0].creativeId).to.equal(VIDEO_BID_RESPONSE.seatbid[0].bid[0].crid);
+ expect(bids[0].meta.advertiserDomains[0]).to.equal('https://dummydomain.com');
+ expect(bids[0].ttl).to.equal(500);
+ expect(bids[0].netRevenue).to.equal(true);
+ });
+ });
+ }
});
describe('getUserSync', function () {
diff --git a/test/spec/modules/tripleliftBidAdapter_spec.js b/test/spec/modules/tripleliftBidAdapter_spec.js
index 275b9b3bfee..851425574d0 100644
--- a/test/spec/modules/tripleliftBidAdapter_spec.js
+++ b/test/spec/modules/tripleliftBidAdapter_spec.js
@@ -736,258 +736,83 @@ describe('triplelift adapter', function () {
});
it('should add tdid to the payload if included', function () {
- const id = '6bca7f6b-a98a-46c0-be05-6020f7604598';
- bidRequests[0].userId.tdid = id;
- const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
- const payload = request.data;
- expect(payload).to.exist;
- expect(payload.user).to.deep.equal({ext: {eids: [{source: 'adserver.org', uids: [{id, ext: {rtiPartner: 'TDID'}}]}]}});
- });
-
- it('should add idl_env to the payload if included', function () {
- const id = 'XY6104gr0njcH9UDIR7ysFFJcm2XNpqeJTYslleJ_cMlsFOfZI';
- bidRequests[0].userId.idl_env = id;
+ const tdid = '6bca7f6b-a98a-46c0-be05-6020f7604598';
+ bidRequests[0].userIdAsEids = [
+ {
+ source: 'adserver.org',
+ uids: [
+ {
+ atype: 1,
+ ext: {
+ rtiPartner: 'TDID'
+ },
+ id: tdid
+ }
+ ]
+ },
+ ];
const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
const payload = request.data;
expect(payload).to.exist;
- expect(payload.user).to.deep.equal({ext: {eids: [{source: 'liveramp.com', uids: [{id, ext: {rtiPartner: 'idl'}}]}]}});
+ expect(payload.user).to.deep.equal({ext: {eids: [{source: 'adserver.org', uids: [{id: tdid, atype: 1, ext: {rtiPartner: 'TDID'}}]}]}});
});
it('should add criteoId to the payload if included', function () {
const id = '53e30ea700424f7bbdd793b02abc5d7';
- bidRequests[0].userId.criteoId = id;
- const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
- const payload = request.data;
- expect(payload).to.exist;
- expect(payload.user).to.deep.equal({ext: {eids: [{source: 'criteo.com', uids: [{id, ext: {rtiPartner: 'criteoId'}}]}]}});
- });
-
- it('should add adqueryId to the payload if included', function () {
- const id = '%7B%22qid%22%3A%229c985f8cc31d9b3c000d%22%7D';
- bidRequests[0].userIdAsEids = [{ source: 'adquery.io', uids: [{ id }] }];
- const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
- const payload = request.data;
- expect(payload).to.exist;
- expect(payload.user).to.deep.equal({ext: {eids: [{source: 'adquery.io', uids: [{id, ext: {rtiPartner: 'adquery.io'}}]}]}});
- });
-
- it('should add amxRtbId to the payload if included', function () {
- const id = 'Ok9JQkBM-UFlAXEZQ-UUNBQlZOQzgrUFhW-UUNBQkRQTUBPQVpVWVxNXlZUUF9AUFhAUF9PXFY/';
- bidRequests[0].userIdAsEids = [{ source: 'amxdt.net', uids: [{ id }] }];
- const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
- const payload = request.data;
- expect(payload).to.exist;
- expect(payload.user).to.deep.equal({ext: {eids: [{source: 'amxdt.net', uids: [{id, ext: {rtiPartner: 'amxdt.net'}}]}]}});
- });
-
- it('should add tdid, idl_env and criteoId to the payload if both are included', function () {
- const tdidId = '6bca7f6b-a98a-46c0-be05-6020f7604598';
- const idlEnvId = 'XY6104gr0njcH9UDIR7ysFFJcm2XNpqeJTYslleJ_cMlsFOfZI';
- const criteoId = '53e30ea700424f7bbdd793b02abc5d7';
- bidRequests[0].userId.tdid = tdidId;
- bidRequests[0].userId.idl_env = idlEnvId;
- bidRequests[0].userId.criteoId = criteoId;
-
- const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
- const payload = request.data;
-
- expect(payload).to.exist;
- expect(payload.user).to.deep.equal({
- ext: {
- eids: [
- {
- source: 'adserver.org',
- uids: [
- {
- id: tdidId,
- ext: { rtiPartner: 'TDID' }
- }
- ],
- },
- {
- source: 'liveramp.com',
- uids: [
- {
- id: idlEnvId,
- ext: { rtiPartner: 'idl' }
- }
- ]
- },
+ bidRequests[0].userIdAsEids = [
+ {
+ source: 'criteo.com',
+ uids: [
{
- source: 'criteo.com',
- uids: [
- {
- id: criteoId,
- ext: { rtiPartner: 'criteoId' }
- }
- ]
+ atype: 1,
+ ext: {
+ rtiPartner: 'criteoId'
+ },
+ id: id
}
]
- }
- });
- });
-
- it('should consolidate user ids from multiple bid requests', function () {
- const tdidId = '6bca7f6b-a98a-46c0-be05-6020f7604598';
- const idlEnvId = 'XY6104gr0njcH9UDIR7ysFFJcm2XNpqeJTYslleJ_cMlsFOfZI';
- const criteoId = '53e30ea700424f7bbdd793b02abc5d7';
- const pubcid = '3261d8ad-435d-481d-abd1-9f1a9ec99f0e';
-
- const bidRequestsMultiple = [
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } }
+ },
];
-
- const request = tripleliftAdapterSpec.buildRequests(bidRequestsMultiple, bidderRequest);
+ const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
const payload = request.data;
-
- expect(payload.user).to.deep.equal({
- ext: {
- eids: [
- {
- source: 'adserver.org',
- uids: [
- {
- id: tdidId,
- ext: { rtiPartner: 'TDID' }
- }
- ],
- },
- {
- source: 'liveramp.com',
- uids: [
- {
- id: idlEnvId,
- ext: { rtiPartner: 'idl' }
- }
- ]
- },
- {
- source: 'criteo.com',
- uids: [
- {
- id: criteoId,
- ext: { rtiPartner: 'criteoId' }
- }
- ]
- },
- {
- source: 'pubcid.org',
- uids: [
- {
- id: '3261d8ad-435d-481d-abd1-9f1a9ec99f0e',
- ext: { rtiPartner: 'pubcid' }
- }
- ]
- }
- ]
- }
- });
-
- expect(payload.user.ext.eids).to.be.an('array');
- expect(payload.user.ext.eids).to.have.lengthOf(4);
+ expect(payload).to.exist;
+ expect(payload.user).to.deep.equal({ext: {eids: [{source: 'criteo.com', uids: [{id: id, atype: 1, ext: {rtiPartner: 'criteoId'}}]}]}});
});
- it('should remove malformed ids that would otherwise break call', function () {
- let tdidId = '6bca7f6b-a98a-46c0-be05-6020f7604598';
- let idlEnvId = null; // fail; can't be null
- let criteoId = '53e30ea700424f7bbdd793b02abc5d7';
- let pubcid = ''; // fail; can't be empty string
-
- let bidRequestsMultiple = [
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } }
- ];
-
- let request = tripleliftAdapterSpec.buildRequests(bidRequestsMultiple, bidderRequest);
- let payload = request.data;
-
- expect(payload.user).to.deep.equal({
- ext: {
- eids: [
- {
- source: 'adserver.org',
- uids: [
- {
- id: tdidId,
- ext: { rtiPartner: 'TDID' }
- }
- ],
- },
+ it('should add tdid and criteoId to the payload if both are included', function () {
+ const tdid = '6bca7f6b-a98a-46c0-be05-6020f7604598';
+ const criteoId = '53e30ea700424f7bbdd793b02abc5d7';
+ bidRequests[0].userIdAsEids = [
+ {
+ source: 'adserver.org',
+ uids: [
{
- source: 'criteo.com',
- uids: [
- {
- id: criteoId,
- ext: { rtiPartner: 'criteoId' }
- }
- ]
+ atype: 1,
+ ext: {
+ rtiPartner: 'TDID'
+ },
+ id: tdid
}
]
- }
- });
-
- expect(payload.user.ext.eids).to.be.an('array');
- expect(payload.user.ext.eids).to.have.lengthOf(2);
-
- tdidId = {}; // fail; can't be empty object
- idlEnvId = { id: '987654' }; // pass
- criteoId = [{ id: '123456' }]; // fail; can't be an array
- pubcid = '3261d8ad-435d-481d-abd1-9f1a9ec99f0e'; // pass
-
- bidRequestsMultiple = [
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } }
- ];
-
- request = tripleliftAdapterSpec.buildRequests(bidRequestsMultiple, bidderRequest);
- payload = request.data;
-
- expect(payload.user).to.deep.equal({
- ext: {
- eids: [
- {
- source: 'liveramp.com',
- uids: [
- {
- id: '987654',
- ext: { rtiPartner: 'idl' }
- }
- ]
- },
+ },
+ {
+ source: 'criteo.com',
+ uids: [
{
- source: 'pubcid.org',
- uids: [
- {
- id: pubcid,
- ext: { rtiPartner: 'pubcid' }
- }
- ]
+ atype: 1,
+ ext: {
+ rtiPartner: 'criteoId'
+ },
+ id: criteoId
}
]
- }
- });
-
- expect(payload.user.ext.eids).to.be.an('array');
- expect(payload.user.ext.eids).to.have.lengthOf(2);
-
- tdidId = { id: '987654' }; // pass
- idlEnvId = { id: 987654 }; // fail; can't be an int
- criteoId = '53e30ea700424f7bbdd793b02abc5d7'; // pass
- pubcid = { id: '' }; // fail; can't be an empty string
-
- bidRequestsMultiple = [
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } },
- { ...bidRequests[0], userId: { tdid: tdidId, idl_env: idlEnvId, criteoId, pubcid } }
+ },
];
- request = tripleliftAdapterSpec.buildRequests(bidRequestsMultiple, bidderRequest);
- payload = request.data;
+ const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest);
+ const payload = request.data;
+ expect(payload).to.exist;
expect(payload.user).to.deep.equal({
ext: {
eids: [
@@ -995,7 +820,8 @@ describe('triplelift adapter', function () {
source: 'adserver.org',
uids: [
{
- id: '987654',
+ id: tdid,
+ atype: 1,
ext: { rtiPartner: 'TDID' }
}
],
@@ -1005,6 +831,7 @@ describe('triplelift adapter', function () {
uids: [
{
id: criteoId,
+ atype: 1,
ext: { rtiPartner: 'criteoId' }
}
]
diff --git a/test/spec/modules/ucfunnelBidAdapter_spec.js b/test/spec/modules/ucfunnelBidAdapter_spec.js
index 9bec7229450..998e0db6fe8 100644
--- a/test/spec/modules/ucfunnelBidAdapter_spec.js
+++ b/test/spec/modules/ucfunnelBidAdapter_spec.js
@@ -30,7 +30,7 @@ const validBannerBidReq = {
params: {
adid: 'ad-34BBD2AA24B678BBFD4E7B9EE3B872D'
},
- sizes: [[300, 250]],
+ sizes: [[300, 250], [336, 280]],
bidId: '263be71e91dd9d',
auctionId: '9ad1fa8d-2297-4660-a018-b39945054746',
ortb2Imp: {
@@ -180,15 +180,15 @@ describe('ucfunnel Adapter', function () {
expect(data.schain).to.equal('1.0,1!exchange1.com,1234,1,bid-request-1,publisher,publisher.com');
});
- it('must parse bid size from a nested array', function () {
- const width = 640;
- const height = 480;
- const bid = deepClone(validBannerBidReq);
- bid.sizes = [[ width, height ]];
- const requests = spec.buildRequests([ bid ], bidderRequest);
+ it('should support multiple size', function () {
+ const sizes = [[300, 250], [336, 280]];
+ const format = '300,250;336,280';
+ validBannerBidReq.sizes = sizes;
+ const requests = spec.buildRequests([ validBannerBidReq ], bidderRequest);
const data = requests[0].data;
- expect(data.w).to.equal(width);
- expect(data.h).to.equal(height);
+ expect(data.w).to.equal(sizes[0][0]);
+ expect(data.h).to.equal(sizes[0][1]);
+ expect(data.format).to.equal(format);
});
it('should set bidfloor if configured', function() {
diff --git a/test/spec/modules/uid2IdSystem_helpers.js b/test/spec/modules/uid2IdSystem_helpers.js
index 5006a50dedd..e0bef047acb 100644
--- a/test/spec/modules/uid2IdSystem_helpers.js
+++ b/test/spec/modules/uid2IdSystem_helpers.js
@@ -26,12 +26,12 @@ export const runAuction = async () => {
}
export const apiHelpers = {
- makeTokenResponse: (token, shouldRefresh = false, expired = false) => ({
+ makeTokenResponse: (token, shouldRefresh = false, expired = false, refreshExpired = false) => ({
advertising_token: token,
refresh_token: 'fake-refresh-token',
identity_expires: expired ? Date.now() - 1000 : Date.now() + 60 * 60 * 1000,
refresh_from: shouldRefresh ? Date.now() - 1000 : Date.now() + 60 * 1000,
- refresh_expires: Date.now() + 24 * 60 * 60 * 1000, // 24 hours
+ refresh_expires: refreshExpired ? Date.now() - 1000 : Date.now() + 24 * 60 * 60 * 1000, // 24 hours
refresh_response_key: 'wR5t6HKMfJ2r4J7fEGX9Gw==', // Fake data
}),
respondAfterDelay: (delay, srv = server) => new Promise((resolve) => setTimeout(() => {
diff --git a/test/spec/modules/uid2IdSystem_spec.js b/test/spec/modules/uid2IdSystem_spec.js
index f33060869df..901e0c57e32 100644
--- a/test/spec/modules/uid2IdSystem_spec.js
+++ b/test/spec/modules/uid2IdSystem_spec.js
@@ -1,6 +1,6 @@
/* eslint-disable no-console */
-import {coreStorage, init, setSubmoduleRegistry, requestBidsHook} from 'modules/userId/index.js';
+import {coreStorage, init, setSubmoduleRegistry} from 'modules/userId/index.js';
import {config} from 'src/config.js';
import * as utils from 'src/utils.js';
import { uid2IdSubmodule } from 'modules/uid2IdSystem.js';
@@ -11,6 +11,7 @@ import { configureTimerInterceptors } from 'test/mocks/timers.js';
import { cookieHelpers, runAuction, apiHelpers, setGdprApplies } from './uid2IdSystem_helpers.js';
import {hook} from 'src/hook.js';
import {uninstall as uninstallGdprEnforcement} from 'modules/gdprEnforcement.js';
+import {server} from 'test/mocks/xhr';
let expect = require('chai').expect;
@@ -23,16 +24,22 @@ const auctionDelayMs = 10;
const initialToken = `initial-advertising-token`;
const legacyToken = 'legacy-advertising-token';
const refreshedToken = 'refreshed-advertising-token';
+const clientSideGeneratedToken = 'client-side-generated-advertising-token';
const legacyConfigParams = {storage: null};
const serverCookieConfigParams = { uid2ServerCookie: publisherCookieName };
const newServerCookieConfigParams = { uid2Cookie: publisherCookieName };
+const cstgConfigParams = { serverPublicKey: 'UID2-X-L-24B8a/eLYBmRkXA9yPgRZt+ouKbXewG2OPs23+ov3JC8mtYJBCx6AxGwJ4MlwUcguebhdDp2CvzsCgS9ogwwGA==', subscriptionId: 'subscription-id' }
const makeUid2IdentityContainer = (token) => ({uid2: {id: token}});
let useLocalStorage = false;
const makePrebidConfig = (params = null, extraSettings = {}, debug = false) => ({
userSync: { auctionDelay: auctionDelayMs, userIds: [{name: 'uid2', params: {storage: useLocalStorage ? 'localStorage' : 'cookie', ...params}}] }, debug, ...extraSettings
});
+const makeOriginalIdentity = (identity, salt = 1) => ({
+ identity: utils.cyrb53Hash(identity, salt),
+ salt
+})
const getFromAppropriateStorage = () => {
if (useLocalStorage) return coreStorage.getDataFromLocalStorage(moduleCookieName);
@@ -46,15 +53,18 @@ const expectGlobalToHaveToken = (token) => expect(getGlobal().getUserIds()).to.d
const expectGlobalToHaveNoUid2 = () => expect(getGlobal().getUserIds()).to.not.haveOwnProperty('uid2');
const expectNoLegacyToken = (bid) => expect(bid.userId).to.not.deep.include(makeUid2IdentityContainer(legacyToken));
const expectModuleStorageEmptyOrMissing = () => expect(getFromAppropriateStorage()).to.be.null;
-const expectModuleStorageToContain = (initialIdentity, latestIdentity) => {
+const expectModuleStorageToContain = (originalAdvertisingToken, latestAdvertisingToken, originalIdentity) => {
const cookie = JSON.parse(getFromAppropriateStorage());
- if (initialIdentity) expect(cookie.originalToken.advertising_token).to.equal(initialIdentity);
- if (latestIdentity) expect(cookie.latestToken.advertising_token).to.equal(latestIdentity);
+ if (originalAdvertisingToken) expect(cookie.originalToken.advertising_token).to.equal(originalAdvertisingToken);
+ if (latestAdvertisingToken) expect(cookie.latestToken.advertising_token).to.equal(latestAdvertisingToken);
+ if (originalIdentity) expect(cookie.originalIdentity).to.eql(makeOriginalIdentity(Object.values(originalIdentity)[0], cookie.originalIdentity.salt));
}
-const apiUrl = 'https://prod.uidapi.com/v2/token/refresh';
+const apiUrl = 'https://prod.uidapi.com/v2/token'
+const refreshApiUrl = `${apiUrl}/refresh`;
const headers = { 'Content-Type': 'application/json' };
-const makeSuccessResponseBody = () => btoa(JSON.stringify({ status: 'success', body: { ...apiHelpers.makeTokenResponse(initialToken), advertising_token: refreshedToken } }));
+const makeSuccessResponseBody = (responseToken) => btoa(JSON.stringify({ status: 'success', body: { ...apiHelpers.makeTokenResponse(initialToken), advertising_token: responseToken } }));
+const cstgApiUrl = `${apiUrl}/client-generate`;
const testCookieAndLocalStorage = (description, test, only = false) => {
const describeFn = only ? describe.only : describe;
@@ -76,7 +86,7 @@ const testCookieAndLocalStorage = (description, test, only = false) => {
};
describe(`UID2 module`, function () {
- let server, suiteSandbox, testSandbox, timerSpy, fullTestTitle, restoreSubtleToUndefined = false;
+ let suiteSandbox, testSandbox, timerSpy, fullTestTitle, restoreSubtleToUndefined = false;
before(function () {
timerSpy = configureTimerInterceptors(debugOutput);
hook.ready();
@@ -87,10 +97,18 @@ describe(`UID2 module`, function () {
// I've confirmed it's available in Firefox since v34 (it seems to be unavailable on BrowserStack in Firefox v106).
if (typeof window.crypto.subtle === 'undefined') {
restoreSubtleToUndefined = true;
- window.crypto.subtle = { importKey: () => {}, decrypt: () => {} };
+ window.crypto.subtle = { importKey: () => {}, digest: () => {}, decrypt: () => {}, deriveKey: () => {}, encrypt: () => {}, generateKey: () => {}, exportKey: () => {} };
}
suiteSandbox.stub(window.crypto.subtle, 'importKey').callsFake(() => Promise.resolve());
+ suiteSandbox.stub(window.crypto.subtle, 'digest').callsFake(() => Promise.resolve('hashed_value'));
suiteSandbox.stub(window.crypto.subtle, 'decrypt').callsFake((settings, key, data) => Promise.resolve(new Uint8Array([...settings.iv, ...data])));
+ suiteSandbox.stub(window.crypto.subtle, 'deriveKey').callsFake(() => Promise.resolve());
+ suiteSandbox.stub(window.crypto.subtle, 'exportKey').callsFake(() => Promise.resolve());
+ suiteSandbox.stub(window.crypto.subtle, 'encrypt').callsFake(() => Promise.resolve(new ArrayBuffer()));
+ suiteSandbox.stub(window.crypto.subtle, 'generateKey').callsFake(() => Promise.resolve({
+ privateKey: {},
+ publicKey: {}
+ }));
});
after(function () {
@@ -99,18 +117,18 @@ describe(`UID2 module`, function () {
if (restoreSubtleToUndefined) window.crypto.subtle = undefined;
});
- const configureUid2Response = (httpStatus, response) => server.respondWith('POST', apiUrl, (xhr) => xhr.respond(httpStatus, headers, response));
- const configureUid2ApiSuccessResponse = () => configureUid2Response(200, makeSuccessResponseBody());
- const configureUid2ApiFailResponse = () => configureUid2Response(500, 'Error');
+ const configureUid2Response = (apiUrl, httpStatus, response) => server.respondWith('POST', apiUrl, (xhr) => xhr.respond(httpStatus, headers, response));
+ const configureUid2ApiSuccessResponse = (apiUrl, responseToken) => configureUid2Response(apiUrl, 200, makeSuccessResponseBody(responseToken));
+ const configureUid2ApiFailResponse = (apiUrl) => configureUid2Response(apiUrl, 500, 'Error');
// Runs the provided test twice - once with a successful API mock, once with one which returns a server error
- const testApiSuccessAndFailure = (act, testDescription, failTestDescription, only = false) => {
+ const testApiSuccessAndFailure = (act, apiUrl, testDescription, failTestDescription, only = false, responseToken = refreshedToken) => {
const testFn = only ? it.only : it;
testFn(`API responds successfully: ${testDescription}`, async function() {
- configureUid2ApiSuccessResponse();
+ configureUid2ApiSuccessResponse(apiUrl, responseToken);
await act(true);
});
testFn(`API responds with an error: ${failTestDescription ?? testDescription}`, async function() {
- configureUid2ApiFailResponse();
+ configureUid2ApiFailResponse(apiUrl);
await act(false);
});
}
@@ -123,8 +141,6 @@ describe(`UID2 module`, function () {
debugOutput(fullTestTitle);
testSandbox = sinon.sandbox.create();
testSandbox.stub(utils, 'logWarn');
- server = sinon.createFakeServer();
-
init(config);
setSubmoduleRegistry([uid2IdSubmodule]);
});
@@ -151,13 +167,13 @@ describe(`UID2 module`, function () {
it('When no baseUrl is provided in config, the module calls the production endpoint', function() {
const uid2Token = apiHelpers.makeTokenResponse(initialToken, true, true);
config.setConfig(makePrebidConfig({uid2Token}));
- expect(server.requests[0]?.url).to.have.string('https://prod.uidapi.com/');
+ expect(server.requests[0]?.url).to.have.string('https://prod.uidapi.com/v2/token/refresh');
});
it('When a baseUrl is provided in config, the module calls the provided endpoint', function() {
const uid2Token = apiHelpers.makeTokenResponse(initialToken, true, true);
config.setConfig(makePrebidConfig({uid2Token, uid2ApiBase: 'https://operator-integ.uidapi.com'}));
- expect(server.requests[0]?.url).to.have.string('https://operator-integ.uidapi.com/');
+ expect(server.requests[0]?.url).to.have.string('https://operator-integ.uidapi.com/v2/token/refresh');
});
});
@@ -238,7 +254,7 @@ describe(`UID2 module`, function () {
cookieHelpers.setPublisherCookie(publisherCookieName, token);
config.setConfig(makePrebidConfig(serverCookieConfigParams, extraConfig));
},
- }
+ },
]
scenarios.forEach(function(scenario) {
@@ -252,7 +268,7 @@ describe(`UID2 module`, function () {
if (apiSucceeds) expectToken(bid, refreshedToken);
else expectNoIdentity(bid);
- }, 'it should be used in the auction', 'the auction should have no uid2');
+ }, refreshApiUrl, 'it should be used in the auction', 'the auction should have no uid2');
testApiSuccessAndFailure(async function(apiSucceeds) {
scenario.setConfig(apiHelpers.makeTokenResponse(initialToken, true, true));
@@ -264,14 +280,14 @@ describe(`UID2 module`, function () {
} else {
expectModuleStorageEmptyOrMissing();
}
- }, 'the refreshed token should be stored in the module storage', 'the module storage should not be set');
+ }, refreshApiUrl, 'the refreshed token should be stored in the module storage', 'the module storage should not be set');
});
describe(`when the response doesn't arrive before the auction timer`, function() {
testApiSuccessAndFailure(async function() {
scenario.setConfig(apiHelpers.makeTokenResponse(initialToken, true, true));
const bid = await runAuction();
expectNoIdentity(bid);
- }, 'it should run the auction');
+ }, refreshApiUrl, 'it should run the auction');
testApiSuccessAndFailure(async function(apiSucceeds) {
scenario.setConfig(apiHelpers.makeTokenResponse(initialToken, true, true));
@@ -283,7 +299,7 @@ describe(`UID2 module`, function () {
await promise;
if (apiSucceeds) expectGlobalToHaveToken(refreshedToken);
else expectGlobalToHaveNoUid2();
- }, 'it should update the userId after the auction', 'there should be no global identity');
+ }, refreshApiUrl, 'it should update the userId after the auction', 'there should be no global identity');
})
describe('and there is a refreshed token in the module cookie', function() {
it('the refreshed value from the cookie is used', async function() {
@@ -322,7 +338,7 @@ describe(`UID2 module`, function () {
apiHelpers.respondAfterDelay(10, server);
const bid = await runAuction();
expectToken(bid, initialToken);
- }, 'it should not be refreshed before the auction runs');
+ }, refreshApiUrl, 'it should not be refreshed before the auction runs');
testApiSuccessAndFailure(async function(success) {
const promise = apiHelpers.respondAfterDelay(1, server);
@@ -333,7 +349,7 @@ describe(`UID2 module`, function () {
} else {
expectModuleStorageToContain(initialToken, initialToken);
}
- }, 'the refreshed token should be stored in the module cookie after the auction runs', 'the module cookie should only have the original token');
+ }, refreshApiUrl, 'the refreshed token should be stored in the module cookie after the auction runs', 'the module cookie should only have the original token');
it('it should use the current token in the auction', async function() {
const bid = await runAuction();
@@ -342,4 +358,273 @@ describe(`UID2 module`, function () {
});
});
});
+
+ if (FEATURES.UID2_CSTG) {
+ describe('When CSTG is enabled provided', function () {
+ const scenarios = [
+ {
+ name: 'email provided in config',
+ identity: { email: 'test@example.com' },
+ setConfig: function (extraConfig) { config.setConfig(makePrebidConfig({ ...cstgConfigParams, ...this.identity }, extraConfig)) },
+ setInvalidConfig: (extraConfig) => config.setConfig(makePrebidConfig({ ...cstgConfigParams, email: 'test . test@gmail.com' }, extraConfig))
+ },
+ {
+ name: 'phone provided in config',
+ identity: { phone: '+12345678910' },
+ setConfig: function (extraConfig) { config.setConfig(makePrebidConfig({ ...cstgConfigParams, ...this.identity }, extraConfig)) },
+ setInvalidConfig: (extraConfig) => config.setConfig(makePrebidConfig({ ...cstgConfigParams, phone: 'test123' }, extraConfig))
+ },
+ {
+ name: 'email hash provided in config',
+ identity: { email_hash: 'lz3+Rj7IV4X1+Vr1ujkG7tstkxwk5pgkqJ6mXbpOgTs=' },
+ setConfig: function (extraConfig) { config.setConfig(makePrebidConfig({ ...cstgConfigParams, emailHash: this.identity.email_hash }, extraConfig)) },
+ setInvalidConfig: (extraConfig) => config.setConfig(makePrebidConfig({ ...cstgConfigParams, emailHash: 'test@example.com' }, extraConfig))
+ },
+ {
+ name: 'phone hash provided in config',
+ identity: { phone_hash: 'kVJ+4ilhrqm3HZDDnCQy4niZknvCoM4MkoVzZrQSdJw=' },
+ setConfig: function (extraConfig) { config.setConfig(makePrebidConfig({ ...cstgConfigParams, phoneHash: this.identity.phone_hash }, extraConfig)) },
+ setInvalidConfig: (extraConfig) => config.setConfig(makePrebidConfig({ ...cstgConfigParams, phoneHash: '614332222111' }, extraConfig))
+ },
+ ]
+ scenarios.forEach(function(scenario) {
+ describe(`And ${scenario.name}`, function() {
+ describe(`When invalid identity is provided`, function() {
+ it('the auction should have no uid2', async function () {
+ scenario.setInvalidConfig()
+ const bid = await runAuction();
+ expectNoIdentity(bid);
+ expectGlobalToHaveNoUid2();
+ expectModuleStorageEmptyOrMissing();
+ })
+ });
+
+ describe('When valid identity is provided, and the auction is set to run immediately', function() {
+ it('it should ignores token provided in config, and the auction should have no uid2', async function() {
+ scenario.setConfig({ uid2Token: apiHelpers.makeTokenResponse(initialToken), auctionDelay: 0, syncDelay: 1 });
+ const bid = await runAuction();
+ expectNoIdentity(bid);
+ expectGlobalToHaveNoUid2();
+ expectModuleStorageEmptyOrMissing();
+ })
+
+ it('it should ignores token provided in server-set cookie', async function() {
+ cookieHelpers.setPublisherCookie(publisherCookieName, initialToken);
+ scenario.setConfig({ ...newServerCookieConfigParams, auctionDelay: 0, syncDelay: 1 })
+ const bid = await runAuction();
+ expectNoIdentity(bid);
+ expectGlobalToHaveNoUid2();
+ expectModuleStorageEmptyOrMissing();
+ })
+
+ describe('When the token generated in time', function() {
+ testApiSuccessAndFailure(async function(apiSucceeds) {
+ scenario.setConfig();
+ apiHelpers.respondAfterDelay(auctionDelayMs / 10, server);
+ const bid = await runAuction();
+
+ if (apiSucceeds) expectToken(bid, clientSideGeneratedToken);
+ else expectNoIdentity(bid);
+ }, cstgApiUrl, 'it should be used in the auction', 'the auction should have no uid2', false, clientSideGeneratedToken);
+
+ testApiSuccessAndFailure(async function(apiSucceeds) {
+ scenario.setConfig();
+ apiHelpers.respondAfterDelay(auctionDelayMs / 10, server);
+
+ await runAuction();
+ if (apiSucceeds) {
+ expectModuleStorageToContain(undefined, clientSideGeneratedToken, scenario.identity);
+ } else {
+ expectModuleStorageEmptyOrMissing();
+ }
+ }, cstgApiUrl, 'the generated token should be stored in the module storage', 'the module storage should not be set', false, clientSideGeneratedToken);
+ });
+ });
+ });
+ });
+ describe(`when the response doesn't arrive before the auction timer`, function() {
+ testApiSuccessAndFailure(async function() {
+ config.setConfig(makePrebidConfig({ ...cstgConfigParams, email: 'test@test.com' }));
+ const bid = await runAuction();
+ expectNoIdentity(bid);
+ }, cstgApiUrl, 'it should run the auction', undefined, false, clientSideGeneratedToken);
+
+ testApiSuccessAndFailure(async function(apiSucceeds) {
+ config.setConfig(makePrebidConfig({ ...cstgConfigParams, email: 'test@test.com' }));
+ const promise = apiHelpers.respondAfterDelay(auctionDelayMs * 2, server);
+
+ const bid = await runAuction();
+ expectNoIdentity(bid);
+ expectGlobalToHaveNoUid2();
+ await promise;
+ if (apiSucceeds) expectGlobalToHaveToken(clientSideGeneratedToken);
+ else expectGlobalToHaveNoUid2();
+ }, cstgApiUrl, 'it should update the userId after the auction', 'there should be no global identity', false, clientSideGeneratedToken);
+ })
+
+ describe('when there is a token in the module cookie', function() {
+ describe('when originalIdentity matches', function() {
+ describe('When the storedToken is valid', function() {
+ it('it should use the stored token in the auction', async function() {
+ const refreshedIdentity = apiHelpers.makeTokenResponse(refreshedToken);
+ const moduleCookie = {originalIdentity: makeOriginalIdentity('test@test.com'), latestToken: refreshedIdentity};
+ coreStorage.setCookie(moduleCookieName, JSON.stringify(moduleCookie), cookieHelpers.getFutureCookieExpiry());
+ config.setConfig(makePrebidConfig({ ...cstgConfigParams, email: 'test@test.com', auctionDelay: 0, syncDelay: 1 }));
+ const bid = await runAuction();
+ expectToken(bid, refreshedToken);
+ });
+ })
+
+ describe('When the storedToken is expired and can be refreshed ', function() {
+ testApiSuccessAndFailure(async function(apiSucceeds) {
+ const refreshedIdentity = apiHelpers.makeTokenResponse(refreshedToken, true, true);
+ const moduleCookie = {originalIdentity: makeOriginalIdentity('test@test.com'), latestToken: refreshedIdentity};
+ coreStorage.setCookie(moduleCookieName, JSON.stringify(moduleCookie), cookieHelpers.getFutureCookieExpiry());
+ config.setConfig(makePrebidConfig({ ...cstgConfigParams, email: 'test@test.com' }));
+ apiHelpers.respondAfterDelay(auctionDelayMs / 10, server);
+
+ const bid = await runAuction();
+
+ if (apiSucceeds) expectToken(bid, refreshedToken);
+ else expectNoIdentity(bid);
+ }, refreshApiUrl, 'it should use refreshed token in the auction', 'the auction should have no uid2');
+ })
+
+ describe('When the storedToken is expired for refresh', function() {
+ testApiSuccessAndFailure(async function(apiSucceeds) {
+ const refreshedIdentity = apiHelpers.makeTokenResponse(refreshedToken, true, true, true);
+ const moduleCookie = {originalIdentity: makeOriginalIdentity('test@test.com'), latestToken: refreshedIdentity};
+ coreStorage.setCookie(moduleCookieName, JSON.stringify(moduleCookie), cookieHelpers.getFutureCookieExpiry());
+ config.setConfig(makePrebidConfig({ ...cstgConfigParams, email: 'test@test.com' }));
+ apiHelpers.respondAfterDelay(auctionDelayMs / 10, server);
+
+ const bid = await runAuction();
+
+ if (apiSucceeds) expectToken(bid, clientSideGeneratedToken);
+ else expectNoIdentity(bid);
+ }, cstgApiUrl, 'it should use generated token in the auction', 'the auction should have no uid2', false, clientSideGeneratedToken);
+ })
+ })
+
+ it('when originalIdentity not match, the auction should has no uid2', async function() {
+ const refreshedIdentity = apiHelpers.makeTokenResponse(refreshedToken);
+ const moduleCookie = {originalIdentity: makeOriginalIdentity('123@test.com'), latestToken: refreshedIdentity};
+ coreStorage.setCookie(moduleCookieName, JSON.stringify(moduleCookie), cookieHelpers.getFutureCookieExpiry());
+ config.setConfig(makePrebidConfig({ ...cstgConfigParams, email: 'test@test.com' }));
+ const bid = await runAuction();
+ expectNoIdentity(bid);
+ });
+ })
+ });
+ describe('When invalid CSTG configuration is provided', function () {
+ const invalidConfigs = [
+ {
+ name: 'CSTG option is not a object',
+ cstgOptions: ''
+ },
+ {
+ name: 'CSTG option is null',
+ cstgOptions: ''
+ },
+ {
+ name: 'serverPublicKey is not a string',
+ cstgOptions: { subscriptionId: cstgConfigParams.subscriptionId, serverPublicKey: {} }
+ },
+ {
+ name: 'serverPublicKey not match regular expression',
+ cstgOptions: { subscriptionId: cstgConfigParams.subscriptionId, serverPublicKey: 'serverPublicKey' }
+ },
+ {
+ name: 'subscriptionId is not a string',
+ cstgOptions: { subscriptionId: {}, serverPublicKey: cstgConfigParams.serverPublicKey }
+ },
+ {
+ name: 'subscriptionId is empty',
+ cstgOptions: { subscriptionId: '', serverPublicKey: cstgConfigParams.serverPublicKey }
+ },
+ ]
+ invalidConfigs.forEach(function(scenario) {
+ describe(`When ${scenario.name}`, function() {
+ it('should not generate token using identity', async () => {
+ config.setConfig(makePrebidConfig({ ...scenario.cstgOptions, email: 'test@email.com' }));
+ const bid = await runAuction();
+ expectNoIdentity(bid);
+ expectGlobalToHaveNoUid2();
+ expectModuleStorageEmptyOrMissing();
+ });
+ });
+ });
+ });
+ describe('When email is provided in different format', function () {
+ const testCases = [
+ { originalEmail: 'TEst.TEST@Test.com ', normalizedEmail: 'test.test@test.com' },
+ { originalEmail: 'test+test@test.com', normalizedEmail: 'test+test@test.com' },
+ { originalEmail: ' testtest@test.com ', normalizedEmail: 'testtest@test.com' },
+ { originalEmail: 'TEst.TEst+123@GMail.Com', normalizedEmail: 'testtest@gmail.com' }
+ ];
+ testCases.forEach((testCase) => {
+ describe('it should normalize the email and generate token on normalized email', async () => {
+ testApiSuccessAndFailure(async function(apiSucceeds) {
+ config.setConfig(makePrebidConfig({ ...cstgConfigParams, email: testCase.originalEmail }));
+ apiHelpers.respondAfterDelay(auctionDelayMs / 10, server);
+
+ await runAuction();
+ if (apiSucceeds) {
+ expectModuleStorageToContain(undefined, clientSideGeneratedToken, { email: testCase.normalizedEmail });
+ } else {
+ expectModuleStorageEmptyOrMissing();
+ }
+ }, cstgApiUrl, 'the generated token should be stored in the module storage', 'the module storage should not be set', false, clientSideGeneratedToken);
+ });
+ });
+ });
+ }
+
+ describe('When neither token nor CSTG config provided', function () {
+ describe('when there is a non-cstg-derived token in the module cookie', function () {
+ it('the auction use stored token if it is valid', async function () {
+ const originalIdentity = apiHelpers.makeTokenResponse(initialToken);
+ const moduleCookie = {originalToken: originalIdentity, latestToken: originalIdentity};
+ coreStorage.setCookie(moduleCookieName, JSON.stringify(moduleCookie), cookieHelpers.getFutureCookieExpiry());
+ config.setConfig(makePrebidConfig({}));
+ const bid = await runAuction();
+ expectToken(bid, initialToken);
+ })
+
+ it('the auction should has no uid2 if stored token is invalid', async function () {
+ const originalIdentity = apiHelpers.makeTokenResponse(initialToken, true, true, true);
+ const moduleCookie = {originalToken: originalIdentity, latestToken: originalIdentity};
+ coreStorage.setCookie(moduleCookieName, JSON.stringify(moduleCookie), cookieHelpers.getFutureCookieExpiry());
+ config.setConfig(makePrebidConfig({}));
+ const bid = await runAuction();
+ expectNoIdentity(bid);
+ })
+ })
+
+ describe('when there is a cstg-derived token in the module cookie', function () {
+ it('the auction use stored token if it is valid', async function () {
+ const originalIdentity = apiHelpers.makeTokenResponse(initialToken);
+ const moduleCookie = {originalIdentity: makeOriginalIdentity('123@test.com'), originalToken: originalIdentity, latestToken: originalIdentity};
+ coreStorage.setCookie(moduleCookieName, JSON.stringify(moduleCookie), cookieHelpers.getFutureCookieExpiry());
+ config.setConfig(makePrebidConfig({}));
+ const bid = await runAuction();
+ expectToken(bid, initialToken);
+ })
+
+ it('the auction should has no uid2 if stored token is invalid', async function () {
+ const originalIdentity = apiHelpers.makeTokenResponse(initialToken, true, true, true);
+ const moduleCookie = {originalIdentity: makeOriginalIdentity('123@test.com'), originalToken: originalIdentity, latestToken: originalIdentity};
+ coreStorage.setCookie(moduleCookieName, JSON.stringify(moduleCookie), cookieHelpers.getFutureCookieExpiry());
+ config.setConfig(makePrebidConfig({}));
+ const bid = await runAuction();
+ expectNoIdentity(bid);
+ })
+ })
+
+ it('the auction should has no uid2', async function () {
+ config.setConfig(makePrebidConfig({}));
+ const bid = await runAuction();
+ expectNoIdentity(bid);
+ })
+ })
});
diff --git a/test/spec/modules/underdogmediaBidAdapter_spec.js b/test/spec/modules/underdogmediaBidAdapter_spec.js
index 2d7c1f11178..c0e2e8dddce 100644
--- a/test/spec/modules/underdogmediaBidAdapter_spec.js
+++ b/test/spec/modules/underdogmediaBidAdapter_spec.js
@@ -5,6 +5,7 @@ import {
spec,
resetUserSync
} from 'modules/underdogmediaBidAdapter.js';
+import { config } from '../../../src/config';
describe('UnderdogMedia adapter', function () {
let bidRequests;
@@ -763,6 +764,20 @@ describe('UnderdogMedia adapter', function () {
expect(request.data.ref).to.equal(undefined);
});
+ it('should have pbTimeout to be 3001 if bidder timeout does not exists', function () {
+ config.setConfig({ bidderTimeout: '' })
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+
+ expect(request.data.pbTimeout).to.equal(3001)
+ })
+
+ it('should have pbTimeout to be a numerical value if bidder timeout is in a string', function () {
+ config.setConfig({ bidderTimeout: '1000' })
+ const request = spec.buildRequests(bidRequests, bidderRequest);
+
+ expect(request.data.pbTimeout).to.equal(1000)
+ })
+
it('should have pubcid if it exists', function () {
let bidRequests = [{
adUnitCode: 'div-gpt-ad-1460505748561-0',
diff --git a/test/spec/modules/unicornBidAdapter_spec.js b/test/spec/modules/unicornBidAdapter_spec.js
index 0abb09bfb78..bd9175dac1e 100644
--- a/test/spec/modules/unicornBidAdapter_spec.js
+++ b/test/spec/modules/unicornBidAdapter_spec.js
@@ -1,4 +1,5 @@
import {assert, expect} from 'chai';
+import * as utils from 'src/utils.js';
import {spec} from 'modules/unicornBidAdapter.js';
import * as _ from 'lodash';
@@ -496,6 +497,17 @@ describe('unicornBidAdapterTest', () => {
});
describe('buildBidRequest', () => {
+ const removeUntestableAttrs = data => {
+ delete data['device'];
+ delete data['site']['domain'];
+ delete data['site']['page'];
+ delete data['id'];
+ data['imp'].forEach(imp => {
+ delete imp['id'];
+ })
+ delete data['user']['id'];
+ return data;
+ };
before(function () {
$$PREBID_GLOBAL$$.bidderSettings = {
unicorn: {
@@ -508,17 +520,6 @@ describe('unicornBidAdapterTest', () => {
});
it('buildBidRequest', () => {
const req = spec.buildRequests(validBidRequests, bidderRequest);
- const removeUntestableAttrs = data => {
- delete data['device'];
- delete data['site']['domain'];
- delete data['site']['page'];
- delete data['id'];
- data['imp'].forEach(imp => {
- delete imp['id'];
- })
- delete data['user']['id'];
- return data;
- };
const uid = JSON.parse(req.data)['user']['id'];
const reqData = removeUntestableAttrs(JSON.parse(req.data));
const openRTBRequestData = removeUntestableAttrs(openRTBRequest);
@@ -527,6 +528,28 @@ describe('unicornBidAdapterTest', () => {
const uid2 = JSON.parse(req2.data)['user']['id'];
assert.deepStrictEqual(uid, uid2);
});
+ it('test if contains ID5', () => {
+ let _validBidRequests = utils.deepClone(validBidRequests);
+ _validBidRequests[0].userId = {
+ id5id: {
+ uid: 'id5_XXXXX'
+ }
+ }
+ const req = spec.buildRequests(_validBidRequests, bidderRequest);
+ const reqData = removeUntestableAttrs(JSON.parse(req.data));
+ const openRTBRequestData = removeUntestableAttrs(utils.deepClone(openRTBRequest));
+ openRTBRequestData.user.eids = [
+ {
+ source: 'id5-sync.com',
+ uids: [
+ {
+ id: 'id5_XXXXX'
+ }
+ ]
+ }
+ ]
+ assert.deepStrictEqual(reqData, openRTBRequestData);
+ })
});
describe('interpretResponse', () => {
diff --git a/test/spec/modules/unrulyBidAdapter_spec.js b/test/spec/modules/unrulyBidAdapter_spec.js
index 6d1d8f9949f..abf1a54787d 100644
--- a/test/spec/modules/unrulyBidAdapter_spec.js
+++ b/test/spec/modules/unrulyBidAdapter_spec.js
@@ -42,9 +42,40 @@ describe('UnrulyAdapter', function () {
}
}
- const createExchangeResponse = (...bids) => ({
- body: {bids}
- });
+ function createOutStreamExchangeAuctionConfig() {
+ return {
+ 'seller': 'https://nexxen.tech',
+ 'decisionLogicURL': 'https://nexxen.tech/padecisionlogic',
+ 'interestGroupBuyers': 'https://mydsp.com',
+ 'perBuyerSignals': {
+ 'https://mydsp.com': {
+ 'floor': 'bouttreefiddy'
+ }
+ }
+ }
+ };
+
+ function createExchangeResponse (bidList, auctionConfigs = null) {
+ let bids = [];
+ if (Array.isArray(bidList)) {
+ bids = bidList;
+ } else if (bidList) {
+ bids.push(bidList);
+ }
+
+ if (!auctionConfigs) {
+ return {
+ 'body': {bids}
+ };
+ }
+
+ return {
+ 'body': {
+ bids,
+ auctionConfigs
+ }
+ }
+ };
const inStreamServerResponse = {
'requestId': '262594d5d1f8104',
@@ -486,7 +517,8 @@ describe('UnrulyAdapter', function () {
'bidderRequestId': '12e00d17dff07b'
}
],
- 'invalidBidsCount': 0
+ 'invalidBidsCount': 0,
+ 'prebidVersion': '$prebid.version$'
}
};
@@ -560,7 +592,8 @@ describe('UnrulyAdapter', function () {
'bidderRequestId': '12e00d17dff07b',
}
],
- 'invalidBidsCount': 0
+ 'invalidBidsCount': 0,
+ 'prebidVersion': '$prebid.version$'
}
};
@@ -651,13 +684,235 @@ describe('UnrulyAdapter', function () {
'bidderRequestId': '12e00d17dff07b',
}
],
- 'invalidBidsCount': 0
+ 'invalidBidsCount': 0,
+ 'prebidVersion': '$prebid.version$'
}
};
let result = adapter.buildRequests(mockBidRequests.bids, mockBidRequests);
expect(result[0].data).to.deep.equal(expectedResult);
});
+ describe('Protected Audience Support', function() {
+ it('should return an array with 2 items and enabled protected audience', function () {
+ mockBidRequests = {
+ 'bidderCode': 'unruly',
+ 'fledgeEnabled': true,
+ 'bids': [
+ {
+ 'bidder': 'unruly',
+ 'params': {
+ 'siteId': 233261,
+ },
+ 'mediaTypes': {
+ 'video': {
+ 'context': 'outstream',
+ 'mimes': [
+ 'video/mp4'
+ ],
+ 'playerSize': [
+ [
+ 640,
+ 480
+ ]
+ ]
+ }
+ },
+ 'adUnitCode': 'video2',
+ 'transactionId': 'a89619e3-137d-4cc5-9ed4-58a0b2a0bbc2',
+ 'sizes': [
+ [
+ 640,
+ 480
+ ]
+ ],
+ 'bidId': '27a3ee1626a5c7',
+ 'bidderRequestId': '12e00d17dff07b',
+ 'ortb2Imp': {
+ 'ext': {
+ 'ae': 1
+ }
+ }
+ },
+ {
+ 'bidder': 'unruly',
+ 'params': {
+ 'siteId': 2234554,
+ },
+ 'mediaTypes': {
+ 'video': {
+ 'context': 'outstream',
+ 'mimes': [
+ 'video/mp4'
+ ],
+ 'playerSize': [
+ [
+ 640,
+ 480
+ ]
+ ]
+ }
+ },
+ 'adUnitCode': 'video2',
+ 'transactionId': 'a89619e3-137d-4cc5-9ed4-58a0b2a0bbc2',
+ 'sizes': [
+ [
+ 640,
+ 480
+ ]
+ ],
+ 'bidId': '27a3ee1626a5c7',
+ 'bidderRequestId': '12e00d17dff07b',
+ 'ortb2Imp': {
+ 'ext': {
+ 'ae': 1
+ }
+ }
+ }
+ ]
+ };
+
+ let result = adapter.buildRequests(mockBidRequests.bids, mockBidRequests);
+ expect(typeof result).to.equal('object');
+ expect(result.length).to.equal(2);
+ expect(result[0].data.bidderRequest.bids.length).to.equal(1);
+ expect(result[1].data.bidderRequest.bids.length).to.equal(1);
+ expect(result[0].data.bidderRequest.bids[0].ortb2Imp.ext.ae).to.equal(1);
+ expect(result[1].data.bidderRequest.bids[0].ortb2Imp.ext.ae).to.equal(1);
+ });
+ it('should return an array with 2 items and enabled protected audience on only one unit', function () {
+ mockBidRequests = {
+ 'bidderCode': 'unruly',
+ 'fledgeEnabled': true,
+ 'bids': [
+ {
+ 'bidder': 'unruly',
+ 'params': {
+ 'siteId': 233261,
+ },
+ 'mediaTypes': {
+ 'video': {
+ 'context': 'outstream',
+ 'mimes': [
+ 'video/mp4'
+ ],
+ 'playerSize': [
+ [
+ 640,
+ 480
+ ]
+ ]
+ }
+ },
+ 'adUnitCode': 'video2',
+ 'transactionId': 'a89619e3-137d-4cc5-9ed4-58a0b2a0bbc2',
+ 'sizes': [
+ [
+ 640,
+ 480
+ ]
+ ],
+ 'bidId': '27a3ee1626a5c7',
+ 'bidderRequestId': '12e00d17dff07b',
+ 'ortb2Imp': {
+ 'ext': {
+ 'ae': 1
+ }
+ }
+ },
+ {
+ 'bidder': 'unruly',
+ 'params': {
+ 'siteId': 2234554,
+ },
+ 'mediaTypes': {
+ 'video': {
+ 'context': 'outstream',
+ 'mimes': [
+ 'video/mp4'
+ ],
+ 'playerSize': [
+ [
+ 640,
+ 480
+ ]
+ ]
+ }
+ },
+ 'adUnitCode': 'video2',
+ 'transactionId': 'a89619e3-137d-4cc5-9ed4-58a0b2a0bbc2',
+ 'sizes': [
+ [
+ 640,
+ 480
+ ]
+ ],
+ 'bidId': '27a3ee1626a5c7',
+ 'bidderRequestId': '12e00d17dff07b',
+ 'ortb2Imp': {
+ 'ext': {}
+ }
+ }
+ ]
+ };
+
+ let result = adapter.buildRequests(mockBidRequests.bids, mockBidRequests);
+ expect(typeof result).to.equal('object');
+ expect(result.length).to.equal(2);
+ expect(result[0].data.bidderRequest.bids.length).to.equal(1);
+ expect(result[1].data.bidderRequest.bids.length).to.equal(1);
+ expect(result[0].data.bidderRequest.bids[0].ortb2Imp.ext.ae).to.equal(1);
+ expect(result[1].data.bidderRequest.bids[0].ortb2Imp.ext.ae).to.be.undefined;
+ });
+ it('disables configured protected audience when fledge is not availble', function () {
+ mockBidRequests = {
+ 'bidderCode': 'unruly',
+ 'fledgeEnabled': false,
+ 'bids': [
+ {
+ 'bidder': 'unruly',
+ 'params': {
+ 'siteId': 233261,
+ },
+ 'mediaTypes': {
+ 'video': {
+ 'context': 'outstream',
+ 'mimes': [
+ 'video/mp4'
+ ],
+ 'playerSize': [
+ [
+ 640,
+ 480
+ ]
+ ]
+ }
+ },
+ 'adUnitCode': 'video2',
+ 'transactionId': 'a89619e3-137d-4cc5-9ed4-58a0b2a0bbc2',
+ 'sizes': [
+ [
+ 640,
+ 480
+ ]
+ ],
+ 'bidId': '27a3ee1626a5c7',
+ 'bidderRequestId': '12e00d17dff07b',
+ 'ortb2Imp': {
+ 'ext': {
+ 'ae': 1
+ }
+ }
+ }
+ ]
+ };
+
+ let result = adapter.buildRequests(mockBidRequests.bids, mockBidRequests);
+ expect(typeof result).to.equal('object');
+ expect(result.length).to.equal(1);
+ expect(result[0].data.bidderRequest.bids.length).to.equal(1);
+ expect(result[0].data.bidderRequest.bids[0].ortb2Imp.ext.ae).to.be.undefined;
+ });
+ });
});
describe('interpretResponse', function () {
@@ -705,7 +960,167 @@ describe('UnrulyAdapter', function () {
renderer: fakeRenderer,
mediaType: 'video'
}
- ])
+ ]);
+ });
+
+ it('should return object with an array of bids and an array of auction configs when it receives a successful response from server', function () {
+ let bidId = '27a3ee1626a5c7'
+ const mockExchangeBid = createOutStreamExchangeBid({adUnitCode: 'video1', requestId: 'mockBidId'});
+ const mockExchangeAuctionConfig = {};
+ mockExchangeAuctionConfig[bidId] = createOutStreamExchangeAuctionConfig();
+ const mockServerResponse = createExchangeResponse(mockExchangeBid, mockExchangeAuctionConfig);
+ const originalRequest = {
+ 'data': {
+ 'bidderRequest': {
+ 'bids': [
+ {
+ 'bidder': 'unruly',
+ 'params': {
+ 'siteId': 233261,
+ },
+ 'mediaTypes': {
+ 'banner': {
+ 'sizes': [
+ [
+ 640,
+ 480
+ ],
+ [
+ 640,
+ 480
+ ],
+ [
+ 300,
+ 250
+ ],
+ [
+ 300,
+ 250
+ ]
+ ]
+ }
+ },
+ 'adUnitCode': 'video2',
+ 'transactionId': 'a89619e3-137d-4cc5-9ed4-58a0b2a0bbc2',
+ 'bidId': bidId,
+ 'bidderRequestId': '12e00d17dff07b',
+ }
+ ]
+ }
+ }
+ };
+
+ expect(adapter.interpretResponse(mockServerResponse, originalRequest)).to.deep.equal({
+ 'bids': [
+ {
+ 'ext': {
+ 'statusCode': 1,
+ 'renderer': {
+ 'id': 'unruly_inarticle',
+ 'config': {
+ 'siteId': 123456,
+ 'targetingUUID': 'xxx-yyy-zzz'
+ },
+ 'url': 'https://video.unrulymedia.com/native/prebid-loader.js'
+ },
+ 'adUnitCode': 'video1'
+ },
+ requestId: 'mockBidId',
+ bidderCode: 'unruly',
+ cpm: 20,
+ width: 323,
+ height: 323,
+ vastUrl: 'https://targeting.unrulymedia.com/in_article?uuid=74544e00-d43b-4f3a-a799-69d22ce979ce&supported_mime_type=application/javascript&supported_mime_type=video/mp4&tj=%7B%22site%22%3A%7B%22lang%22%3A%22en-GB%22%2C%22ref%22%3A%22%22%2C%22page%22%3A%22https%3A%2F%2Fdemo.unrulymedia.com%2FinArticle%2Finarticle_nypost_upbeat%2Ftravel_magazines.html%22%2C%22domain%22%3A%22demo.unrulymedia.com%22%7D%2C%22user%22%3A%7B%22profile%22%3A%7B%22quantcast%22%3A%7B%22segments%22%3A%5B%7B%22id%22%3A%22D%22%7D%2C%7B%22id%22%3A%22T%22%7D%5D%7D%7D%7D%7D&video_width=618&video_height=347',
+ netRevenue: true,
+ creativeId: 'mockBidId',
+ ttl: 360,
+ 'meta': {
+ 'mediaType': 'video',
+ 'videoContext': 'outstream'
+ },
+ currency: 'USD',
+ renderer: fakeRenderer,
+ mediaType: 'video'
+ }
+ ],
+ 'fledgeAuctionConfigs': [{
+ 'bidId': bidId,
+ 'config': {
+ 'seller': 'https://nexxen.tech',
+ 'decisionLogicURL': 'https://nexxen.tech/padecisionlogic',
+ 'interestGroupBuyers': 'https://mydsp.com',
+ 'perBuyerSignals': {
+ 'https://mydsp.com': {
+ 'floor': 'bouttreefiddy'
+ }
+ }
+ }
+ }]
+ });
+ });
+
+ it('should return object with an array of auction configs when it receives a successful response from server without bids', function () {
+ let bidId = '27a3ee1626a5c7';
+ const mockExchangeAuctionConfig = {};
+ mockExchangeAuctionConfig[bidId] = createOutStreamExchangeAuctionConfig();
+ const mockServerResponse = createExchangeResponse(null, mockExchangeAuctionConfig);
+ const originalRequest = {
+ 'data': {
+ 'bidderRequest': {
+ 'bids': [
+ {
+ 'bidder': 'unruly',
+ 'params': {
+ 'siteId': 233261,
+ },
+ 'mediaTypes': {
+ 'banner': {
+ 'sizes': [
+ [
+ 640,
+ 480
+ ],
+ [
+ 640,
+ 480
+ ],
+ [
+ 300,
+ 250
+ ],
+ [
+ 300,
+ 250
+ ]
+ ]
+ }
+ },
+ 'adUnitCode': 'video2',
+ 'transactionId': 'a89619e3-137d-4cc5-9ed4-58a0b2a0bbc2',
+ 'bidId': bidId,
+ 'bidderRequestId': '12e00d17dff07b'
+ }
+ ]
+ }
+ }
+ };
+
+ expect(adapter.interpretResponse(mockServerResponse, originalRequest)).to.deep.equal({
+ 'bids': [],
+ 'fledgeAuctionConfigs': [{
+ 'bidId': bidId,
+ 'config': {
+ 'seller': 'https://nexxen.tech',
+ 'decisionLogicURL': 'https://nexxen.tech/padecisionlogic',
+ 'interestGroupBuyers': 'https://mydsp.com',
+ 'perBuyerSignals': {
+ 'https://mydsp.com': {
+ 'floor': 'bouttreefiddy'
+ }
+ }
+ }
+ }]
+ });
});
it('should initialize and set the renderer', function () {
@@ -875,7 +1290,7 @@ describe('UnrulyAdapter', function () {
it('should return correct response for multiple bids', function () {
const outStreamServerResponse = createOutStreamExchangeBid({adUnitCode: 'video1', requestId: 'mockBidId'});
- const mockServerResponse = createExchangeResponse(outStreamServerResponse, inStreamServerResponse, bannerServerResponse);
+ const mockServerResponse = createExchangeResponse([outStreamServerResponse, inStreamServerResponse, bannerServerResponse]);
const expectedOutStreamResponse = outStreamServerResponse;
expectedOutStreamResponse.mediaType = 'video';
@@ -890,7 +1305,7 @@ describe('UnrulyAdapter', function () {
it('should return only valid bids', function () {
const {ad, ...bannerServerResponseNoAd} = bannerServerResponse;
- const mockServerResponse = createExchangeResponse(bannerServerResponseNoAd, inStreamServerResponse);
+ const mockServerResponse = createExchangeResponse([bannerServerResponseNoAd, inStreamServerResponse]);
const expectedInStreamResponse = inStreamServerResponse;
expectedInStreamResponse.mediaType = 'video';
diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js
index 17a865796a2..1e909d79ed4 100644
--- a/test/spec/modules/userId_spec.js
+++ b/test/spec/modules/userId_spec.js
@@ -12,6 +12,7 @@ import {
setSubmoduleRegistry,
syncDelay,
} from 'modules/userId/index.js';
+import {UID1_EIDS} from 'libraries/uid1Eids/uid1Eids.js';
import {createEidsArray, EID_CONFIG} from 'modules/userId/eids.js';
import {config} from 'src/config.js';
import * as utils from 'src/utils.js';
@@ -99,6 +100,25 @@ describe('User ID', function () {
}
}
+ function createMockEid(name, source) {
+ return {
+ [name]: {
+ source: source || `${name}Source`,
+ atype: 3,
+ getValue: function(data) {
+ if (data.id) {
+ return data.id;
+ } else {
+ return data;
+ }
+ },
+ getUidExt: function(data) {
+ return data.ext
+ }
+ }
+ }
+ }
+
function getAdUnitMock(code = 'adUnit-code') {
return {
code,
@@ -448,7 +468,25 @@ describe('User ID', function () {
]
}
])
- })
+ });
+
+ it('when merging with pubCommonId, should not alter its eids', () => {
+ const uid = {
+ pubProvidedId: [
+ {
+ source: 'mock1Source',
+ uids: [
+ {id: 'uid2'}
+ ]
+ }
+ ],
+ mockId1: 'uid1',
+ };
+ const eids = createEidsArray(uid);
+ expect(eids).to.have.length(1);
+ expect(eids[0].uids.map(u => u.id)).to.have.members(['uid1', 'uid2']);
+ expect(uid.pubProvidedId[0].uids).to.eql([{id: 'uid2'}]);
+ });
})
it('pbjs.getUserIds', function (done) {
@@ -626,10 +664,10 @@ describe('User ID', function () {
it('pbjs.getUserIdsAsEids should prioritize user ids according to config available to core', () => {
init(config);
setSubmoduleRegistry([
- createMockIdSubmodule('mockId1Module', {id: {uid2: {id: 'uid2_value'}}}),
- createMockIdSubmodule('mockId2Module', {id: {pubcid: 'pubcid_value', lipb: {lipbid: 'lipbid_value_from_mockId2Module'}}}),
- createMockIdSubmodule('mockId3Module', {id: {uid2: {id: 'uid2_value_from_mockId3Module'}, pubcid: 'pubcid_value_from_mockId3Module', lipb: {lipbid: 'lipbid_value'}, merkleId: {id: 'merkleId_value_from_mockId3Module'}}}),
- createMockIdSubmodule('mockId4Module', {id: {merkleId: {id: 'merkleId_value'}}})
+ createMockIdSubmodule('mockId1Module', {id: {uid2: {id: 'uid2_value'}}}, null, createMockEid('uid2')),
+ createMockIdSubmodule('mockId2Module', {id: {pubcid: 'pubcid_value', lipb: {lipbid: 'lipbid_value_from_mockId2Module'}}}, null, createMockEid('pubcid')),
+ createMockIdSubmodule('mockId3Module', {id: {uid2: {id: 'uid2_value_from_mockId3Module'}, pubcid: 'pubcid_value_from_mockId3Module', lipb: {lipbid: 'lipbid_value'}, merkleId: {id: 'merkleId_value_from_mockId3Module'}}}, null, {...createMockEid('uid2'), ...createMockEid('merkleId'), ...createMockEid('lipb')}),
+ createMockIdSubmodule('mockId4Module', {id: {merkleId: {id: 'merkleId_value'}}}, null, createMockEid('merkleId'))
]);
config.setConfig({
userSync: {
@@ -661,6 +699,38 @@ describe('User ID', function () {
});
});
+ it('pbjs.getUserIdsAsEids should prioritize the uid1 according to config available to core', () => {
+ init(config);
+ setSubmoduleRegistry([
+ createMockIdSubmodule('mockId1Module', {id: {tdid: {id: 'uid1_value'}}}, null, UID1_EIDS),
+ createMockIdSubmodule('mockId2Module', {id: {tdid: {id: 'uid1Id_value_from_mockId2Module'}}}, null, UID1_EIDS),
+ createMockIdSubmodule('mockId3Module', {id: {tdid: {id: 'uid1Id_value_from_mockId3Module'}}}, null, UID1_EIDS)
+ ]);
+ config.setConfig({
+ userSync: {
+ idPriority: {
+ tdid: ['mockId2Module', 'mockId3Module', 'mockId1Module']
+ },
+ auctionDelay: 10, // with auctionDelay > 0, no auction is needed to complete init
+ userIds: [
+ { name: 'mockId1Module' },
+ { name: 'mockId2Module' },
+ { name: 'mockId3Module' }
+ ]
+ }
+ });
+
+ const ids = {
+ 'tdid': { id: 'uid1Id_value_from_mockId2Module' },
+ };
+
+ return getGlobal().getUserIdsAsync().then(() => {
+ const eids = getGlobal().getUserIdsAsEids();
+ const expected = createEidsArray(ids);
+ expect(eids).to.deep.equal(expected);
+ })
+ });
+
describe('EID updateConfig', () => {
function mockSubmod(name, eids) {
return createMockIdSubmodule(name, null, null, eids);
@@ -3536,11 +3606,16 @@ describe('User ID', function () {
it('pbjs.getUserIdsAsEidBySource with priority config available to core', () => {
init(config);
+ const uid2Eids = createMockEid('uid2', 'uidapi.com')
+ const pubcEids = createMockEid('pubcid', 'pubcid.org')
+ const liveIntentEids = createMockEid('lipb', 'liveintent.com')
+ const merkleEids = createMockEid('merkleId', 'merkleinc.com')
+
setSubmoduleRegistry([
- createMockIdSubmodule('mockId1Module', {id: {uid2: {id: 'uid2_value'}}}),
- createMockIdSubmodule('mockId2Module', {id: {pubcid: 'pubcid_value', lipb: {lipbid: 'lipbid_value_from_mockId2Module'}}}),
- createMockIdSubmodule('mockId3Module', {id: {uid2: {id: 'uid2_value_from_mockId3Module'}, pubcid: 'pubcid_value_from_mockId3Module', lipb: {lipbid: 'lipbid_value'}, merkleId: {id: 'merkleId_value_from_mockId3Module'}}}),
- createMockIdSubmodule('mockId4Module', {id: {merkleId: {id: 'merkleId_value'}}})
+ createMockIdSubmodule('mockId1Module', {id: {uid2: {id: 'uid2_value'}}}, null, uid2Eids),
+ createMockIdSubmodule('mockId2Module', {id: {pubcid: 'pubcid_value', lipb: {lipbid: 'lipbid_value_from_mockId2Module'}}}, null, {...pubcEids, ...liveIntentEids}),
+ createMockIdSubmodule('mockId3Module', {id: {uid2: {id: 'uid2_value_from_mockId3Module'}, pubcid: 'pubcid_value_from_mockId3Module', lipb: {lipbid: 'lipbid_value'}, merkleId: {id: 'merkleId_value_from_mockId3Module'}}}, null, {...uid2Eids, ...pubcEids, ...liveIntentEids}),
+ createMockIdSubmodule('mockId4Module', {id: {merkleId: {id: 'merkleId_value'}}}, null, merkleEids)
]);
config.setConfig({
userSync: {
diff --git a/test/spec/modules/viantOrtbBidAdapter_spec.js b/test/spec/modules/viantOrtbBidAdapter_spec.js
index ef537d50986..73fdb7f3dc8 100644
--- a/test/spec/modules/viantOrtbBidAdapter_spec.js
+++ b/test/spec/modules/viantOrtbBidAdapter_spec.js
@@ -109,6 +109,49 @@ describe('viantOrtbBidAdapter', function () {
});
});
});
+
+ describe('native', function () {
+ describe('and request config uses mediaTypes', () => {
+ function makeBid() {
+ return {
+ 'bidder': 'viant',
+ 'params': {
+ 'unit': '12345678',
+ 'delDomain': 'test-del-domain',
+ 'publisherId': '464',
+ 'placementId': 'some-PlacementId_2'
+ },
+ 'mediaTypes': {
+ 'video': {
+ 'context': 'instream',
+ 'playerSize': [[640, 480]],
+ 'mimes': ['video/mp4'],
+ 'protocols': [1, 2, 3, 4, 5, 6, 7, 8],
+ 'api': [1, 3],
+ 'skip': 1,
+ 'skipafter': 5,
+ 'minduration': 10,
+ 'maxduration': 30
+ }
+ },
+ 'adUnitCode': 'adunit-code',
+ 'bidId': '30b31c1838de1e',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'auctionId': '1d1a030790a475',
+ 'transactionId': '4008d88a-8137-410b-aa35-fbfdabcb478e'
+ }
+ }
+ it('should return true when required params found', function () {
+ expect(spec.isBidRequestValid(makeBid())).to.equal(true);
+ });
+
+ it('should return false when required params are not passed', function () {
+ let nativeBidWithMediaTypes = Object.assign({}, makeBid());
+ nativeBidWithMediaTypes.params = {};
+ expect(spec.isBidRequestValid(nativeBidWithMediaTypes)).to.equal(false);
+ });
+ });
+ });
});
describe('buildRequests-banner', function () {
@@ -172,7 +215,7 @@ describe('viantOrtbBidAdapter', function () {
});
it('sends bid requests to the correct endpoint', function () {
const url = testBuildRequests(baseBannerBidRequests, baseBidderRequest)[0].url;
- expect(url).to.equal('https://bidders-us-east-1.adelphic.net/d/rtb/v25/prebid/bidder_test');
+ expect(url).to.equal('https://bidders-us-east-1.adelphic.net/d/rtb/v25/prebid/bidder');
});
it('sends site', function () {
diff --git a/test/spec/modules/vidazooBidAdapter_spec.js b/test/spec/modules/vidazooBidAdapter_spec.js
index 864f2b8551c..5515002a054 100644
--- a/test/spec/modules/vidazooBidAdapter_spec.js
+++ b/test/spec/modules/vidazooBidAdapter_spec.js
@@ -19,6 +19,7 @@ import {version} from 'package.json';
import {useFakeTimers} from 'sinon';
import {BANNER, VIDEO} from '../../../src/mediaTypes';
import {config} from '../../../src/config';
+import {deepSetValue} from 'src/utils.js';
export const TEST_ID_SYSTEMS = ['britepoolid', 'criteoId', 'id5id', 'idl_env', 'lipb', 'netId', 'parrableId', 'pubcid', 'tdid', 'pubProvidedId'];
@@ -108,7 +109,19 @@ const BIDDER_REQUEST = {
'ortb2': {
'site': {
'cat': ['IAB2'],
- 'pagecat': ['IAB2-2']
+ 'pagecat': ['IAB2-2'],
+ 'content': {
+ 'data': [{
+ 'name': 'example.com',
+ 'ext': {
+ 'segtax': 7
+ },
+ 'segments': [
+ {'id': 'segId1'},
+ {'id': 'segId2'}
+ ]
+ }]
+ }
},
'regs': {
'gpp': 'gpp_string',
@@ -131,6 +144,15 @@ const BIDDER_REQUEST = {
'bitness': '64',
'architecture': ''
}
+ },
+ user: {
+ data: [
+ {
+ ext: {segtax: 600, segclass: '1'},
+ name: 'example.com',
+ segment: [{id: '243'}],
+ },
+ ],
}
},
};
@@ -318,6 +340,23 @@ describe('VidazooBidAdapter', function () {
'bitness': '64',
'architecture': ''
},
+ contentData: [{
+ 'name': 'example.com',
+ 'ext': {
+ 'segtax': 7
+ },
+ 'segments': [
+ {'id': 'segId1'},
+ {'id': 'segId2'}
+ ]
+ }],
+ userData: [
+ {
+ ext: {segtax: 600, segclass: '1'},
+ name: 'example.com',
+ segment: [{id: '243'}],
+ },
+ ],
uniqueDealId: `${hashUrl}_${Date.now().toString()}`,
uqs: getTopWindowQueryParams(),
isStorageAllowed: true,
@@ -340,7 +379,8 @@ describe('VidazooBidAdapter', function () {
}
}
}
- });
+ })
+ ;
});
it('should build banner request for each size', function () {
@@ -405,6 +445,23 @@ describe('VidazooBidAdapter', function () {
gpid: '1234567890',
cat: ['IAB2'],
pagecat: ['IAB2-2'],
+ contentData: [{
+ 'name': 'example.com',
+ 'ext': {
+ 'segtax': 7
+ },
+ 'segments': [
+ {'id': 'segId1'},
+ {'id': 'segId2'}
+ ]
+ }],
+ userData: [
+ {
+ ext: {segtax: 600, segclass: '1'},
+ name: 'example.com',
+ segment: [{id: '243'}],
+ },
+ ],
webSessionId: webSessionId
}
});
@@ -478,6 +535,23 @@ describe('VidazooBidAdapter', function () {
gpid: '1234567890',
cat: ['IAB2'],
pagecat: ['IAB2-2'],
+ contentData: [{
+ 'name': 'example.com',
+ 'ext': {
+ 'segtax': 7
+ },
+ 'segments': [
+ {'id': 'segId1'},
+ {'id': 'segId2'}
+ ]
+ }],
+ userData: [
+ {
+ ext: {segtax: 600, segclass: '1'},
+ name: 'example.com',
+ segment: [{id: '243'}],
+ },
+ ],
webSessionId: webSessionId
};
@@ -523,6 +597,15 @@ describe('VidazooBidAdapter', function () {
expect(requests).to.have.length(2);
});
+ it('should set fledge correctly if enabled', function () {
+ config.resetConfig();
+ const bidderRequest = utils.deepClone(BIDDER_REQUEST);
+ bidderRequest.fledgeEnabled = true;
+ deepSetValue(bidderRequest, 'ortb2Imp.ext.ae', 1);
+ const requests = adapter.buildRequests([BID], bidderRequest);
+ expect(requests[0].data.fledge).to.equal(1);
+ });
+
after(function () {
$$PREBID_GLOBAL$$.bidderSettings = {};
config.resetConfig();
@@ -648,6 +731,14 @@ describe('VidazooBidAdapter', function () {
expect(responses).to.have.length(1);
expect(responses[0].ttl).to.equal(300);
});
+
+ it('should add nurl if exists on response', function () {
+ const serverResponse = utils.deepClone(SERVER_RESPONSE);
+ serverResponse.body.results[0].nurl = 'https://test.com/win-notice?test=123';
+ const responses = adapter.interpretResponse(serverResponse, REQUEST);
+ expect(responses).to.have.length(1);
+ expect(responses[0].nurl).to.equal('https://test.com/win-notice?test=123');
+ });
});
describe('user id system', function () {
@@ -833,4 +924,66 @@ describe('VidazooBidAdapter', function () {
expect(parsed).to.be.equal(value);
});
});
+
+ describe('validate onBidWon', function () {
+ beforeEach(function () {
+ sinon.stub(utils, 'triggerPixel');
+ });
+ afterEach(function () {
+ utils.triggerPixel.restore();
+ });
+
+ it('should call triggerPixel if nurl exists', function () {
+ const bid = {
+ adUnitCode: 'div-gpt-ad-12345-0',
+ adId: '2d52001cabd527',
+ auctionId: '1fdb5ff1b6eaa7',
+ transactionId: 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf',
+ status: 'rendered',
+ timeToRespond: 100,
+ cpm: 0.8,
+ originalCpm: 0.8,
+ creativeId: '12610997325162499419',
+ currency: 'USD',
+ originalCurrency: 'USD',
+ height: 250,
+ mediaType: 'banner',
+ nurl: 'https://test.com/win-notice?test=123',
+ netRevenue: true,
+ requestId: '2d52001cabd527',
+ ttl: 30,
+ width: 300
+ };
+ adapter.onBidWon(bid);
+ expect(utils.triggerPixel.called).to.be.true;
+
+ const url = utils.triggerPixel.args[0];
+
+ expect(url[0]).to.be.equal('https://test.com/win-notice?test=123&adId=2d52001cabd527&creativeId=12610997325162499419&auctionId=1fdb5ff1b6eaa7&transactionId=c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf&adUnitCode=div-gpt-ad-12345-0&cpm=0.8¤cy=USD&originalCpm=0.8&originalCurrency=USD&netRevenue=true&mediaType=banner&timeToRespond=100&status=rendered');
+ });
+
+ it('should not call triggerPixel if nurl does not exist', function () {
+ const bid = {
+ adUnitCode: 'div-gpt-ad-12345-0',
+ adId: '2d52001cabd527',
+ auctionId: '1fdb5ff1b6eaa7',
+ transactionId: 'c881914b-a3b5-4ecf-ad9c-1c2f37c6aabf',
+ status: 'rendered',
+ timeToRespond: 100,
+ cpm: 0.8,
+ originalCpm: 0.8,
+ creativeId: '12610997325162499419',
+ currency: 'USD',
+ originalCurrency: 'USD',
+ height: 250,
+ mediaType: 'banner',
+ netRevenue: true,
+ requestId: '2d52001cabd527',
+ ttl: 30,
+ width: 300
+ };
+ adapter.onBidWon(bid);
+ expect(utils.triggerPixel.called).to.be.false;
+ });
+ });
});
diff --git a/test/spec/modules/videoModule/pbVideo_spec.js b/test/spec/modules/videoModule/pbVideo_spec.js
index 2e26737da40..1ccd9766eab 100644
--- a/test/spec/modules/videoModule/pbVideo_spec.js
+++ b/test/spec/modules/videoModule/pbVideo_spec.js
@@ -1,3 +1,4 @@
+import 'src/prebid.js';
import { expect } from 'chai';
import { PbVideo } from 'modules/videoModule';
import CONSTANTS from 'src/constants.json';
@@ -26,7 +27,8 @@ function resetTestVars() {
onEvents: sinon.spy(),
getOrtbVideo: () => ortbVideoMock,
getOrtbContent: () => ortbContentMock,
- setAdTagUrl: sinon.spy()
+ setAdTagUrl: sinon.spy(),
+ hasProviderFor: sinon.spy(),
};
getConfigMock = () => {};
requestBidsMock = {
diff --git a/test/spec/modules/visxBidAdapter_spec.js b/test/spec/modules/visxBidAdapter_spec.js
index 139349ceead..5528705efd7 100755
--- a/test/spec/modules/visxBidAdapter_spec.js
+++ b/test/spec/modules/visxBidAdapter_spec.js
@@ -1257,6 +1257,7 @@ describe('VisxAdapter', function () {
const request = spec.buildRequests(bidRequests);
const pendingUrl = 'https://t.visx.net/track/pending/123123123';
const winUrl = 'https://t.visx.net/track/win/53245341';
+ const runtimeUrl = 'https://t.visx.net/track/status/12345678';
const expectedResponse = [
{
'requestId': '300bfeb0d71a5b',
@@ -1281,7 +1282,8 @@ describe('VisxAdapter', function () {
'ext': {
'events': {
'pending': pendingUrl,
- 'win': winUrl
+ 'win': winUrl,
+ 'runtime': runtimeUrl
},
'targeting': {
'hb_visx_product': 'understitial',
@@ -1298,6 +1300,9 @@ describe('VisxAdapter', function () {
pending: pendingUrl,
win: winUrl,
});
+ utils.deepSetValue(serverResponse.bid[0], 'ext.visx.events', {
+ runtime: runtimeUrl
+ });
const result = spec.interpretResponse({'body': {'seatbid': [serverResponse]}}, request);
expect(result).to.deep.equal(expectedResponse);
});
@@ -1325,6 +1330,39 @@ describe('VisxAdapter', function () {
expect(utils.triggerPixel.calledOnceWith(trackUrl)).to.equal(true);
});
+ it('onBidWon with runtime tracker (0 < timeToRespond <= 5000 )', function () {
+ const trackUrl = 'https://t.visx.net/track/win/123123123';
+ const runtimeUrl = 'https://t.visx.net/track/status/12345678/{STATUS_CODE}';
+ const bid = { auctionId: '1', ext: { events: { win: trackUrl, runtime: runtimeUrl } }, timeToRespond: 100 };
+ spec.onBidWon(bid);
+ expect(utils.triggerPixel.calledTwice).to.equal(true);
+ expect(utils.triggerPixel.calledWith(trackUrl)).to.equal(true);
+ expect(utils.triggerPixel.calledWith(runtimeUrl.replace('{STATUS_CODE}', 999002))).to.equal(true);
+ });
+
+ it('onBidWon with runtime tracker (timeToRespond <= 0 )', function () {
+ const runtimeUrl = 'https://t.visx.net/track/status/12345678/{STATUS_CODE}';
+ const bid = { auctionId: '2', ext: { events: { runtime: runtimeUrl } }, timeToRespond: 0 };
+ spec.onBidWon(bid);
+ expect(utils.triggerPixel.calledOnceWith(runtimeUrl.replace('{STATUS_CODE}', 999000))).to.equal(true);
+ });
+
+ it('onBidWon with runtime tracker (timeToRespond > 5000 )', function () {
+ const runtimeUrl = 'https://t.visx.net/track/status/12345678/{STATUS_CODE}';
+ const bid = { auctionId: '3', ext: { events: { runtime: runtimeUrl } }, timeToRespond: 5001 };
+ spec.onBidWon(bid);
+ expect(utils.triggerPixel.calledOnceWith(runtimeUrl.replace('{STATUS_CODE}', 999100))).to.equal(true);
+ });
+
+ it('onBidWon runtime tracker should be called once per auction', function () {
+ const runtimeUrl = 'https://t.visx.net/track/status/12345678/{STATUS_CODE}';
+ const bid1 = { auctionId: '4', ext: { events: { runtime: runtimeUrl } }, timeToRespond: 100 };
+ spec.onBidWon(bid1);
+ const bid2 = { auctionId: '4', ext: { events: { runtime: runtimeUrl } }, timeToRespond: 200 };
+ spec.onBidWon(bid2);
+ expect(utils.triggerPixel.calledOnceWith(runtimeUrl.replace('{STATUS_CODE}', 999002))).to.equal(true);
+ });
+
it('onTimeout', function () {
const data = [{ timeout: 3000, adUnitCode: 'adunit-code-1', auctionId: '1cbd2feafe5e8b', bidder: 'visx', bidId: '23423', params: [{ uid: '1' }] }];
const expectedData = [{ timeout: 3000, params: [{ uid: 1 }] }];
diff --git a/test/spec/modules/vrtcalBidAdapter_spec.js b/test/spec/modules/vrtcalBidAdapter_spec.js
index cc4dc0a3882..938934170e9 100644
--- a/test/spec/modules/vrtcalBidAdapter_spec.js
+++ b/test/spec/modules/vrtcalBidAdapter_spec.js
@@ -134,4 +134,39 @@ describe('vrtcalBidAdapter', function () {
).to.be.true
})
})
+
+ describe('getUserSyncs', function() {
+ const syncurl_iframe = 'https://usync.vrtcal.com/i?ssp=1804&synctype=iframe';
+ const syncurl_redirect = 'https://usync.vrtcal.com/i?ssp=1804&synctype=redirect';
+
+ it('base iframe sync pper config', function() {
+ expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined, undefined)).to.deep.equal([{
+ type: 'iframe', url: syncurl_iframe + '&us_privacy=&gdpr=0&gdpr_consent=&gpp=&gpp_sid=&surl='
+ }]);
+ });
+
+ it('base redirect sync per config', function() {
+ expect(spec.getUserSyncs({ iframeEnabled: false }, {}, undefined, undefined)).to.deep.equal([{
+ type: 'image', url: syncurl_redirect + '&us_privacy=&gdpr=0&gdpr_consent=&gpp=&gpp_sid=&surl='
+ }]);
+ });
+
+ it('pass with ccpa data', function() {
+ expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined, 'ccpa_consent_string', undefined)).to.deep.equal([{
+ type: 'iframe', url: syncurl_iframe + '&us_privacy=ccpa_consent_string&gdpr=0&gdpr_consent=&gpp=&gpp_sid=&surl='
+ }]);
+ });
+
+ it('pass with gdpr data', function() {
+ expect(spec.getUserSyncs({ iframeEnabled: true }, {}, {gdprApplies: 1, consentString: 'gdpr_consent_string'}, undefined, undefined)).to.deep.equal([{
+ type: 'iframe', url: syncurl_iframe + '&us_privacy=&gdpr=1&gdpr_consent=gdpr_consent_string&gpp=&gpp_sid=&surl='
+ }]);
+ });
+
+ it('pass with gpp data', function() {
+ expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined, undefined, {gppString: 'gpp_consent_string', applicableSections: [1, 5]})).to.deep.equal([{
+ type: 'iframe', url: syncurl_iframe + '&us_privacy=&gdpr=0&gdpr_consent=&gpp=gpp_consent_string&gpp_sid=1,5&surl='
+ }]);
+ });
+ })
})
diff --git a/test/spec/modules/weboramaRtdProvider_spec.js b/test/spec/modules/weboramaRtdProvider_spec.js
index 7de8474d7c9..d562d9ffd13 100644
--- a/test/spec/modules/weboramaRtdProvider_spec.js
+++ b/test/spec/modules/weboramaRtdProvider_spec.js
@@ -48,6 +48,120 @@ describe('weboramaRtdProvider', function() {
};
expect(weboramaSubmodule.init(moduleConfig)).to.equal(true);
});
+
+ it('instantiate with empty sfbxLiteData should return true', function() {
+ const moduleConfig = {
+ params: {
+ sfbxLiteDataConf: {},
+ }
+ };
+ expect(weboramaSubmodule.init(moduleConfig)).to.equal(true);
+ });
+
+ describe('webo user data should check gdpr consent', function() {
+ it('should initialize if gdpr does not applies', function() {
+ const moduleConfig = {
+ params: {
+ weboUserDataConf: {}
+ }
+ };
+ const userConsent = {
+ gdpr: {
+ gdprApplies: false,
+ },
+ }
+ expect(weboramaSubmodule.init(moduleConfig, userConsent)).to.equal(true);
+ });
+ it('should initialize if gdpr applies and consent is ok', function() {
+ const moduleConfig = {
+ params: {
+ weboUserDataConf: {}
+ }
+ };
+ const userConsent = {
+ gdpr: {
+ gdprApplies: true,
+ vendorData: {
+ purpose: {
+ consents: {
+ 1: true,
+ 3: true,
+ 4: true,
+ 5: true,
+ 6: true,
+ 9: true,
+ },
+ },
+ specialFeatureOptins: {
+ 1: true,
+ },
+ vendor: {
+ consents: {
+ 284: true,
+ },
+ }
+ },
+ },
+ }
+ expect(weboramaSubmodule.init(moduleConfig, userConsent)).to.equal(true);
+ });
+ it('should NOT initialize if gdpr applies and consent is nok: miss consent vendor id', function() {
+ const moduleConfig = {
+ params: {
+ weboUserDataConf: {}
+ }
+ };
+ const userConsent = {
+ gdpr: {
+ gdprApplies: true,
+ vendorData: {
+ purpose: {
+ consents: {
+ 1: true,
+ 3: true,
+ 4: true,
+ },
+ },
+ specialFeatureOptins: {},
+ vendor: {
+ consents: {
+ 284: false,
+ },
+ }
+ },
+ },
+ }
+ expect(weboramaSubmodule.init(moduleConfig, userConsent)).to.equal(false);
+ });
+ it('should NOT initialize if gdpr applies and consent is nok: miss one purpose id', function() {
+ const moduleConfig = {
+ params: {
+ weboUserDataConf: {}
+ }
+ };
+ const userConsent = {
+ gdpr: {
+ gdprApplies: true,
+ vendorData: {
+ purpose: {
+ consents: {
+ 1: false,
+ 3: true,
+ 4: true,
+ },
+ },
+ specialFeatureOptins: {},
+ vendor: {
+ consents: {
+ 284: true,
+ },
+ }
+ },
+ },
+ }
+ expect(weboramaSubmodule.init(moduleConfig, userConsent)).to.equal(false);
+ });
+ });
});
describe('Handle Set Targeting and Bid Request', function() {
diff --git a/test/spec/modules/yandexAnalyticsAdapter_spec.js b/test/spec/modules/yandexAnalyticsAdapter_spec.js
new file mode 100644
index 00000000000..ca9b29d13a5
--- /dev/null
+++ b/test/spec/modules/yandexAnalyticsAdapter_spec.js
@@ -0,0 +1,147 @@
+import * as sinon from 'sinon';
+import yandexAnalytics, { EVENTS_TO_TRACK } from 'modules/yandexAnalyticsAdapter.js';
+import * as log from '../../../src/utils.js'
+import * as events from '../../../src/events.js';
+
+describe('Yandex analytics adapter testing', () => {
+ const sandbox = sinon.createSandbox();
+ let clock;
+ let logError;
+ let getEvents;
+ let onEvent;
+ const counterId = 123;
+ const counterWindowKey = 'yaCounter123';
+
+ beforeEach(() => {
+ yandexAnalytics.counters = {};
+ yandexAnalytics.counterInitTimeouts = {};
+ yandexAnalytics.bufferedEvents = [];
+ yandexAnalytics.oneCounterInited = false;
+ clock = sinon.useFakeTimers();
+ logError = sandbox.stub(log, 'logError');
+ sandbox.stub(log, 'logInfo');
+ getEvents = sandbox.stub(events, 'getEvents').returns([]);
+ onEvent = sandbox.stub(events, 'on');
+ sandbox.stub(window.document, 'createElement').callsFake((tag) => {
+ const element = {
+ tag,
+ events: {},
+ attributes: {},
+ addEventListener: (event, cb) => {
+ element.events[event] = cb;
+ },
+ removeEventListener: (event, cb) => {
+ chai.expect(element.events[event]).to.equal(cb);
+ },
+ setAttribute: (attr, val) => {
+ element.attributes[attr] = val;
+ },
+ };
+ return element;
+ });
+ });
+
+ afterEach(() => {
+ window.Ya = null;
+ window[counterWindowKey] = null;
+ sandbox.restore();
+ clock.restore();
+ });
+
+ it('fails if timeout for counter insertion is exceeded', () => {
+ yandexAnalytics.enableAnalytics({
+ options: {
+ counters: [
+ 123,
+ ],
+ },
+ });
+ clock.tick(25001);
+ chai.expect(yandexAnalytics.bufferedEvents).to.deep.equal([]);
+ sinon.assert.calledWith(logError, `Can't find metrika counter after 25 seconds.`);
+ sinon.assert.calledWith(logError, `Aborting yandex analytics provider initialization.`);
+ });
+
+ it('fails if no valid counters provided', () => {
+ yandexAnalytics.enableAnalytics({
+ options: {
+ counters: [
+ 'abc',
+ ],
+ },
+ });
+ sinon.assert.calledWith(logError, 'options.counters contains no valid counter ids');
+ });
+
+ it('subscribes to events if counter is already present', () => {
+ window[counterWindowKey] = {
+ pbjs: sandbox.stub(),
+ };
+
+ getEvents.returns([
+ {
+ eventType: EVENTS_TO_TRACK[0],
+ },
+ {
+ eventType: 'Some_untracked_event',
+ }
+ ]);
+ const eventsToSend = [{
+ event: EVENTS_TO_TRACK[0],
+ data: {
+ eventType: EVENTS_TO_TRACK[0],
+ }
+ }];
+
+ yandexAnalytics.enableAnalytics({
+ options: {
+ counters: [
+ counterId,
+ ],
+ },
+ });
+
+ EVENTS_TO_TRACK.forEach((eventName, i) => {
+ const [event, callback] = onEvent.getCall(i).args;
+ chai.expect(event).to.equal(eventName);
+ callback(i);
+ eventsToSend.push({
+ event: eventName,
+ data: i,
+ });
+ });
+
+ clock.tick(1501);
+
+ const [ sentEvents ] = window[counterWindowKey].pbjs.getCall(0).args;
+ chai.expect(sentEvents).to.deep.equal(eventsToSend);
+ });
+
+ it('waits for counter initialization', () => {
+ window.Ya = {};
+ // Simulatin metrika script initialization
+ yandexAnalytics.enableAnalytics({
+ options: {
+ counters: [
+ counterId,
+ ],
+ },
+ });
+
+ // Sending event
+ const [event, eventCallback] = onEvent.getCall(0).args;
+ eventCallback({});
+
+ const counterPbjsMethod = sandbox.stub();
+ window[`yaCounter${counterId}`] = {
+ pbjs: counterPbjsMethod,
+ };
+ clock.tick(2001);
+
+ const [ sentEvents ] = counterPbjsMethod.getCall(0).args;
+ chai.expect(sentEvents).to.deep.equal([{
+ event,
+ data: {},
+ }]);
+ });
+});
diff --git a/test/spec/modules/yandexBidAdapter_spec.js b/test/spec/modules/yandexBidAdapter_spec.js
index f14e8df6c09..140be4121ec 100644
--- a/test/spec/modules/yandexBidAdapter_spec.js
+++ b/test/spec/modules/yandexBidAdapter_spec.js
@@ -1,8 +1,8 @@
import { assert, expect } from 'chai';
-import { spec, NATIVE_ASSETS } from 'modules/yandexBidAdapter.js';
-import { parseUrl } from 'src/utils.js';
-import { BANNER, NATIVE } from '../../../src/mediaTypes';
+import { NATIVE_ASSETS, spec } from 'modules/yandexBidAdapter.js';
+import * as utils from 'src/utils.js';
import { config } from '../../../src/config';
+import { BANNER, NATIVE } from '../../../src/mediaTypes';
describe('Yandex adapter', function () {
describe('isBidRequestValid', function () {
@@ -41,11 +41,45 @@ describe('Yandex adapter', function () {
});
describe('buildRequests', function () {
+ /** @type {import('../../../src/auction').BidderRequest} */
const bidderRequest = {
- refererInfo: {
- domain: 'ya.ru',
- ref: 'https://ya.ru/',
- page: 'https://ya.ru/',
+ ortb2: {
+ site: {
+ domain: 'ya.ru',
+ ref: 'https://ya.ru/',
+ page: 'https://ya.ru/',
+ publisher: {
+ domain: 'ya.ru',
+ },
+ },
+ device: {
+ w: 1600,
+ h: 900,
+ dnt: 0,
+ ua: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
+ language: 'en',
+ sua: {
+ source: 1,
+ platform: {
+ brand: 'macOS',
+ },
+ browsers: [
+ {
+ brand: 'Not_A Brand',
+ version: ['8'],
+ },
+ {
+ brand: 'Chromium',
+ version: ['120'],
+ },
+ {
+ brand: 'Google Chrome',
+ version: ['120'],
+ },
+ ],
+ mobile: 0,
+ },
+ },
},
gdprConsent: {
gdprApplies: 1,
@@ -71,7 +105,7 @@ describe('Yandex adapter', function () {
expect(method).to.equal('POST');
- const parsedRequestUrl = parseUrl(url);
+ const parsedRequestUrl = utils.parseUrl(url);
const { search: query } = parsedRequestUrl
expect(parsedRequestUrl.hostname).to.equal('bs.yandex.ru');
@@ -100,26 +134,49 @@ describe('Yandex adapter', function () {
const bannerRequest = getBidRequest();
const requests = spec.buildRequests([bannerRequest], bidderRequest);
const { url } = requests[0];
- const parsedRequestUrl = parseUrl(url);
+ const parsedRequestUrl = utils.parseUrl(url);
const { search: query } = parsedRequestUrl
expect(query['ssp-cur']).to.equal('USD');
});
- it('should send eids if defined', function() {
- const bannerRequest = getBidRequest({
+ it('should send eids and ortb2 user data if defined', function() {
+ const bidderRequestWithUserData = {
+ ...bidderRequest,
+ ortb2: {
+ ...bidderRequest.ortb2,
+ user: {
+ data: [
+ {
+ ext: { segtax: 600, segclass: '1' },
+ name: 'example.com',
+ segment: [{ id: '243' }],
+ },
+ {
+ ext: { segtax: 600, segclass: '1' },
+ name: 'ads.example.org',
+ segment: [{ id: '243' }],
+ },
+ ],
+ },
+ }
+ };
+ const bidRequestExtra = {
userIdAsEids: [{
source: 'sharedid.org',
- uids: [
- {
- id: '01',
- atype: 1
- }
- ]
- }]
- });
+ uids: [{ id: '01', atype: 1 }],
+ }],
+ };
- const requests = spec.buildRequests([bannerRequest], bidderRequest);
+ const expected = {
+ ext: {
+ eids: bidRequestExtra.userIdAsEids,
+ },
+ data: bidderRequestWithUserData.ortb2.user.data,
+ };
+
+ const bannerRequest = getBidRequest(bidRequestExtra);
+ const requests = spec.buildRequests([bannerRequest], bidderRequestWithUserData);
expect(requests).to.have.lengthOf(1);
const request = requests[0];
@@ -128,17 +185,17 @@ describe('Yandex adapter', function () {
const { data } = request;
expect(data.user).to.exist;
- expect(data.user).to.deep.equal({
- ext: {
- eids: [{
- source: 'sharedid.org',
- uids: [{
- id: '01',
- atype: 1,
- }],
- }],
- }
- });
+ expect(data.user).to.deep.equal(expected);
+ });
+
+ it('should send site', function() {
+ const expected = {
+ site: bidderRequest.ortb2.site
+ };
+
+ const requests = spec.buildRequests([getBidRequest()], bidderRequest);
+
+ expect(requests[0].data.site).to.deep.equal(expected.site);
});
describe('banner', () => {
@@ -478,6 +535,60 @@ describe('Yandex adapter', function () {
});
});
});
+
+ describe('onBidWon', function() {
+ beforeEach(function() {
+ sinon.stub(utils, 'triggerPixel');
+ });
+ afterEach(function() {
+ utils.triggerPixel.restore();
+ });
+
+ it('Should not trigger pixel if bid does not contain nurl', function() {
+ spec.onBidWon({});
+
+ expect(utils.triggerPixel.callCount).to.equal(0)
+ })
+
+ it('Should trigger pixel if bid has nurl', function() {
+ spec.onBidWon({
+ nurl: 'https://example.com/some-tracker',
+ timeToRespond: 378,
+ });
+
+ expect(utils.triggerPixel.callCount).to.equal(1)
+ expect(utils.triggerPixel.getCall(0).args[0]).to.equal('https://example.com/some-tracker?rtt=378')
+ })
+
+ it('Should trigger pixel if bid has nurl with path & params', function() {
+ spec.onBidWon({
+ nurl: 'https://example.com/some-tracker/abcdxyz?param1=1¶m2=2',
+ timeToRespond: 378,
+ });
+
+ expect(utils.triggerPixel.callCount).to.equal(1)
+ expect(utils.triggerPixel.getCall(0).args[0]).to.equal('https://example.com/some-tracker/abcdxyz?param1=1¶m2=2&rtt=378')
+ })
+
+ it('Should trigger pixel if bid has nurl with path & params and rtt macros', function() {
+ spec.onBidWon({
+ nurl: 'https://example.com/some-tracker/abcdxyz?param1=1¶m2=2&custom-rtt=${RTT}',
+ timeToRespond: 378,
+ });
+
+ expect(utils.triggerPixel.callCount).to.equal(1)
+ expect(utils.triggerPixel.getCall(0).args[0]).to.equal('https://example.com/some-tracker/abcdxyz?param1=1¶m2=2&custom-rtt=378')
+ })
+
+ it('Should trigger pixel if bid has nurl and there is no timeToRespond param, but has rtt macros in nurl', function() {
+ spec.onBidWon({
+ nurl: 'https://example.com/some-tracker/abcdxyz?param1=1¶m2=2&custom-rtt=${RTT}',
+ });
+
+ expect(utils.triggerPixel.callCount).to.equal(1)
+ expect(utils.triggerPixel.getCall(0).args[0]).to.equal('https://example.com/some-tracker/abcdxyz?param1=1¶m2=2&custom-rtt=-1')
+ })
+ })
});
function getBidConfig() {
diff --git a/test/spec/modules/yieldlabBidAdapter_spec.js b/test/spec/modules/yieldlabBidAdapter_spec.js
index 93c231c816b..751dff4fe33 100644
--- a/test/spec/modules/yieldlabBidAdapter_spec.js
+++ b/test/spec/modules/yieldlabBidAdapter_spec.js
@@ -226,6 +226,36 @@ const PVID_RESPONSE = Object.assign({}, VIDEO_RESPONSE, {
pvid: '43513f11-55a0-4a83-94e5-0ebc08f54a2c',
});
+const DIGITAL_SERVICES_ACT_RESPONSE = Object.assign({}, RESPONSE, {
+ dsa: {
+ behalf: 'some-behalf',
+ paid: 'some-paid',
+ transparency: [{
+ domain: 'test.com',
+ dsaparams: [1, 2, 3]
+ }],
+ adrender: 1
+ }
+});
+
+const DIGITAL_SERVICES_ACT_CONFIG = {
+ ortb2: {
+ regs: {
+ ext: {
+ dsa: {
+ dsarequired: '1',
+ pubrender: '2',
+ datatopub: '3',
+ transparency: [{
+ domain: 'test.com',
+ dsaparams: [1, 2, 3]
+ }]
+ },
+ }
+ },
+ }
+}
+
const REQPARAMS = {
json: true,
ts: 1234567890,
@@ -486,6 +516,75 @@ describe('yieldlabBidAdapter', () => {
expect(request.url).to.not.include('sizes');
});
});
+
+ describe('Digital Services Act handling', () => {
+ beforeEach(() => {
+ config.setConfig(DIGITAL_SERVICES_ACT_CONFIG);
+ });
+
+ afterEach(() => {
+ config.resetConfig();
+ });
+
+ it('does pass dsarequired parameter', () => {
+ let request = spec.buildRequests([DEFAULT_REQUEST()], { ...REQPARAMS, ...DIGITAL_SERVICES_ACT_CONFIG });
+ expect(request.url).to.include('dsarequired=1');
+ });
+
+ it('does pass dsapubrender parameter', () => {
+ let request = spec.buildRequests([DEFAULT_REQUEST()], { ...REQPARAMS, ...DIGITAL_SERVICES_ACT_CONFIG });
+ expect(request.url).to.include('dsapubrender=2');
+ });
+
+ it('does pass dsadatatopub parameter', () => {
+ let request = spec.buildRequests([DEFAULT_REQUEST()], { ...REQPARAMS, ...DIGITAL_SERVICES_ACT_CONFIG });
+ expect(request.url).to.include('dsadatatopub=3');
+ });
+
+ it('does pass dsadomain parameter', () => {
+ let request = spec.buildRequests([DEFAULT_REQUEST()], { ...REQPARAMS, ...DIGITAL_SERVICES_ACT_CONFIG });
+ expect(request.url).to.include('dsadomain=test.com');
+ });
+
+ it('does pass encoded dsaparams parameter', () => {
+ let request = spec.buildRequests([DEFAULT_REQUEST()], { ...REQPARAMS, ...DIGITAL_SERVICES_ACT_CONFIG });
+ expect(request.url).to.include('dsaparams=1%2C2%2C3');
+ });
+
+ it('does pass multiple transparencies in dsatransparency param', () => {
+ const DSA_CONFIG_WITH_MULTIPLE_TRANSPARENCIES = {
+ ortb2: {
+ regs: {
+ ext: {
+ dsa: {
+ dsarequired: '1',
+ pubrender: '2',
+ datatopub: '3',
+ transparency: [
+ {
+ domain: 'test.com',
+ dsaparams: [1, 2, 3]
+ },
+ {
+ domain: 'example.com',
+ dsaparams: [4, 5, 6]
+ }
+ ]
+ }
+ }
+ }
+ }
+ };
+
+ config.setConfig(DSA_CONFIG_WITH_MULTIPLE_TRANSPARENCIES);
+
+ let request = spec.buildRequests([DEFAULT_REQUEST()], { ...REQPARAMS, ...DSA_CONFIG_WITH_MULTIPLE_TRANSPARENCIES });
+
+ expect(request.url).to.include('dsatransparency=test.com~1_2_3~~example.com~4_5_6');
+ expect(request.url).to.not.include('dsadomain');
+ expect(request.url).to.not.include('dsaparams');
+ });
+ });
});
describe('interpretResponse', () => {
@@ -676,6 +775,17 @@ describe('yieldlabBidAdapter', () => {
const result = spec.interpretResponse({body: [VIDEO_RESPONSE]}, {validBidRequests: [VIDEO_REQUEST()], queryParams: REQPARAMS_IAB_CONTENT});
expect(result[0].vastUrl).to.include('&iab_content=id%3Afoo_id%2Cepisode%3A99%2Ctitle%3Afoo_title%252Cbar_title%2Cseries%3Afoo_series%2Cseason%3As1%2Cartist%3Afoo%2520bar%2Cgenre%3Abaz%2Cisrc%3ACC-XXX-YY-NNNNN%2Curl%3Ahttp%253A%252F%252Ffoo_url.de%2Ccat%3Acat1%7Ccat2%252Cppp%7Ccat3%257C%257C%257C%252F%252F%2Ccontext%3A7%2Ckeywords%3Ak1%252C%7Ck2..%2Clive%3A0');
});
+
+ it('should get digital services act object in matched bid response', () => {
+ const result = spec.interpretResponse({body: [DIGITAL_SERVICES_ACT_RESPONSE]}, {validBidRequests: [{...DEFAULT_REQUEST(), ...DIGITAL_SERVICES_ACT_CONFIG}], queryParams: REQPARAMS});
+
+ expect(result[0].requestId).to.equal('2d925f27f5079f');
+ expect(result[0].meta.dsa.behalf).to.equal('some-behalf');
+ expect(result[0].meta.dsa.paid).to.equal('some-paid');
+ expect(result[0].meta.dsa.transparency[0].domain).to.equal('test.com');
+ expect(result[0].meta.dsa.transparency[0].dsaparams).to.deep.equal([1, 2, 3]);
+ expect(result[0].meta.dsa.adrender).to.equal(1);
+ });
});
describe('getUserSyncs', () => {
diff --git a/test/spec/modules/yieldmoBidAdapter_spec.js b/test/spec/modules/yieldmoBidAdapter_spec.js
index 229dc05e2fa..f37ef9178dd 100644
--- a/test/spec/modules/yieldmoBidAdapter_spec.js
+++ b/test/spec/modules/yieldmoBidAdapter_spec.js
@@ -47,7 +47,7 @@ describe('YieldmoAdapter', function () {
video: {
playerSize: [640, 480],
context: 'instream',
- mimes: ['video/mp4']
+ mimes: ['video/mp4'],
},
},
params: {
@@ -61,11 +61,11 @@ describe('YieldmoAdapter', function () {
api: [2, 3],
skipppable: true,
playbackmethod: [1, 2],
- ...videoParams
- }
+ ...videoParams,
+ },
},
transactionId: '54a58774-7a41-494e-8cbc-fa7b79164f0c',
- ...rootParams
+ ...rootParams,
});
const mockBidderRequest = (params = {}, bids = [mockBannerBid()]) => ({
@@ -74,7 +74,6 @@ describe('YieldmoAdapter', function () {
bidderRequestId: '14c4ede8c693f',
bids,
auctionStart: 1520001292880,
- timeout: 3000,
start: 1520001292884,
doneCbCallCount: 0,
refererInfo: {
@@ -169,6 +168,14 @@ describe('YieldmoAdapter', function () {
expect(requests[0].url).to.be.equal(BANNER_ENDPOINT);
});
+ it('should pass default timeout in bid request', function () {
+ const requests = build([mockBannerBid()]);
+ expect(requests[0].data.tmax).to.equal(400);
+ });
+ it('should pass tmax to bid request', function () {
+ const requests = build([mockBannerBid()], mockBidderRequest({timeout: 1000}));
+ expect(requests[0].data.tmax).to.equal(1000);
+ });
it('should not blow up if crumbs is undefined', function () {
expect(function () {
build([mockBannerBid({crumbs: undefined})]);
@@ -387,6 +394,61 @@ describe('YieldmoAdapter', function () {
expect(placementInfo).to.include('"gpid":"/6355419/Travel/Europe/France/Paris"');
});
+ it('should add topics to the banner bid request', function () {
+ const biddata = build([mockBannerBid()], mockBidderRequest({ortb2: { user: {
+ data: [
+ {
+ ext: {
+ segtax: 600,
+ segclass: '2206021246',
+ },
+ segment: ['7', '8', '9'],
+ },
+ ],
+ }}}));
+
+ expect(biddata[0].data.topics).to.equal(JSON.stringify({
+ taxonomy: 600,
+ classifier: '2206021246',
+ topics: [7, 8, 9],
+ }));
+ });
+
+ it('should add cdep to the banner bid request', function () {
+ const biddata = build(
+ [mockBannerBid()],
+ mockBidderRequest({
+ ortb2: {
+ device: {
+ ext: {
+ cdep: 'test_cdep'
+ },
+ },
+ },
+ })
+ );
+
+ expect(biddata[0].data.cdep).to.equal(
+ 'test_cdep'
+ );
+ });
+
+ it('should send gpc in the banner bid request', function () {
+ const biddata = build(
+ [mockBannerBid()],
+ mockBidderRequest({
+ ortb2: {
+ regs: {
+ ext: {
+ gpc: '1'
+ },
+ },
+ },
+ })
+ );
+ expect(biddata[0].data.gpc).to.equal('1');
+ });
+
it('should add eids to the banner bid request', function () {
const params = {
userIdAsEids: [{
@@ -453,26 +515,22 @@ describe('YieldmoAdapter', function () {
expect(buildVideoBidAndGetVideoParam().minduration).to.deep.equal(['video/mp4']);
});
+ it('should add plcmt value to the imp.video', function () {
+ const videoBid = mockVideoBid({}, {}, { plcmt: 1 });
+ expect(utils.deepAccess(videoBid, 'params.video')['plcmt']).to.equal(1);
+ });
+
+ it('should add start delay if plcmt value is not 1', function () {
+ const videoBid = mockVideoBid({}, {}, { plcmt: 2 });
+ expect(build([videoBid])[0].data.imp[0].video.startdelay).to.equal(0);
+ });
+
it('should override mediaTypes.video.mimes prop if params.video.mimes is present', function () {
utils.deepAccess(videoBid, 'mediaTypes.video')['mimes'] = ['video/mp4'];
utils.deepAccess(videoBid, 'params.video')['mimes'] = ['video/mkv'];
expect(buildVideoBidAndGetVideoParam().mimes).to.deep.equal(['video/mkv']);
});
- it('should validate protocol in video bid request', function () {
- expect(
- spec.isBidRequestValid(
- mockVideoBid({}, {}, { protocols: [2, 3, 11] })
- )
- ).to.be.true;
-
- expect(
- spec.isBidRequestValid(
- mockVideoBid({}, {}, { protocols: [2, 3, 10] })
- )
- ).to.be.false;
- });
-
describe('video.skip state check', () => {
it('should not set video.skip if neither *.video.skip nor *.video.skippable is present', function () {
utils.deepAccess(videoBid, 'mediaTypes.video')['skippable'] = false;
@@ -603,6 +661,51 @@ describe('YieldmoAdapter', function () {
};
expect(buildAndGetData([mockVideoBid({...params})]).user.eids).to.eql(params.fakeUserIdAsEids);
});
+
+ it('should add topics to the bid request', function () {
+ let videoBidder = mockBidderRequest(
+ {
+ ortb2: {
+ user: {
+ data: [
+ {
+ ext: {
+ segtax: 600,
+ segclass: '2206021246',
+ },
+ segment: ['7', '8', '9'],
+ },
+ ],
+ },
+ },
+ },
+ [mockVideoBid()]
+ );
+ let payload = buildAndGetData([mockVideoBid()], 0, videoBidder);
+ expect(payload.topics).to.deep.equal({
+ taxonomy: 600,
+ classifier: '2206021246',
+ topics: [7, 8, 9],
+ });
+ });
+
+ it('should send gpc in the bid request', function () {
+ let videoBidder = mockBidderRequest(
+ {
+ ortb2: {
+ regs: {
+ ext: {
+ gpc: '1',
+ },
+ },
+ },
+ },
+ [mockVideoBid()]
+ );
+ let payload = buildAndGetData([mockVideoBid()], 0, videoBidder);
+ expect(payload.regs.ext.gpc).to.equal('1');
+ });
+
it('should add device info to payload if available', function () {
let videoBidder = mockBidderRequest({ ortb2: {
device: {
diff --git a/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js b/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js
index 0796736a162..54b61f19506 100644
--- a/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js
+++ b/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js
@@ -9,7 +9,7 @@ let events = require('src/events');
const EVENTS = {
AUCTION_END: {
- 'auctionId': '75e394d9-ccce-4978-9238-91e6a1ac88a1',
+ 'auctionId': '75e394d9',
'timestamp': 1638441234544,
'auctionEnd': 1638441234784,
'auctionStatus': 'completed',
@@ -61,7 +61,7 @@ const EVENTS = {
600
]
],
- 'transactionId': '6b29369c-0c2e-414e-be1f-5867aec18d83'
+ 'transactionId': '6b29369c'
}
],
'adUnitCodes': [
@@ -70,7 +70,7 @@ const EVENTS = {
'bidderRequests': [
{
'bidderCode': 'zeta_global_ssp',
- 'auctionId': '75e394d9-ccce-4978-9238-91e6a1ac88a1',
+ 'auctionId': '75e394d9',
'bidderRequestId': '1207cb49191887',
'bids': [
{
@@ -90,7 +90,7 @@ const EVENTS = {
}
},
'adUnitCode': '/19968336/header-bid-tag-0',
- 'transactionId': '6b29369c-0c2e-414e-be1f-5867aec18d83',
+ 'transactionId': '6b29369c',
'sizes': [
[
300,
@@ -103,7 +103,7 @@ const EVENTS = {
],
'bidId': '206be9a13236af',
'bidderRequestId': '1207cb49191887',
- 'auctionId': '75e394d9-ccce-4978-9238-91e6a1ac88a1',
+ 'auctionId': '75e394d9',
'src': 'client',
'bidRequestsCount': 1,
'bidderRequestsCount': 1,
@@ -126,7 +126,7 @@ const EVENTS = {
},
{
'bidderCode': 'appnexus',
- 'auctionId': '75e394d9-ccce-4978-9238-91e6a1ac88a1',
+ 'auctionId': '75e394d9',
'bidderRequestId': '32b97f0a935422',
'bids': [
{
@@ -149,7 +149,7 @@ const EVENTS = {
}
},
'adUnitCode': '/19968336/header-bid-tag-0',
- 'transactionId': '6b29369c-0c2e-414e-be1f-5867aec18d83',
+ 'transactionId': '6b29369c',
'sizes': [
[
300,
@@ -162,7 +162,7 @@ const EVENTS = {
],
'bidId': '41badc0e164c758',
'bidderRequestId': '32b97f0a935422',
- 'auctionId': '75e394d9-ccce-4978-9238-91e6a1ac88a1',
+ 'auctionId': '75e394d9',
'src': 'client',
'bidRequestsCount': 1,
'bidderRequestsCount': 1,
@@ -205,7 +205,7 @@ const EVENTS = {
}
},
'adUnitCode': '/19968336/header-bid-tag-0',
- 'transactionId': '6b29369c-0c2e-414e-be1f-5867aec18d83',
+ 'transactionId': '6b29369c',
'sizes': [
[
300,
@@ -218,7 +218,7 @@ const EVENTS = {
],
'bidId': '41badc0e164c758',
'bidderRequestId': '32b97f0a935422',
- 'auctionId': '75e394d9-ccce-4978-9238-91e6a1ac88a1',
+ 'auctionId': '75e394d9',
'src': 'client',
'bidRequestsCount': 1,
'bidderRequestsCount': 1,
@@ -243,12 +243,12 @@ const EVENTS = {
'netRevenue': true,
'meta': {
'advertiserDomains': [
- 'viaplay.fi'
+ 'example.adomain'
]
},
'originalCpm': 2.258302852806723,
'originalCurrency': 'USD',
- 'auctionId': '75e394d9-ccce-4978-9238-91e6a1ac88a1',
+ 'auctionId': '75e394d9',
'responseTimestamp': 1638441234670,
'requestTimestamp': 1638441234547,
'bidder': 'zeta_global_ssp',
@@ -268,7 +268,7 @@ const EVENTS = {
'hb_size': '480x320',
'hb_source': 'client',
'hb_format': 'banner',
- 'hb_adomain': 'viaplay.fi'
+ 'hb_adomain': 'example.adomain'
}
}
],
@@ -311,12 +311,12 @@ const EVENTS = {
'netRevenue': true,
'meta': {
'advertiserDomains': [
- 'viaplay.fi'
+ 'example.adomain'
]
},
'originalCpm': 2.258302852806723,
'originalCurrency': 'USD',
- 'auctionId': '75e394d9-ccce-4978-9238-91e6a1ac88a1',
+ 'auctionId': '75e394d9',
'responseTimestamp': 1638441234670,
'requestTimestamp': 1638441234547,
'bidder': 'zeta_global_ssp',
@@ -336,7 +336,7 @@ const EVENTS = {
'hb_size': '480x320',
'hb_source': 'client',
'hb_format': 'banner',
- 'hb_adomain': 'viaplay.fi'
+ 'hb_adomain': 'example.adomain'
},
'status': 'rendered',
'params': [
@@ -398,5 +398,35 @@ describe('Zeta Global SSP Analytics Adapter', function() {
expect(auctionSucceeded.bid.params[0]).to.be.deep.equal(EVENTS.AUCTION_END.adUnits[0].bids[0].params);
expect(EVENTS.AUCTION_END.adUnits[0].bids[0].bidder).to.be.equal('zeta_global_ssp');
});
+
+ it('Keep only needed fields', function() {
+ this.timeout(3000);
+
+ events.emit(CONSTANTS.EVENTS.AUCTION_END, EVENTS.AUCTION_END);
+ events.emit(CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED, EVENTS.AD_RENDER_SUCCEEDED);
+
+ expect(requests.length).to.equal(2);
+ const auctionEnd = JSON.parse(requests[0].requestBody);
+ const auctionSucceeded = JSON.parse(requests[1].requestBody);
+
+ expect(auctionEnd.adUnitCodes).to.be.undefined;
+ expect(auctionEnd.adUnits[0].bids[0].bidder).to.be.equal('zeta_global_ssp');
+ expect(auctionEnd.auctionEnd).to.be.undefined;
+ expect(auctionEnd.auctionId).to.be.equal('75e394d9');
+ expect(auctionEnd.bidderRequests[0].bidderCode).to.be.equal('zeta_global_ssp');
+ expect(auctionEnd.bidderRequests[0].bids[0].bidId).to.be.equal('206be9a13236af');
+ expect(auctionEnd.bidderRequests[0].bids[0].adUnitCode).to.be.equal('/19968336/header-bid-tag-0');
+ expect(auctionEnd.bidsReceived[0].bidderCode).to.be.equal('zeta_global_ssp');
+ expect(auctionEnd.bidsReceived[0].adserverTargeting.hb_adomain).to.be.equal('example.adomain');
+ expect(auctionEnd.bidsReceived[0].auctionId).to.be.equal('75e394d9');
+
+ expect(auctionSucceeded.adId).to.be.equal('5759bb3ef7be1e8');
+ expect(auctionSucceeded.bid.auctionId).to.be.equal('75e394d9');
+ expect(auctionSucceeded.bid.requestId).to.be.equal('206be9a13236af');
+ expect(auctionSucceeded.bid.bidderCode).to.be.equal('zeta_global_ssp');
+ expect(auctionSucceeded.bid.creativeId).to.be.equal('456456456');
+ expect(auctionSucceeded.bid.size).to.be.equal('480x320');
+ expect(auctionSucceeded.doc.location.hostname).to.be.equal('localhost');
+ });
});
});
diff --git a/test/spec/modules/zeta_global_sspBidAdapter_spec.js b/test/spec/modules/zeta_global_sspBidAdapter_spec.js
index 601f4546a29..f9cfe2dde6a 100644
--- a/test/spec/modules/zeta_global_sspBidAdapter_spec.js
+++ b/test/spec/modules/zeta_global_sspBidAdapter_spec.js
@@ -1,5 +1,6 @@
import {spec} from '../../../modules/zeta_global_sspBidAdapter.js'
import {BANNER, VIDEO} from '../../../src/mediaTypes';
+import {deepClone} from '../../../src/utils';
describe('Zeta Ssp Bid Adapter', function () {
const eids = [
@@ -48,12 +49,17 @@ describe('Zeta Ssp Bid Adapter', function () {
},
tags: {
someTag: 444,
+ emptyTag: {},
+ nullTag: null,
+ complexEmptyTag: {
+ empty: {},
+ nullValue: null
+ }
},
sid: 'publisherId',
- shortname: 'test_shortname',
tagid: 'test_tag_id',
site: {
- page: 'testPage'
+ page: 'http://www.zetaglobal.com/page?param=value'
},
app: {
bundle: 'testBundle'
@@ -124,7 +130,34 @@ describe('Zeta Ssp Bid Adapter', function () {
uspConsent: 'someCCPAString',
params: params,
userIdAsEids: eids,
- timeout: 500
+ timeout: 500,
+ ortb2: {
+ device: {
+ sua: {
+ mobile: 1,
+ architecture: 'arm',
+ platform: {
+ brand: 'Chrome',
+ version: ['102']
+ }
+ }
+ },
+ user: {
+ data: [
+ {
+ ext: {
+ segtax: 600,
+ segclass: 'classifier_v1'
+ },
+ segment: [
+ { id: '3' },
+ { id: '44' },
+ { id: '59' }
+ ]
+ }
+ ]
+ }
+ }
}];
const bannerWithFewSizesRequest = [{
@@ -176,6 +209,7 @@ describe('Zeta Ssp Bid Adapter', function () {
id: '12345',
seatbid: [
{
+ seat: '1',
bid: [
{
id: 'auctionId',
@@ -201,7 +235,7 @@ describe('Zeta Ssp Bid Adapter', function () {
id: '123',
site: {
id: 'SITE_ID',
- page: 'page.com',
+ page: 'http://www.zetaglobal.com/page?param=value',
domain: 'domain.com'
},
user: {
@@ -229,7 +263,7 @@ describe('Zeta Ssp Bid Adapter', function () {
id: '123',
site: {
id: 'SITE_ID',
- page: 'page.com',
+ page: 'http://www.zetaglobal.com/page?param=value',
domain: 'domain.com'
},
user: {
@@ -253,11 +287,13 @@ describe('Zeta Ssp Bid Adapter', function () {
};
it('Test the bid validation function', function () {
- const validBid = spec.isBidRequestValid(bannerRequest[0]);
- const invalidBid = spec.isBidRequestValid(null);
+ const invalidBid = deepClone(bannerRequest[0]);
+ invalidBid.params = {};
+ const isValidBid = spec.isBidRequestValid(bannerRequest[0]);
+ const isInvalidBid = spec.isBidRequestValid(null);
- expect(validBid).to.be.true;
- expect(invalidBid).to.be.false;
+ expect(isValidBid).to.be.true;
+ expect(isInvalidBid).to.be.false;
});
it('Test provide eids', function () {
@@ -276,7 +312,7 @@ describe('Zeta Ssp Bid Adapter', function () {
it('Test page and domain in site', function () {
const request = spec.buildRequests(bannerRequest, bannerRequest[0]);
const payload = JSON.parse(request.data);
- expect(payload.site.page).to.eql('http://www.zetaglobal.com/page?param=value');
+ expect(payload.site.page).to.eql('zetaglobal.com/page');
expect(payload.site.domain).to.eql('zetaglobal.com');
});
@@ -453,7 +489,7 @@ describe('Zeta Ssp Bid Adapter', function () {
it('Test required params in banner request', function () {
const request = spec.buildRequests(bannerRequest, bannerRequest[0]);
const payload = JSON.parse(request.data);
- expect(request.url).to.eql('https://ssp.disqus.com/bid/prebid?shortname=test_shortname');
+ expect(request.url).to.eql('https://ssp.disqus.com/bid/prebid?sid=publisherId');
expect(payload.ext.sid).to.eql('publisherId');
expect(payload.ext.tags.someTag).to.eql(444);
expect(payload.ext.tags.shortname).to.be.undefined;
@@ -462,7 +498,7 @@ describe('Zeta Ssp Bid Adapter', function () {
it('Test required params in video request', function () {
const request = spec.buildRequests(videoRequest, videoRequest[0]);
const payload = JSON.parse(request.data);
- expect(request.url).to.eql('https://ssp.disqus.com/bid/prebid?shortname=test_shortname');
+ expect(request.url).to.eql('https://ssp.disqus.com/bid/prebid?sid=publisherId');
expect(payload.ext.sid).to.eql('publisherId');
expect(payload.ext.tags.someTag).to.eql(444);
expect(payload.ext.tags.shortname).to.be.undefined;
@@ -471,7 +507,7 @@ describe('Zeta Ssp Bid Adapter', function () {
it('Test multi imp', function () {
const request = spec.buildRequests(multiImpRequest, multiImpRequest[0]);
const payload = JSON.parse(request.data);
- expect(request.url).to.eql('https://ssp.disqus.com/bid/prebid?shortname=test_shortname');
+ expect(request.url).to.eql('https://ssp.disqus.com/bid/prebid?sid=publisherId');
expect(payload.imp.length).to.eql(2);
@@ -566,6 +602,7 @@ describe('Zeta Ssp Bid Adapter', function () {
expect(bidResponse[0].mediaType).to.eql(BANNER);
expect(bidResponse[0].ad).to.eql(zetaResponse.body.seatbid[0].bid[0].adm);
expect(bidResponse[0].vastXml).to.be.undefined;
+ expect(bidResponse[0].dspId).to.eql(zetaResponse.body.seatbid[0].seat);
});
it('Test the response default mediaType:video', function () {
@@ -575,6 +612,7 @@ describe('Zeta Ssp Bid Adapter', function () {
expect(bidResponse[0].mediaType).to.eql(VIDEO);
expect(bidResponse[0].ad).to.eql(zetaResponse.body.seatbid[0].bid[0].adm);
expect(bidResponse[0].vastXml).to.eql(zetaResponse.body.seatbid[0].bid[0].adm);
+ expect(bidResponse[0].dspId).to.eql(zetaResponse.body.seatbid[0].seat);
});
it('Test the response mediaType:video from ext param', function () {
@@ -589,6 +627,7 @@ describe('Zeta Ssp Bid Adapter', function () {
expect(bidResponse[0].mediaType).to.eql(VIDEO);
expect(bidResponse[0].ad).to.eql(zetaResponse.body.seatbid[0].bid[0].adm);
expect(bidResponse[0].vastXml).to.eql(zetaResponse.body.seatbid[0].bid[0].adm);
+ expect(bidResponse[0].dspId).to.eql(zetaResponse.body.seatbid[0].seat);
});
it('Test the response mediaType:banner from ext param', function () {
@@ -603,5 +642,41 @@ describe('Zeta Ssp Bid Adapter', function () {
expect(bidResponse[0].mediaType).to.eql(BANNER);
expect(bidResponse[0].ad).to.eql(zetaResponse.body.seatbid[0].bid[0].adm);
expect(bidResponse[0].vastXml).to.be.undefined;
+ expect(bidResponse[0].dspId).to.eql(zetaResponse.body.seatbid[0].seat);
+ });
+
+ it('Test provide segments into the request', function () {
+ const request = spec.buildRequests(bannerRequest, bannerRequest[0]);
+ const payload = JSON.parse(request.data);
+ expect(payload.user.data[0].segment.length).to.eql(3);
+ expect(payload.user.data[0].segment[0].id).to.eql('3');
+ expect(payload.user.data[0].segment[1].id).to.eql('44');
+ expect(payload.user.data[0].segment[2].id).to.eql('59');
+ });
+
+ it('Test provide device params', function () {
+ const request = spec.buildRequests(bannerRequest, bannerRequest[0]);
+ const payload = JSON.parse(request.data);
+
+ expect(payload.device.sua.mobile).to.eql(1);
+ expect(payload.device.sua.architecture).to.eql('arm');
+ expect(payload.device.sua.platform.brand).to.eql('Chrome');
+ expect(payload.device.sua.platform.version[0]).to.eql('102');
+
+ expect(payload.device.ua).to.not.be.undefined;
+ expect(payload.device.language).to.not.be.undefined;
+ expect(payload.device.w).to.not.be.undefined;
+ expect(payload.device.h).to.not.be.undefined;
+ });
+
+ it('Test that all empties are removed', function () {
+ const request = spec.buildRequests(bannerRequest, bannerRequest[0]);
+ const payload = JSON.parse(request.data);
+
+ expect(payload.ext.tags.someTag).to.eql(444);
+
+ expect(payload.ext.tags.emptyTag).to.be.undefined;
+ expect(payload.ext.tags.nullTag).to.be.undefined;
+ expect(payload.ext.tags.complexEmptyTag).to.be.undefined;
});
});
diff --git a/test/spec/modules/zmaticooBidAdapter_spec.js b/test/spec/modules/zmaticooBidAdapter_spec.js
new file mode 100644
index 00000000000..bb89984c738
--- /dev/null
+++ b/test/spec/modules/zmaticooBidAdapter_spec.js
@@ -0,0 +1,266 @@
+import {checkParamDataType, spec} from '../../../modules/zmaticooBidAdapter.js'
+import utils, {deepClone} from '../../../src/utils';
+import {expect} from 'chai';
+
+describe('zMaticoo Bidder Adapter', function () {
+ const bannerRequest = [{
+ auctionId: '223',
+ mediaTypes: {
+ banner: {
+ sizes: [[320, 50]],
+ }
+ },
+ refererInfo: {
+ page: 'testprebid.com'
+ },
+ params: {
+ user: {
+ uid: '12345',
+ buyeruid: '12345'
+ },
+ pubId: 'prebid-test',
+ test: 1,
+ bidfloor: 1,
+ tagid: 'test'
+ }
+ }];
+ const bannerRequest1 = [{
+ auctionId: '223',
+ mediaTypes: {
+ banner: {
+ sizes: [[320, 50]],
+ }
+ },
+ refererInfo: {
+ page: 'testprebid.com'
+ },
+ params: {
+ user: {
+ uid: '12345',
+ buyeruid: '12345'
+ },
+ pubId: 'prebid-test',
+ test: 1,
+ tagid: 'test'
+ },
+ gdprConsent: {
+ gdprApplies: 1,
+ consentString: 'consentString'
+ },
+ getFloor: function () {
+ return {
+ currency: 'USD',
+ floor: 0.5,
+ }
+ },
+ }];
+ const videoRequest = [{
+ auctionId: '223',
+ mediaTypes: {
+ video: {
+ playerSize: [480, 320],
+ mimes: ['video/mp4'],
+ context: 'instream',
+ placement: 1,
+ maxduration: 30,
+ minduration: 15,
+ pos: 1,
+ startdelay: 10,
+ protocols: [2, 3],
+ api: [2, 3],
+ playbackmethod: [2, 6],
+ skip: 10,
+ }
+ },
+ refererInfo: {
+ page: 'testprebid.com'
+ },
+ params: {
+ user: {
+ uid: '12345',
+ buyeruid: '12345'
+ },
+ pubId: 'prebid-test',
+ test: 1,
+ tagid: 'test',
+ bidfloor: 1
+ }
+ }];
+
+ const videoRequest1 = [{
+ auctionId: '223',
+ mediaTypes: {
+ video: {
+ playerSize: [[480, 320]],
+ mimes: ['video/mp4'],
+ context: 'instream',
+ placement: 1,
+ maxduration: 30,
+ minduration: 15,
+ pos: 1,
+ startdelay: 10,
+ protocols: [2, 3],
+ api: [2, 3],
+ playbackmethod: [2, 6],
+ skip: 10,
+ }
+ },
+ params: {
+ user: {
+ uid: '12345',
+ buyeruid: '12345'
+ },
+ pubId: 'prebid-test',
+ test: 1,
+ tagid: 'test',
+ bidfloor: 1
+ }
+ }];
+
+ describe('isBidRequestValid', function () {
+ it('this is valid bidrequest', function () {
+ const validBid = spec.isBidRequestValid(videoRequest[0]);
+ expect(validBid).to.be.true;
+ });
+ it('missing required bid data {bid}', function () {
+ const invalidBid = spec.isBidRequestValid(null);
+ expect(invalidBid).to.be.false;
+ });
+ it('missing required params.pubId', function () {
+ const request = deepClone(videoRequest[0])
+ delete request.params.pubId
+ const invalidBid = spec.isBidRequestValid(request);
+ expect(invalidBid).to.be.false;
+ });
+ })
+ describe('buildRequests', function () {
+ it('Test the banner request processing function', function () {
+ const request = spec.buildRequests(bannerRequest, bannerRequest[0]);
+ expect(request).to.not.be.empty;
+ const payload = request.data;
+ expect(payload).to.not.be.empty;
+ });
+ it('Test the video request processing function', function () {
+ const request = spec.buildRequests(videoRequest, videoRequest[0]);
+ expect(request).to.not.be.empty;
+ const payload = request.data;
+ expect(payload).to.not.be.empty;
+ });
+ it('Test the param', function () {
+ const request = spec.buildRequests(bannerRequest, bannerRequest[0]);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].tagid).to.eql(videoRequest[0].params.tagid);
+ expect(payload.imp[0].bidfloor).to.eql(videoRequest[0].params.bidfloor);
+ });
+ it('Test video object', function () {
+ const request = spec.buildRequests(videoRequest, videoRequest[0]);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].video).to.exist;
+ expect(payload.imp[0].video.minduration).to.eql(videoRequest[0].mediaTypes.video.minduration);
+ expect(payload.imp[0].video.maxduration).to.eql(videoRequest[0].mediaTypes.video.maxduration);
+ expect(payload.imp[0].video.protocols).to.eql(videoRequest[0].mediaTypes.video.protocols);
+ expect(payload.imp[0].video.mimes).to.eql(videoRequest[0].mediaTypes.video.mimes);
+ expect(payload.imp[0].video.w).to.eql(480);
+ expect(payload.imp[0].video.h).to.eql(320);
+ expect(payload.imp[0].banner).to.be.undefined;
+ });
+
+ it('Test video isArray size', function () {
+ const request = spec.buildRequests(videoRequest1, videoRequest1[0]);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].video.w).to.eql(480);
+ expect(payload.imp[0].video.h).to.eql(320);
+ });
+ it('Test banner object', function () {
+ const request = spec.buildRequests(bannerRequest, bannerRequest[0]);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].video).to.be.undefined;
+ expect(payload.imp[0].banner).to.exist;
+ });
+
+ it('Test provide gdpr and ccpa values in payload', function () {
+ const request = spec.buildRequests(bannerRequest1, bannerRequest1[0]);
+ const payload = JSON.parse(request.data);
+ expect(payload.user.ext.consent).to.eql('consentString');
+ expect(payload.regs.ext.gdpr).to.eql(1);
+ });
+
+ it('Test bidfloor is function', function () {
+ const request = spec.buildRequests(bannerRequest1, bannerRequest1[0]);
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].bidfloor).to.eql(0.5);
+ });
+ });
+ describe('checkParamDataType tests', function () {
+ it('return the expected datatypes', function () {
+ assert.isString(checkParamDataType('Right string', 'test', 'string'));
+ assert.isBoolean(checkParamDataType('Right bool', true, 'boolean'));
+ assert.isNumber(checkParamDataType('Right number', 10, 'number'));
+ assert.isArray(checkParamDataType('Right array', [10, 11], 'array'));
+ });
+
+ it('return undefined var for wrong datatypes', function () {
+ expect(checkParamDataType('Wrong string', 10, 'string')).to.be.undefined;
+ expect(checkParamDataType('Wrong bool', 10, 'boolean')).to.be.undefined;
+ expect(checkParamDataType('Wrong number', 'one', 'number')).to.be.undefined;
+ expect(checkParamDataType('Wrong array', false, 'array')).to.be.undefined;
+ });
+ })
+ describe('interpretResponse', function () {
+ const responseBody = {
+ id: '12345',
+ seatbid: [
+ {
+ bid: [
+ {
+ id: 'auctionId',
+ impid: 'impId',
+ price: 0.0,
+ adm: 'adMarkup',
+ crid: 'creativeId',
+ adomain: ['test.com'],
+ h: 50,
+ w: 320,
+ nurl: 'https://gwbudgetali.iymedia.me/budget.php',
+ ext: {
+ vast_url: '
',
+ prebid: {
+ type: 'banner'
+ }
+ }
+ }
+ ]
+ }
+ ],
+ cur: 'USD'
+ };
+ it('Test the response parsing function', function () {
+ const receivedBid = responseBody.seatbid[0].bid[0];
+ const response = {};
+ response.body = responseBody;
+ const bidResponse = spec.interpretResponse(response, null);
+ expect(bidResponse).to.not.be.empty;
+ const bid = bidResponse[0];
+ expect(bid).to.not.be.empty;
+ expect(bid.ad).to.equal(receivedBid.adm);
+ expect(bid.cpm).to.equal(receivedBid.price);
+ expect(bid.height).to.equal(receivedBid.h);
+ expect(bid.width).to.equal(receivedBid.w);
+ expect(bid.requestId).to.equal(receivedBid.impid);
+ expect(bid.vastXml).to.equal(receivedBid.ext.vast_url);
+ expect(bid.meta.advertiserDomains).to.equal(receivedBid.adomain);
+ expect(bid.mediaType).to.equal(receivedBid.ext.prebid.type);
+ expect(bid.nurl).to.equal(receivedBid.nurl);
+ });
+ });
+ describe('onBidWon', function () {
+ it('should make an ajax call with the original cpm', function () {
+ const bid = {
+ nurl: 'http://test.com/win?auctionPrice=${AUCTION_PRICE}',
+ cpm: 2.1,
+ }
+ const bidWonResult = spec.onBidWon(bid)
+ expect(bidWonResult).to.equal(true)
+ });
+ })
+});
diff --git a/test/spec/native_spec.js b/test/spec/native_spec.js
index 9cfee6f5cd8..9184601a76d 100644
--- a/test/spec/native_spec.js
+++ b/test/spec/native_spec.js
@@ -9,7 +9,12 @@ import {
decorateAdUnitsWithNativeParams,
isOpenRTBBidRequestValid,
isNativeOpenRTBBidValid,
- toOrtbNativeRequest, toOrtbNativeResponse, legacyPropertiesToOrtbNative, fireImpressionTrackers, fireClickTrackers,
+ toOrtbNativeRequest,
+ toOrtbNativeResponse,
+ legacyPropertiesToOrtbNative,
+ fireImpressionTrackers,
+ fireClickTrackers,
+ setNativeResponseProperties,
} from 'src/native.js';
import CONSTANTS from 'src/constants.json';
import { stubAuctionIndex } from '../helpers/indexStub.js';
@@ -19,7 +24,7 @@ const utils = require('src/utils');
const bid = {
adId: '123',
- transactionId: 'au',
+ adUnitId: 'au',
native: {
title: 'Native Creative',
body: 'Cool description great stuff',
@@ -49,7 +54,7 @@ const bid = {
const ortbBid = {
adId: '123',
- transactionId: 'au',
+ adUnitId: 'au',
native: {
ortb: {
assets: [
@@ -106,7 +111,7 @@ const ortbBid = {
const completeNativeBid = {
adId: '123',
- transactionId: 'au',
+ adUnitId: 'au',
native: {
...bid.native,
...ortbBid.native
@@ -157,7 +162,7 @@ const ortbRequest = {
}
const bidWithUndefinedFields = {
- transactionId: 'au',
+ adUnitId: 'au',
native: {
title: 'Native Creative',
body: undefined,
@@ -209,7 +214,7 @@ describe('native.js', function () {
it('sends placeholders for configured assets', function () {
const adUnit = {
- transactionId: 'au',
+ adUnitId: 'au',
nativeParams: {
body: { sendId: true },
clickUrl: { sendId: true },
@@ -246,7 +251,7 @@ describe('native.js', function () {
it('should only include native targeting keys with values', function () {
const adUnit = {
- transactionId: 'au',
+ adUnitId: 'au',
nativeParams: {
body: { sendId: true },
clickUrl: { sendId: true },
@@ -273,7 +278,7 @@ describe('native.js', function () {
it('should only include targeting that has sendTargetingKeys set to true', function () {
const adUnit = {
- transactionId: 'au',
+ adUnitId: 'au',
nativeParams: {
image: {
required: true,
@@ -294,7 +299,7 @@ describe('native.js', function () {
it('should only include targeting if sendTargetingKeys not set to false', function () {
const adUnit = {
- transactionId: 'au',
+ adUnitId: 'au',
nativeParams: {
image: {
required: true,
@@ -345,73 +350,10 @@ describe('native.js', function () {
]);
});
- it('should copy over rendererUrl to bid object and include it in targeting', function () {
- const adUnit = {
- transactionId: 'au',
- nativeParams: {
- image: {
- required: true,
- sizes: [150, 50],
- },
- title: {
- required: true,
- len: 80,
- },
- rendererUrl: {
- url: 'https://www.renderer.com/',
- },
- },
- };
- const targeting = getNativeTargeting(bid, deps(adUnit));
-
- expect(Object.keys(targeting)).to.deep.equal([
- CONSTANTS.NATIVE_KEYS.title,
- CONSTANTS.NATIVE_KEYS.body,
- CONSTANTS.NATIVE_KEYS.cta,
- CONSTANTS.NATIVE_KEYS.image,
- CONSTANTS.NATIVE_KEYS.icon,
- CONSTANTS.NATIVE_KEYS.sponsoredBy,
- CONSTANTS.NATIVE_KEYS.clickUrl,
- CONSTANTS.NATIVE_KEYS.privacyLink,
- CONSTANTS.NATIVE_KEYS.rendererUrl,
- ]);
-
- expect(bid.native.rendererUrl).to.deep.equal('https://www.renderer.com/');
- delete bid.native.rendererUrl;
- });
-
- it('should copy over adTemplate to bid object and include it in targeting', function () {
- const adUnit = {
- transactionId: 'au',
- nativeParams: {
- image: {
- required: true,
- sizes: [150, 50],
- },
- title: {
- required: true,
- len: 80,
- },
- adTemplate: '',
- },
- };
- const targeting = getNativeTargeting(bid, deps(adUnit));
-
- expect(Object.keys(targeting)).to.deep.equal([
- CONSTANTS.NATIVE_KEYS.title,
- CONSTANTS.NATIVE_KEYS.body,
- CONSTANTS.NATIVE_KEYS.cta,
- CONSTANTS.NATIVE_KEYS.image,
- CONSTANTS.NATIVE_KEYS.icon,
- CONSTANTS.NATIVE_KEYS.sponsoredBy,
- CONSTANTS.NATIVE_KEYS.clickUrl,
- CONSTANTS.NATIVE_KEYS.privacyLink,
- ]);
-
- expect(bid.native.adTemplate).to.deep.equal(
- ''
- );
- delete bid.native.adTemplate;
+ it('should include rendererUrl in targeting', function () {
+ const rendererUrl = 'https://www.renderer.com/';
+ const targeting = getNativeTargeting({...bid, native: {...bid.native, rendererUrl: {url: rendererUrl}}}, deps({}));
+ expect(targeting[CONSTANTS.NATIVE_KEYS.rendererUrl]).to.eql(rendererUrl);
});
it('fires impression trackers', function () {
@@ -646,6 +588,58 @@ describe('native.js', function () {
expect(actual.impressionTrackers).to.contain('https://sample-imp.com');
});
});
+
+ describe('setNativeResponseProperties', () => {
+ let adUnit;
+ beforeEach(() => {
+ adUnit = {
+ mediaTypes: {
+ native: {},
+ },
+ nativeParams: {}
+ };
+ });
+ it('sets legacy response', () => {
+ adUnit.nativeOrtbRequest = {
+ assets: [{
+ id: 1,
+ data: {
+ type: 2
+ }
+ }]
+ };
+ const ortbBid = {
+ ...bid,
+ native: {
+ ortb: {
+ link: {
+ url: 'clickurl'
+ },
+ assets: [{
+ id: 1,
+ data: {
+ value: 'body'
+ }
+ }]
+ }
+ }
+ };
+ setNativeResponseProperties(ortbBid, adUnit);
+ expect(ortbBid.native.clickUrl).to.eql('clickurl');
+ expect(ortbBid.native.body).to.eql('body');
+ });
+
+ it('sets rendererUrl', () => {
+ adUnit.nativeParams.rendererUrl = {url: 'renderer'};
+ setNativeResponseProperties(bid, adUnit);
+ expect(bid.native.rendererUrl).to.eql('renderer');
+ });
+ it('sets adTemplate', () => {
+ adUnit.nativeParams.adTemplate = 'template';
+ setNativeResponseProperties(bid, adUnit);
+ expect(bid.native.adTemplate).to.eql('template');
+ });
+ });
});
describe('validate native openRTB', function () {
@@ -724,7 +718,7 @@ describe('validate native openRTB', function () {
describe('validate native', function () {
const adUnit = {
- transactionId: 'test_adunit',
+ adUnitId: 'test_adunit',
mediaTypes: {
native: {
title: {
@@ -749,7 +743,7 @@ describe('validate native', function () {
let validBid = {
adId: 'abc123',
requestId: 'test_bid_id',
- transactionId: 'test_adunit',
+ adUnitId: 'test_adunit',
adUnitCode: '123/prebid_native_adunit',
bidder: 'test_bidder',
native: {
@@ -776,7 +770,7 @@ describe('validate native', function () {
let noIconDimBid = {
adId: 'abc234',
requestId: 'test_bid_id',
- transactionId: 'test_adunit',
+ adUnitId: 'test_adunit',
adUnitCode: '123/prebid_native_adunit',
bidder: 'test_bidder',
native: {
@@ -799,7 +793,7 @@ describe('validate native', function () {
let noImgDimBid = {
adId: 'abc345',
requestId: 'test_bid_id',
- transactionId: 'test_adunit',
+ adUnitId: 'test_adunit',
adUnitCode: '123/prebid_native_adunit',
bidder: 'test_bidder',
native: {
@@ -836,7 +830,7 @@ describe('validate native', function () {
it('should convert from old-style native to OpenRTB request', () => {
const adUnit = {
- transactionId: 'test_adunit',
+ adUnitId: 'test_adunit',
mediaTypes: {
native: {
title: {
@@ -1043,7 +1037,7 @@ describe('validate native', function () {
const validBidRequests = [{
bidId: 'bidId3',
adUnitCode: 'adUnitCode3',
- transactionId: 'transactionId3',
+ adUnitId: 'transactionId3',
mediaTypes: {
banner: {}
},
diff --git a/test/spec/ortbConverter/common_spec.js b/test/spec/ortbConverter/common_spec.js
new file mode 100644
index 00000000000..d2d61e6778c
--- /dev/null
+++ b/test/spec/ortbConverter/common_spec.js
@@ -0,0 +1,29 @@
+import {DEFAULT_PROCESSORS} from '../../../libraries/ortbConverter/processors/default.js';
+import {BID_RESPONSE} from '../../../src/pbjsORTB.js';
+
+describe('common processors', () => {
+ describe('bid response properties', () => {
+ const responseProps = DEFAULT_PROCESSORS[BID_RESPONSE].props.fn;
+ let context;
+
+ beforeEach(() => {
+ context = {
+ ortbResponse: {}
+ }
+ })
+
+ describe('meta.dsa', () => {
+ const MOCK_DSA = {transparency: 'info'};
+ it('is not set if bid has no meta.dsa', () => {
+ const resp = {};
+ responseProps(resp, {}, context);
+ expect(resp.meta?.dsa).to.not.exist;
+ });
+ it('is set to ext.dsa otherwise', () => {
+ const resp = {};
+ responseProps(resp, {ext: {dsa: MOCK_DSA}}, context);
+ expect(resp.meta.dsa).to.eql(MOCK_DSA);
+ })
+ })
+ })
+})
diff --git a/test/spec/unit/adRendering_spec.js b/test/spec/unit/adRendering_spec.js
new file mode 100644
index 00000000000..c2f62842c7e
--- /dev/null
+++ b/test/spec/unit/adRendering_spec.js
@@ -0,0 +1,248 @@
+import * as events from 'src/events.js';
+import * as utils from 'src/utils.js';
+import {
+ doRender,
+ getRenderingData,
+ handleCreativeEvent,
+ handleNativeMessage,
+ handleRender
+} from '../../../src/adRendering.js';
+import CONSTANTS from 'src/constants.json';
+import {expect} from 'chai/index.mjs';
+import {config} from 'src/config.js';
+import {VIDEO} from '../../../src/mediaTypes.js';
+import {auctionManager} from '../../../src/auctionManager.js';
+
+describe('adRendering', () => {
+ let sandbox;
+ beforeEach(() => {
+ sandbox = sinon.sandbox.create();
+ sandbox.stub(utils, 'logWarn');
+ sandbox.stub(utils, 'logError');
+ })
+ afterEach(() => {
+ sandbox.restore();
+ })
+
+ describe('getRenderingData', () => {
+ let bidResponse;
+ beforeEach(() => {
+ bidResponse = {};
+ });
+
+ ['ad', 'adUrl'].forEach((prop) => {
+ describe(`on ${prop}`, () => {
+ it('replaces AUCTION_PRICE macro', () => {
+ bidResponse[prop] = 'pre${AUCTION_PRICE}post';
+ bidResponse.cpm = 123;
+ const result = getRenderingData(bidResponse);
+ expect(result[prop]).to.eql('pre123post');
+ });
+ it('replaces CLICKTHROUGH macro', () => {
+ bidResponse[prop] = 'pre${CLICKTHROUGH}post';
+ const result = getRenderingData(bidResponse, {clickUrl: 'clk'});
+ expect(result[prop]).to.eql('preclkpost');
+ });
+ it('defaults CLICKTHROUGH to empty string', () => {
+ bidResponse[prop] = 'pre${CLICKTHROUGH}post';
+ const result = getRenderingData(bidResponse);
+ expect(result[prop]).to.eql('prepost');
+ });
+ });
+ });
+ })
+
+ describe('rendering logic', () => {
+ let bidResponse, renderFn, resizeFn, adId;
+ beforeEach(() => {
+ sandbox.stub(events, 'emit');
+ renderFn = sinon.stub();
+ resizeFn = sinon.stub();
+ adId = 123;
+ bidResponse = {
+ adId
+ }
+ });
+
+ function expectAdRenderFailedEvent(reason) {
+ sinon.assert.calledWith(events.emit, CONSTANTS.EVENTS.AD_RENDER_FAILED, sinon.match({adId, reason}));
+ }
+
+ describe('doRender', () => {
+ let getRenderingDataStub;
+ function getRenderingDataHook(next, ...args) {
+ next.bail(getRenderingDataStub(...args));
+ }
+ before(() => {
+ getRenderingData.before(getRenderingDataHook, 999);
+ })
+ after(() => {
+ getRenderingData.getHooks({hook: getRenderingDataHook}).remove();
+ });
+ beforeEach(() => {
+ getRenderingDataStub = sinon.stub();
+ })
+
+ describe('when the ad has a renderer', () => {
+ let bidResponse;
+ beforeEach(() => {
+ bidResponse = {
+ adId: 'mock-ad-id',
+ renderer: {
+ url: 'some-custom-renderer',
+ render: sinon.stub()
+ }
+ }
+ });
+
+ it('does not invoke renderFn, but the renderer instead', () => {
+ doRender({renderFn, bidResponse});
+ sinon.assert.notCalled(renderFn);
+ sinon.assert.called(bidResponse.renderer.render);
+ });
+
+ it('emits AD_RENDER_SUCCEDED', () => {
+ doRender({renderFn, bidResponse});
+ sinon.assert.calledWith(events.emit, CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED, sinon.match({
+ bid: bidResponse,
+ adId: bidResponse.adId
+ }));
+ });
+ });
+
+ if (FEATURES.VIDEO) {
+ it('should emit AD_RENDER_FAILED on video bids', () => {
+ bidResponse.mediaType = VIDEO;
+ doRender({renderFn, bidResponse});
+ expectAdRenderFailedEvent(CONSTANTS.AD_RENDER_FAILED_REASON.PREVENT_WRITING_ON_MAIN_DOCUMENT)
+ });
+ }
+
+ it('invokes renderFn with rendering data', () => {
+ const data = {ad: 'creative'};
+ getRenderingDataStub.returns(data);
+ doRender({renderFn, resizeFn, bidResponse});
+ sinon.assert.calledWith(renderFn, sinon.match({
+ adId: bidResponse.adId,
+ ...data
+ }))
+ });
+
+ it('invokes resizeFn with w/h from rendering data', () => {
+ getRenderingDataStub.returns({width: 123, height: 321});
+ doRender({renderFn, resizeFn, bidResponse});
+ sinon.assert.calledWith(resizeFn, 123, 321);
+ });
+
+ it('does not invoke resizeFn if rendering data has no w/h', () => {
+ getRenderingDataStub.returns({});
+ doRender({renderFn, resizeFn, bidResponse});
+ sinon.assert.notCalled(resizeFn);
+ })
+ });
+
+ describe('handleRender', () => {
+ let doRenderStub
+ function doRenderHook(next, ...args) {
+ next.bail(doRenderStub(...args));
+ }
+ before(() => {
+ doRender.before(doRenderHook, 999);
+ })
+ after(() => {
+ doRender.getHooks({hook: doRenderHook}).remove();
+ })
+ beforeEach(() => {
+ sandbox.stub(auctionManager, 'addWinningBid');
+ doRenderStub = sinon.stub();
+ })
+ describe('should emit AD_RENDER_FAILED', () => {
+ it('when bidResponse is missing', () => {
+ handleRender({adId});
+ expectAdRenderFailedEvent(CONSTANTS.AD_RENDER_FAILED_REASON.CANNOT_FIND_AD);
+ sinon.assert.notCalled(doRenderStub);
+ });
+ it('on exceptions', () => {
+ doRenderStub.throws(new Error());
+ handleRender({adId, bidResponse});
+ expectAdRenderFailedEvent(CONSTANTS.AD_RENDER_FAILED_REASON.EXCEPTION);
+ });
+ })
+
+ describe('when bid was already rendered', () => {
+ beforeEach(() => {
+ bidResponse.status = CONSTANTS.BID_STATUS.RENDERED;
+ });
+ afterEach(() => {
+ config.resetConfig();
+ })
+ it('should emit STALE_RENDER', () => {
+ handleRender({adId, bidResponse});
+ sinon.assert.calledWith(events.emit, CONSTANTS.EVENTS.STALE_RENDER, bidResponse);
+ sinon.assert.called(doRenderStub);
+ });
+ it('should skip rendering if suppressStaleRender', () => {
+ config.setConfig({auctionOptions: {suppressStaleRender: true}});
+ handleRender({adId, bidResponse});
+ sinon.assert.notCalled(doRenderStub);
+ })
+ });
+
+ it('should mark bid as won and emit BID_WON', () => {
+ handleRender({renderFn, bidResponse});
+ sinon.assert.calledWith(events.emit, CONSTANTS.EVENTS.BID_WON, bidResponse);
+ sinon.assert.calledWith(auctionManager.addWinningBid, bidResponse);
+ })
+ })
+ })
+
+ describe('handleCreativeEvent', () => {
+ let bid;
+ beforeEach(() => {
+ sandbox.stub(events, 'emit');
+ bid = {
+ status: CONSTANTS.BID_STATUS.RENDERED
+ }
+ });
+ it('emits AD_RENDER_FAILED with given reason', () => {
+ handleCreativeEvent({event: CONSTANTS.EVENTS.AD_RENDER_FAILED, info: {reason: 'reason', message: 'message'}}, bid);
+ sinon.assert.calledWith(events.emit, CONSTANTS.EVENTS.AD_RENDER_FAILED, sinon.match({bid, reason: 'reason', message: 'message'}));
+ });
+
+ it('emits AD_RENDER_SUCCEEDED', () => {
+ handleCreativeEvent({event: CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED}, bid);
+ sinon.assert.calledWith(events.emit, CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED, sinon.match({bid}));
+ });
+
+ it('logs an error on other events', () => {
+ handleCreativeEvent({event: 'unsupported'}, bid);
+ sinon.assert.called(utils.logError);
+ sinon.assert.notCalled(events.emit);
+ });
+ });
+
+ describe('handleNativeMessage', () => {
+ if (!FEATURES.NATIVE) return;
+ let bid;
+ beforeEach(() => {
+ bid = {
+ adId: '123'
+ };
+ })
+
+ it('should resize', () => {
+ const resizeFn = sinon.stub();
+ handleNativeMessage({action: 'resizeNativeHeight', height: 100}, bid, {resizeFn});
+ sinon.assert.calledWith(resizeFn, undefined, 100);
+ });
+
+ it('should fire trackers', () => {
+ const data = {
+ action: 'click'
+ };
+ const fireTrackers = sinon.stub();
+ handleNativeMessage(data, bid, {fireTrackers});
+ sinon.assert.calledWith(fireTrackers, data, bid);
+ })
+ })
+});
diff --git a/test/spec/unit/core/adapterManager_spec.js b/test/spec/unit/core/adapterManager_spec.js
index 98d841d9c7c..dac70696b4b 100644
--- a/test/spec/unit/core/adapterManager_spec.js
+++ b/test/spec/unit/core/adapterManager_spec.js
@@ -964,25 +964,42 @@ describe('adapterManager tests', function () {
'start': 1462918897460
}];
- it('invokes callBids on the S2S adapter', function () {
- const done = sinon.stub();
- const onTimelyResponse = sinon.stub();
- prebidServerAdapterMock.callBids.callsFake((_1, _2, _3, done) => {
- done();
+ describe('invokes callBids on the S2S adapter', () => {
+ let onTimelyResponse, timedOut, done;
+ beforeEach(() => {
+ done = sinon.stub();
+ onTimelyResponse = sinon.stub();
+ prebidServerAdapterMock.callBids.callsFake((_1, _2, _3, done) => {
+ done(timedOut);
+ });
+ })
+
+ function runTest() {
+ adapterManager.callBids(
+ getAdUnits(),
+ bidRequests,
+ () => {},
+ done,
+ undefined,
+ undefined,
+ onTimelyResponse
+ );
+ sinon.assert.calledTwice(prebidServerAdapterMock.callBids);
+ sinon.assert.calledTwice(done);
+ }
+
+ it('and marks requests as timely if the adapter says timedOut = false', function () {
+ timedOut = false;
+ runTest();
+ bidRequests.forEach(br => sinon.assert.calledWith(onTimelyResponse, br.bidderRequestId));
});
- adapterManager.callBids(
- getAdUnits(),
- bidRequests,
- () => {},
- done,
- undefined,
- undefined,
- onTimelyResponse
- );
- sinon.assert.calledTwice(prebidServerAdapterMock.callBids);
- sinon.assert.calledTwice(done);
- bidRequests.forEach(br => sinon.assert.calledWith(onTimelyResponse, br.bidderRequestId));
- });
+
+ it('and does NOT mark them as timely if it says timedOut = true', () => {
+ timedOut = true;
+ runTest();
+ sinon.assert.notCalled(onTimelyResponse);
+ })
+ })
// Enable this test when prebidServer adapter is made 1.0 compliant
it('invokes callBids with only s2s bids', function () {
diff --git a/test/spec/unit/core/ajax_spec.js b/test/spec/unit/core/ajax_spec.js
index a3a0459b980..dd03ad1a761 100644
--- a/test/spec/unit/core/ajax_spec.js
+++ b/test/spec/unit/core/ajax_spec.js
@@ -232,7 +232,7 @@ describe('attachCallbacks', () => {
};
}
- function expectNullXHR(response) {
+ function expectNullXHR(response, reason) {
return new Promise((resolve, reject) => {
attachCallbacks(Promise.resolve(response), {
success: () => {
@@ -246,7 +246,8 @@ describe('attachCallbacks', () => {
statusText: '',
responseText: '',
response: '',
- responseXML: null
+ responseXML: null,
+ reason
});
expect(xhr.getResponseHeader('any')).to.be.null;
resolve();
@@ -256,9 +257,21 @@ describe('attachCallbacks', () => {
}
it('runs error callback on rejections', () => {
- return expectNullXHR(Promise.reject(new Error()));
+ const err = new Error();
+ return expectNullXHR(Promise.reject(err), err);
});
+ it('sets timedOut = true on fetch timeout', (done) => {
+ const ctl = new AbortController();
+ ctl.abort();
+ attachCallbacks(fetch('/', {signal: ctl.signal}), {
+ error(_, xhr) {
+ expect(xhr.timedOut).to.be.true;
+ done();
+ }
+ });
+ })
+
Object.entries({
'2xx response': {
success: true,
@@ -368,8 +381,9 @@ describe('attachCallbacks', () => {
});
it(`runs error callback if body cannot be retrieved`, () => {
- response.text = () => Promise.reject(new Error());
- return expectNullXHR(response);
+ const err = new Error();
+ response.text = () => Promise.reject(err);
+ return expectNullXHR(response, err);
});
if (success) {
diff --git a/test/spec/unit/core/auctionIndex_spec.js b/test/spec/unit/core/auctionIndex_spec.js
index f00e2cd281f..df29ed1a6cb 100644
--- a/test/spec/unit/core/auctionIndex_spec.js
+++ b/test/spec/unit/core/auctionIndex_spec.js
@@ -38,22 +38,22 @@ describe('auction index', () => {
let adUnits;
beforeEach(() => {
- adUnits = [{transactionId: 'au1'}, {transactionId: 'au2'}];
+ adUnits = [{adUnitId: 'au1'}, {adUnitId: 'au2'}];
auctions = [
mockAuction('a1', [adUnits[0], {}]),
mockAuction('a2', [adUnits[1]])
];
});
- it('should find adUnits by transactionId', () => {
- expect(index.getAdUnit({transactionId: 'au2'})).to.equal(adUnits[1]);
+ it('should find adUnits by adUnitId', () => {
+ expect(index.getAdUnit({adUnitId: 'au2'})).to.equal(adUnits[1]);
});
it('should return undefined if adunit is missing', () => {
- expect(index.getAdUnit({transactionId: 'missing'})).to.be.undefined;
+ expect(index.getAdUnit({adUnitId: 'missing'})).to.be.undefined;
});
- it('should return undefined if no transactionId is provided', () => {
+ it('should return undefined if no adUnitId is provided', () => {
expect(index.getAdUnit({})).to.be.undefined;
});
});
@@ -87,12 +87,12 @@ describe('auction index', () => {
beforeEach(() => {
mediaTypes = [{mockMT: '1'}, {mockMT: '2'}, {mockMT: '3'}, {mockMT: '4'}]
adUnits = [
- {transactionId: 'au1', mediaTypes: mediaTypes[0]},
- {transactionId: 'au2', mediaTypes: mediaTypes[1]}
+ {adUnitId: 'au1', mediaTypes: mediaTypes[0]},
+ {adUnitId: 'au2', mediaTypes: mediaTypes[1]}
]
bidderRequests = [
- {bidderRequestId: 'ber1', bids: [{bidId: 'b1', mediaTypes: mediaTypes[2], transactionId: 'au1'}, {}]},
- {bidderRequestId: 'ber2', bids: [{bidId: 'b2', mediaTypes: mediaTypes[3], transactionId: 'au2'}]}
+ {bidderRequestId: 'ber1', bids: [{bidId: 'b1', mediaTypes: mediaTypes[2], adUnitId: 'au1'}, {}]},
+ {bidderRequestId: 'ber2', bids: [{bidId: 'b2', mediaTypes: mediaTypes[3], adUnitId: 'au2'}]}
]
auctions = [
mockAuction('a1', [adUnits[0]], [bidderRequests[0], {}]),
@@ -100,8 +100,8 @@ describe('auction index', () => {
]
});
- it('should find mediaTypes by transactionId', () => {
- expect(index.getMediaTypes({transactionId: 'au2'})).to.equal(mediaTypes[1]);
+ it('should find mediaTypes by adUnitId', () => {
+ expect(index.getMediaTypes({adUnitId: 'au2'})).to.equal(mediaTypes[1]);
});
it('should find mediaTypes by requestId', () => {
@@ -109,18 +109,18 @@ describe('auction index', () => {
});
it('should give precedence to request.mediaTypes over adUnit.mediaTypes', () => {
- expect(index.getMediaTypes({requestId: 'b2', transactionId: 'au2'})).to.equal(mediaTypes[3]);
+ expect(index.getMediaTypes({requestId: 'b2', adUnitId: 'au2'})).to.equal(mediaTypes[3]);
});
- it('should return undef if requestId and transactionId do not match', () => {
- expect(index.getMediaTypes({requestId: 'b1', transactionId: 'au2'})).to.be.undefined;
+ it('should return undef if requestId and adUnitId do not match', () => {
+ expect(index.getMediaTypes({requestId: 'b1', adUnitId: 'au2'})).to.be.undefined;
});
it('should return undef if no params are provided', () => {
expect(index.getMediaTypes({})).to.be.undefined;
});
- ['requestId', 'transactionId'].forEach(param => {
+ ['requestId', 'adUnitId'].forEach(param => {
it(`should return undef if ${param} is missing`, () => {
expect(index.getMediaTypes({[param]: 'missing'})).to.be.undefined;
});
diff --git a/test/spec/unit/core/bidderFactory_spec.js b/test/spec/unit/core/bidderFactory_spec.js
index 4c13d830206..5fe5a1accfc 100644
--- a/test/spec/unit/core/bidderFactory_spec.js
+++ b/test/spec/unit/core/bidderFactory_spec.js
@@ -38,10 +38,6 @@ const MOCK_BIDS_REQUEST = {
]
}
-function onTimelyResponseStub() {
-
-}
-
before(() => {
hook.ready();
});
@@ -49,6 +45,10 @@ before(() => {
let wrappedCallback = config.callbackWithBidder(CODE);
describe('bidderFactory', () => {
+ let onTimelyResponseStub;
+ beforeEach(() => {
+ onTimelyResponseStub = sinon.stub();
+ })
describe('bidders created by newBidder', function () {
let spec;
let bidder;
@@ -422,7 +422,15 @@ describe('bidderFactory', () => {
});
describe('browsingTopics ajax option', () => {
- let transmitUfpdAllowed, bidder;
+ let transmitUfpdAllowed, bidder, origBS;
+ before(() => {
+ origBS = window.$$PREBID_GLOBAL$$.bidderSettings;
+ })
+
+ after(() => {
+ window.$$PREBID_GLOBAL$$.bidderSettings = origBS;
+ });
+
beforeEach(() => {
activityRules.isActivityAllowed.reset();
activityRules.isActivityAllowed.callsFake((activity) => activity === ACTIVITY_TRANSMIT_UFPD ? transmitUfpdAllowed : true);
@@ -448,49 +456,71 @@ describe('bidderFactory', () => {
});
Object.entries({
- 'allowed': true,
- 'not allowed': false
- }).forEach(([t, allow]) => {
- it(`should be set to ${allow} when transmitUfpd is ${t}`, () => {
- transmitUfpdAllowed = allow;
- spec.buildRequests.returns([
- {
- method: 'GET',
- url: '1',
- },
- {
- method: 'POST',
- url: '2',
- data: {}
- },
- {
- method: 'GET',
- url: '3',
- options: {
- browsingTopics: true
- }
- },
- {
- method: 'POST',
- url: '4',
- data: {},
- options: {
- browsingTopics: true
+ 'omitted': [undefined, true],
+ 'enabled': [true, true],
+ 'disabled': [false, false]
+ }).forEach(([t, [topicsHeader, enabled]]) => {
+ describe(`when bidderSettings.topicsHeader is ${t}`, () => {
+ beforeEach(() => {
+ window.$$PREBID_GLOBAL$$.bidderSettings = {
+ [CODE]: {
+ topicsHeader: topicsHeader
}
}
- ]);
- bidder.callBids(MOCK_BIDS_REQUEST, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);
- ['1', '2', '3', '4'].forEach(url => {
- sinon.assert.calledWith(
- ajaxStub,
- url,
- sinon.match.any,
- sinon.match.any,
- sinon.match({browsingTopics: allow})
- );
});
- });
- });
+
+ afterEach(() => {
+ delete window.$$PREBID_GLOBAL$$.bidderSettings[CODE];
+ });
+
+ Object.entries({
+ 'allowed': true,
+ 'not allowed': false
+ }).forEach(([t, allow]) => {
+ const shouldBeSet = allow && enabled;
+
+ it(`should be set to ${shouldBeSet} when transmitUfpd is ${t}`, () => {
+ transmitUfpdAllowed = allow;
+ spec.buildRequests.returns([
+ {
+ method: 'GET',
+ url: '1',
+ },
+ {
+ method: 'POST',
+ url: '2',
+ data: {}
+ },
+ {
+ method: 'GET',
+ url: '3',
+ options: {
+ browsingTopics: true
+ }
+ },
+ {
+ method: 'POST',
+ url: '4',
+ data: {},
+ options: {
+ browsingTopics: true
+ }
+ }
+ ]);
+ bidder.callBids(MOCK_BIDS_REQUEST, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);
+ ['1', '2', '3', '4'].forEach(url => {
+ sinon.assert.calledWith(
+ ajaxStub,
+ url,
+ sinon.match.any,
+ sinon.match.any,
+ sinon.match({browsingTopics: shouldBeSet})
+ );
+ });
+ });
+ });
+ })
+ })
});
it('should not add bids for each placement code if no requests are given', function () {
@@ -552,6 +582,14 @@ describe('bidderFactory', () => {
utils.logError.restore();
});
+ it('should call onTimelyResponse', () => {
+ const bidder = newBidder(spec);
+ spec.isBidRequestValid.returns(true);
+ spec.buildRequests.returns({method: 'POST', url: 'test', data: {}});
+ bidder.callBids(MOCK_BIDS_REQUEST, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);
+ sinon.assert.called(onTimelyResponseStub);
+ })
+
it('should call spec.interpretResponse() with the response content', function () {
const bidder = newBidder(spec);
@@ -770,12 +808,13 @@ describe('bidderFactory', () => {
let ajaxStub;
let callBidderErrorStub;
let eventEmitterStub;
- let xhrErrorMock = {
- status: 500,
- statusText: 'Internal Server Error'
- };
+ let xhrErrorMock;
beforeEach(function () {
+ xhrErrorMock = {
+ status: 500,
+ statusText: 'Internal Server Error'
+ };
ajaxStub = sinon.stub(ajax, 'ajax').callsFake(function(url, callbacks) {
callbacks.error('ajax call failed.', xhrErrorMock);
});
@@ -791,6 +830,20 @@ describe('bidderFactory', () => {
eventEmitterStub.restore();
});
+ Object.entries({
+ 'timeouts': true,
+ 'other errors': false
+ }).forEach(([t, timedOut]) => {
+ it(`should ${timedOut ? 'NOT ' : ''}call onTimelyResponse on ${t}`, () => {
+ Object.assign(xhrErrorMock, {timedOut});
+ const bidder = newBidder(spec);
+ spec.isBidRequestValid.returns(true);
+ spec.buildRequests.returns({method: 'POST', url: 'test', data: {}});
+ bidder.callBids(MOCK_BIDS_REQUEST, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);
+ sinon.assert[timedOut ? 'notCalled' : 'called'](onTimelyResponseStub);
+ })
+ })
+
it('should not spec.interpretResponse()', function () {
const bidder = newBidder(spec);
@@ -1056,7 +1109,7 @@ describe('bidderFactory', () => {
if (FEATURES.NATIVE) {
it('should add native bids that do have required assets', function () {
adUnits = [{
- transactionId: 'au',
+ adUnitId: 'au',
nativeParams: {
title: {'required': true},
}
@@ -1067,7 +1120,7 @@ describe('bidderFactory', () => {
bidId: '1',
auctionId: 'first-bid-id',
adUnitCode: 'mock/placement',
- transactionId: 'au',
+ adUnitId: 'au',
params: {
param: 5
},
@@ -1403,67 +1456,95 @@ describe('bidderFactory', () => {
transactionId: 'au',
}]
};
- const fledgeAuctionConfig = {
+ const paapiConfig = {
bidId: '1',
config: {
foo: 'bar'
}
}
- describe('when response has FLEDGE auction config', function() {
- let fledgeStub;
- function fledgeHook(next, ...args) {
- fledgeStub(...args);
+ it('should unwrap bids', function() {
+ const bidder = newBidder(spec);
+ spec.interpretResponse.returns({
+ bids: bids,
+ });
+ bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);
+ sinon.assert.calledWith(addBidResponseStub, 'mock/placement', sinon.match(bids[0]));
+ });
+
+ it('does not unwrap bids from a bid that happens to have a "bids" property', () => {
+ const bidder = newBidder(spec);
+ const bid = Object.assign({
+ bids: ['a', 'b']
+ }, bids[0]);
+ spec.interpretResponse.returns(bid);
+ bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);
+ sinon.assert.calledWith(addBidResponseStub, 'mock/placement', sinon.match(bid));
+ })
+
+ describe('when response has PAAPI auction config', function() {
+ let paapiStub;
+
+ function paapiHook(next, ...args) {
+ paapiStub(...args);
}
before(() => {
- addComponentAuction.before(fledgeHook);
+ addComponentAuction.before(paapiHook);
});
after(() => {
- addComponentAuction.getHooks({hook: fledgeHook}).remove();
+ addComponentAuction.getHooks({hook: paapiHook}).remove();
})
beforeEach(function () {
- fledgeStub = sinon.stub();
+ paapiStub = sinon.stub();
});
- it('should unwrap bids', function() {
- const bidder = newBidder(spec);
- spec.interpretResponse.returns({
- bids: bids,
- fledgeAuctionConfigs: []
- });
- bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);
- expect(addBidResponseStub.calledOnce).to.equal(true);
- expect(addBidResponseStub.firstCall.args[0]).to.equal('mock/placement');
- });
+ const PAAPI_PROPS = ['fledgeAuctionConfigs', 'paapiAuctionConfigs'];
- it('should call fledgeManager with FLEDGE configs', function() {
+ it(`should not accept both ${PAAPI_PROPS.join(' and ')}`, () => {
const bidder = newBidder(spec);
- spec.interpretResponse.returns({
- bids: bids,
- fledgeAuctionConfigs: [fledgeAuctionConfig]
- });
- bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);
-
- expect(fledgeStub.calledOnce).to.equal(true);
- sinon.assert.calledWith(fledgeStub, bidRequest.auctionId, 'mock/placement', fledgeAuctionConfig.config);
- expect(addBidResponseStub.calledOnce).to.equal(true);
- expect(addBidResponseStub.firstCall.args[0]).to.equal('mock/placement');
+ spec.interpretResponse.returns(Object.fromEntries(PAAPI_PROPS.map(prop => [prop, [paapiConfig]])))
+ expect(() => {
+ bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);
+ }).to.throw;
})
- it('should call fledgeManager with FLEDGE configs even if no bids returned', function() {
- const bidder = newBidder(spec);
- spec.interpretResponse.returns({
- bids: [],
- fledgeAuctionConfigs: [fledgeAuctionConfig]
- });
- bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);
+ PAAPI_PROPS.forEach(paapiProp => {
+ describe(`using ${paapiProp}`, () => {
+ it('should call paapi hook with PAAPI configs', function() {
+ const bidder = newBidder(spec);
+ spec.interpretResponse.returns({
+ bids: bids,
+ [paapiProp]: [paapiConfig]
+ });
+ bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);
+
+ expect(paapiStub.calledOnce).to.equal(true);
+ sinon.assert.calledWith(paapiStub, bidRequest.bids[0], paapiConfig.config);
+ expect(addBidResponseStub.calledOnce).to.equal(true);
+ expect(addBidResponseStub.firstCall.args[0]).to.equal('mock/placement');
+ })
- expect(fledgeStub.calledOnce).to.be.true;
- sinon.assert.calledWith(fledgeStub, bidRequest.auctionId, 'mock/placement', fledgeAuctionConfig.config);
- expect(addBidResponseStub.calledOnce).to.equal(false);
+ Object.entries({
+ 'missing': undefined,
+ 'an empty array': []
+ }).forEach(([t, bids]) => {
+ it(`should call paapi hook with PAAPI configs even when bids is ${t}`, function() {
+ const bidder = newBidder(spec);
+ spec.interpretResponse.returns({
+ bids,
+ [paapiProp]: [paapiConfig]
+ });
+ bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);
+
+ expect(paapiStub.calledOnce).to.be.true;
+ sinon.assert.calledWith(paapiStub, bidRequest.bids[0], paapiConfig.config);
+ expect(addBidResponseStub.calledOnce).to.equal(false);
+ })
+ })
+ })
})
})
})
diff --git a/test/spec/unit/core/events_spec.js b/test/spec/unit/core/events_spec.js
index 6551c9f2456..e1451f657b5 100644
--- a/test/spec/unit/core/events_spec.js
+++ b/test/spec/unit/core/events_spec.js
@@ -1,5 +1,6 @@
import {config} from 'src/config.js';
-import {emit, clearEvents, getEvents} from '../../../../src/events.js';
+import {emit, clearEvents, getEvents, on, off} from '../../../../src/events.js';
+import * as utils from '../../../../src/utils.js'
describe('events', () => {
let clock;
@@ -26,5 +27,19 @@ describe('events', () => {
config.setConfig({eventHistoryTTL: 1000});
clock.tick(10000);
expect(getEvents().length).to.eql(1);
- })
+ });
+
+ it('should include the eventString if a callback fails', () => {
+ const logErrorStub = sinon.stub(utils, 'logError');
+ const eventString = 'bidWon';
+ let fn = function() { throw new Error('Test error'); };
+ on(eventString, fn);
+
+ emit(eventString, {});
+
+ sinon.assert.calledWith(logErrorStub, 'Error executing handler:', 'events.js', sinon.match.instanceOf(Error), eventString);
+
+ off(eventString, fn);
+ logErrorStub.restore();
+ });
})
diff --git a/test/spec/unit/core/targeting_spec.js b/test/spec/unit/core/targeting_spec.js
index 4716e5749cb..ba9aeff70d1 100644
--- a/test/spec/unit/core/targeting_spec.js
+++ b/test/spec/unit/core/targeting_spec.js
@@ -955,6 +955,7 @@ describe('targeting tests', function () {
expect(bids.length).to.equal(1);
expect(bids[0].adId).to.equal('adid-1');
+ expect(bids[0].latestTargetedAuctionId).to.equal(2);
useBidCache = false;
@@ -962,6 +963,7 @@ describe('targeting tests', function () {
expect(bids.length).to.equal(1);
expect(bids[0].adId).to.equal('adid-2');
+ expect(bids[0].latestTargetedAuctionId).to.equal(2);
});
it('should use bidCacheFilterFunction', function() {
@@ -989,9 +991,13 @@ describe('targeting tests', function () {
expect(bids.length).to.equal(4);
expect(bids[0].adId).to.equal('adid-1');
+ expect(bids[0].latestTargetedAuctionId).to.equal(2);
expect(bids[1].adId).to.equal('adid-4');
+ expect(bids[1].latestTargetedAuctionId).to.equal(2);
expect(bids[2].adId).to.equal('adid-5');
+ expect(bids[2].latestTargetedAuctionId).to.equal(2);
expect(bids[3].adId).to.equal('adid-8');
+ expect(bids[3].latestTargetedAuctionId).to.equal(2);
// Bid Caching Off, No Filter Function
useBidCache = false;
@@ -1000,9 +1006,13 @@ describe('targeting tests', function () {
expect(bids.length).to.equal(4);
expect(bids[0].adId).to.equal('adid-2');
+ expect(bids[0].latestTargetedAuctionId).to.equal(2);
expect(bids[1].adId).to.equal('adid-4');
+ expect(bids[1].latestTargetedAuctionId).to.equal(2);
expect(bids[2].adId).to.equal('adid-6');
+ expect(bids[2].latestTargetedAuctionId).to.equal(2);
expect(bids[3].adId).to.equal('adid-8');
+ expect(bids[3].latestTargetedAuctionId).to.equal(2);
// Bid Caching On AGAIN, No Filter Function (should be same as first time)
useBidCache = true;
@@ -1011,9 +1021,13 @@ describe('targeting tests', function () {
expect(bids.length).to.equal(4);
expect(bids[0].adId).to.equal('adid-1');
+ expect(bids[0].latestTargetedAuctionId).to.equal(2);
expect(bids[1].adId).to.equal('adid-4');
+ expect(bids[1].latestTargetedAuctionId).to.equal(2);
expect(bids[2].adId).to.equal('adid-5');
+ expect(bids[2].latestTargetedAuctionId).to.equal(2);
expect(bids[3].adId).to.equal('adid-8');
+ expect(bids[3].latestTargetedAuctionId).to.equal(2);
// Bid Caching On, with Filter Function to Exclude video
useBidCache = true;
@@ -1026,9 +1040,13 @@ describe('targeting tests', function () {
expect(bids.length).to.equal(4);
expect(bids[0].adId).to.equal('adid-1');
+ expect(bids[0].latestTargetedAuctionId).to.equal(2);
expect(bids[1].adId).to.equal('adid-4');
+ expect(bids[1].latestTargetedAuctionId).to.equal(2);
expect(bids[2].adId).to.equal('adid-6');
+ expect(bids[2].latestTargetedAuctionId).to.equal(2);
expect(bids[3].adId).to.equal('adid-8');
+ expect(bids[3].latestTargetedAuctionId).to.equal(2);
// filter function should have been called for each cached bid (4 times)
expect(bcffCalled).to.equal(4);
@@ -1044,9 +1062,13 @@ describe('targeting tests', function () {
expect(bids.length).to.equal(4);
expect(bids[0].adId).to.equal('adid-2');
+ expect(bids[0].latestTargetedAuctionId).to.equal(2);
expect(bids[1].adId).to.equal('adid-4');
+ expect(bids[1].latestTargetedAuctionId).to.equal(2);
expect(bids[2].adId).to.equal('adid-6');
+ expect(bids[2].latestTargetedAuctionId).to.equal(2);
expect(bids[3].adId).to.equal('adid-8');
+ expect(bids[3].latestTargetedAuctionId).to.equal(2);
// filter function should not have been called
expect(bcffCalled).to.equal(0);
});
diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js
index b39c984316a..7f55a2cddf0 100644
--- a/test/spec/unit/pbjs_api_spec.js
+++ b/test/spec/unit/pbjs_api_spec.js
@@ -14,7 +14,7 @@ import { config as configObj } from 'src/config.js';
import * as ajaxLib from 'src/ajax.js';
import * as auctionModule from 'src/auction.js';
import { registerBidder } from 'src/adapters/bidderFactory.js';
-import { _sendAdToCreative } from 'src/secureCreatives.js';
+import {resizeRemoteCreative} from 'src/secureCreatives.js';
import {find} from 'src/polyfill.js';
import * as pbjsModule from 'src/prebid.js';
import {hook} from '../../../src/hook.js';
@@ -25,6 +25,9 @@ import {stubAuctionIndex} from '../../helpers/indexStub.js';
import {createBid} from '../../../src/bidfactory.js';
import {enrichFPD} from '../../../src/fpd/enrichment.js';
import {mockFpdEnrichments} from '../../helpers/fpd.js';
+import {generateUUID} from '../../../src/utils.js';
+import {getCreativeRenderer} from '../../../src/creativeRenderers.js';
+
var assert = require('chai').assert;
var expect = require('chai').expect;
@@ -42,11 +45,12 @@ var adUnits = getAdUnits();
var adUnitCodes = getAdUnits().map(unit => unit.code);
var bidsBackHandler = function() {};
const timeout = 2000;
+const auctionId = generateUUID();
let auction;
function resetAuction() {
if (auction == null) {
- auction = auctionManager.createAuction({adUnits, adUnitCodes, callback: bidsBackHandler, cbTimeout: timeout});
+ auction = auctionManager.createAuction({adUnits, adUnitCodes, callback: bidsBackHandler, cbTimeout: timeout, labels: undefined, auctionId: auctionId});
}
$$PREBID_GLOBAL$$.setConfig({ enableSendAllBids: false });
auction.getBidRequests = getBidRequests;
@@ -198,11 +202,13 @@ window.apntag = {
describe('Unit: Prebid Module', function () {
let bidExpiryStub, sandbox;
- before(() => {
+ before((done) => {
hook.ready();
$$PREBID_GLOBAL$$.requestBids.getHooks().remove();
resetDebugging();
sinon.stub(filters, 'isActualBid').returns(true); // stub this out so that we can use vanilla objects as bids
+ // preload creative renderer
+ getCreativeRenderer({}).then(() => done());
});
beforeEach(function () {
@@ -554,6 +560,7 @@ describe('Unit: Prebid Module', function () {
'bidderRequestId': '331f3cf3f1d9c8',
'auctionId': '20882439e3238c',
'transactionId': 'trdiv-gpt-ad-1460505748561-0',
+ 'adUnitId': 'audiv-gpt-ad-1460505748561-0',
}
],
'auctionStart': 1505250713622,
@@ -571,6 +578,7 @@ describe('Unit: Prebid Module', function () {
let auctionManagerInstance = newAuctionManager();
targeting = newTargeting(auctionManagerInstance);
let adUnits = [{
+ adUnitId: 'audiv-gpt-ad-1460505748561-0',
transactionId: 'trdiv-gpt-ad-1460505748561-0',
code: 'div-gpt-ad-1460505748561-0',
sizes: [[300, 250], [300, 600]],
@@ -716,6 +724,7 @@ describe('Unit: Prebid Module', function () {
const adUnit = {
transactionId: `tr${code}`,
+ adUnitId: `au${code}`,
code: code,
sizes: [[300, 250], [300, 600]],
bids: [{
@@ -818,6 +827,7 @@ describe('Unit: Prebid Module', function () {
},
'adUnitCode': 'div-gpt-ad-1460505748561-0',
'transactionId': 'trdiv-gpt-ad-1460505748561-0',
+ 'adUnitId': 'audiv-gpt-ad-1460505748561-0',
'sizes': [
[
300,
@@ -1080,35 +1090,6 @@ describe('Unit: Prebid Module', function () {
expect(slots[0].spySetTargeting.args).to.deep.contain.members(expected);
});
- it('should find correct gpt slot based on ad id rather than ad unit code when resizing secure creative', function () {
- var slots = [
- new Slot('div-not-matching-adunit-code-1', config.adUnitCodes[0]),
- new Slot('div-not-matching-adunit-code-2', config.adUnitCodes[0]),
- new Slot('div-not-matching-adunit-code-3', config.adUnitCodes[0])
- ];
-
- slots[1].setTargeting('hb_adid', ['someAdId']);
- slots[1].spyGetSlotElementId.resetHistory();
- window.googletag.pubads().setSlots(slots);
-
- const mockAdObject = {
- adId: 'someAdId',
- ad: '',
- adUrl: 'http://creative.prebid.org/${AUCTION_PRICE}',
- width: 300,
- height: 250,
- renderer: null,
- cpm: '1.00',
- adUnitCode: config.adUnitCodes[0],
- };
-
- _sendAdToCreative(mockAdObject, sinon.stub());
-
- expect(slots[0].spyGetSlotElementId.called).to.equal(false);
- expect(slots[1].spyGetSlotElementId.called).to.equal(true);
- expect(slots[2].spyGetSlotElementId.called).to.equal(false);
- });
-
it('Calling enableSendAllBids should set targeting to include standard keys with bidder' +
' append to key name', function () {
var slots = createSlotArray();
@@ -1230,9 +1211,14 @@ describe('Unit: Prebid Module', function () {
height: 0
}
},
+ body: {
+ appendChild: sinon.stub()
+ },
getElementsByTagName: sinon.stub(),
- querySelector: sinon.stub()
+ querySelector: sinon.stub(),
+ createElement: sinon.stub(),
};
+ doc.defaultView.document = doc;
elStub = {
insertBefore: sinon.stub()
@@ -1262,7 +1248,7 @@ describe('Unit: Prebid Module', function () {
it('should require doc and id params', function () {
$$PREBID_GLOBAL$$.renderAd();
- var error = 'Error trying to write ad Id :undefined to the page. Missing adId';
+ var error = 'Error rendering ad (id: undefined): missing adId';
assert.ok(spyLogError.calledWith(error), 'expected param error was logged');
});
@@ -1287,14 +1273,13 @@ describe('Unit: Prebid Module', function () {
adUrl: 'http://server.example.com/ad/ad.js'
});
$$PREBID_GLOBAL$$.renderAd(doc, bidId);
- assert.ok(elStub.insertBefore.called, 'url was written to iframe in doc');
+ sinon.assert.calledWith(doc.createElement, 'iframe');
});
it('should log an error when no ad or url', function () {
pushBidResponseToAuction({});
$$PREBID_GLOBAL$$.renderAd(doc, bidId);
- var error = 'Error trying to write ad. No ad for bid response id: ' + bidId;
- assert.ok(spyLogError.calledWith(error), 'expected error was logged');
+ sinon.assert.called(spyLogError);
});
it('should log an error when not in an iFrame', function () {
@@ -1303,7 +1288,7 @@ describe('Unit: Prebid Module', function () {
});
inIframe = false;
$$PREBID_GLOBAL$$.renderAd(document, bidId);
- const error = 'Error trying to write ad. Ad render call ad id ' + bidId + ' was prevented from writing to the main document.';
+ const error = `Error rendering ad (id: ${bidId}): renderAd was prevented from writing to the main document.`;
assert.ok(spyLogError.calledWith(error), 'expected error was logged');
});
@@ -1324,14 +1309,14 @@ describe('Unit: Prebid Module', function () {
doc.write = sinon.stub().throws(error);
$$PREBID_GLOBAL$$.renderAd(doc, bidId);
- var errorMessage = 'Error trying to write ad Id :' + bidId + ' to the page:' + error.message;
+ var errorMessage = `Error rendering ad (id: ${bidId}): doc write error`
assert.ok(spyLogError.calledWith(errorMessage), 'expected error was logged');
});
it('should log an error when ad not found', function () {
var fakeId = 99;
$$PREBID_GLOBAL$$.renderAd(doc, fakeId);
- var error = 'Error trying to write ad. Cannot find ad by given id : ' + fakeId;
+ var error = `Error rendering ad (id: ${fakeId}): Cannot find ad '${fakeId}'`
assert.ok(spyLogError.calledWith(error), 'expected error was logged');
});
@@ -1343,14 +1328,6 @@ describe('Unit: Prebid Module', function () {
assert.deepEqual($$PREBID_GLOBAL$$.getAllWinningBids()[0], adResponse);
});
- it('should replace ${CLICKTHROUGH} macro in winning bids response', function () {
- pushBidResponseToAuction({
- ad: ""
- });
- $$PREBID_GLOBAL$$.renderAd(doc, bidId, {clickThrough: 'https://someadserverclickurl.com'});
- expect(adResponse).to.have.property('ad').and.to.match(/https:\/\/someadserverclickurl\.com/i);
- });
-
it('fires billing url if present on s2s bid', function () {
const burl = 'http://www.example.com/burl';
pushBidResponseToAuction({
@@ -1538,6 +1515,7 @@ describe('Unit: Prebid Module', function () {
}
},
transactionId: 'mock-tid',
+ adUnitId: 'mock-au',
bids: [
{bidder: BIDDER_CODE, params: {placementId: 'id'}},
]
@@ -1612,6 +1590,7 @@ describe('Unit: Prebid Module', function () {
height: 250,
adUnitCode: bidRequests[0].bids[0].adUnitCode,
transactionId: 'mock-tid',
+ adUnitId: 'mock-au',
adserverTargeting: {
'hb_bidder': BIDDER_CODE,
'hb_adid': bidId,
@@ -1690,7 +1669,8 @@ describe('Unit: Prebid Module', function () {
const bid = {
bidder: 'mock-bidder',
adUnitCode: adUnits[0].code,
- transactionId: adUnits[0].transactionId
+ transactionId: adUnits[0].transactionId,
+ adUnitId: adUnits[0].adUnitId,
}
requestBids({
adUnits,
@@ -1976,6 +1956,102 @@ describe('Unit: Prebid Module', function () {
.and.to.match(/[a-f0-9\-]{36}/i);
});
+ it('should use the same transactionID for ad units with the same code', () => {
+ $$PREBID_GLOBAL$$.requestBids({
+ adUnits: [
+ {
+ code: 'twin',
+ mediaTypes: { banner: { sizes: [] } },
+ bids: []
+ }, {
+ code: 'twin',
+ mediaTypes: { banner: { sizes: [] } },
+ bids: []
+ }
+ ]
+ });
+ const tid = auctionArgs.adUnits[0].transactionId;
+ expect(tid).to.exist;
+ expect(auctionArgs.adUnits[1].transactionId).to.eql(tid);
+ });
+
+ it('should re-use pub-provided transaction ID for ad units with the same code', () => {
+ $$PREBID_GLOBAL$$.requestBids({
+ adUnits: [
+ {
+ code: 'twin',
+ mediaTypes: { banner: { sizes: [] } },
+ bids: [],
+ }, {
+ code: 'twin',
+ mediaTypes: { banner: { sizes: [] } },
+ bids: [],
+ ortb2Imp: {
+ ext: {
+ tid: 'pub-tid'
+ }
+ }
+ }
+ ]
+ });
+ expect(auctionArgs.adUnits.map(au => au.transactionId)).to.eql(['pub-tid', 'pub-tid']);
+ });
+
+ it('should use pub-provided TIDs when they conflict for ad units with the same code', () => {
+ $$PREBID_GLOBAL$$.requestBids({
+ adUnits: [
+ {
+ code: 'twin',
+ mediaTypes: { banner: { sizes: [] } },
+ bids: [],
+ ortb2Imp: {
+ ext: {
+ tid: 't1'
+ }
+ }
+ }, {
+ code: 'twin',
+ mediaTypes: { banner: { sizes: [] } },
+ bids: [],
+ ortb2Imp: {
+ ext: {
+ tid: 't2'
+ }
+ }
+ }
+ ]
+ });
+ expect(auctionArgs.adUnits.map(au => au.transactionId)).to.eql(['t1', 't2']);
+ });
+
+ it('should generate unique adUnitId', () => {
+ $$PREBID_GLOBAL$$.requestBids({
+ adUnits: [
+ {
+ code: 'single',
+ mediaTypes: { banner: { sizes: [] } },
+ bids: []
+ }, {
+ code: 'twin',
+ mediaTypes: { banner: { sizes: [] } },
+ bids: []
+ },
+ {
+ code: 'twin',
+ mediaTypes: { banner: { sizes: [] } },
+ bids: []
+ }
+ ]
+ });
+
+ const ids = new Set();
+ auctionArgs.adUnits.forEach(au => {
+ expect(au.adUnitId).to.exist;
+ ids.add(au.adUnitId);
+ });
+ expect(ids.size).to.eql(3);
+ });
+
describe('transactionId', () => {
let adUnit;
beforeEach(() => {
@@ -2734,6 +2810,13 @@ describe('Unit: Prebid Module', function () {
events.on.restore();
});
+ it('should emit event BID_ACCEPTED when invoked', function () {
+ var callback = sinon.spy();
+ $$PREBID_GLOBAL$$.onEvent('bidAccepted', callback);
+ events.emit(CONSTANTS.EVENTS.BID_ACCEPTED);
+ sinon.assert.calledOnce(callback);
+ });
+
describe('beforeRequestBids', function () {
let bidRequestedHandler;
let beforeRequestBidsHandler;
@@ -3302,16 +3385,20 @@ describe('Unit: Prebid Module', function () {
const highestBid = $$PREBID_GLOBAL$$.getHighestUnusedBidResponseForAdUnitCode('/19968336/header-bid-tag-0');
expect(highestBid).to.deep.equal(_bidsReceived[2])
})
- })
+ });
- describe('getHighestCpm', () => {
+ describe('getHighestCpmBids', () => {
after(() => {
resetAuction();
});
it('returns an array containing the highest bid object for the given adUnitCode', function () {
- const highestCpmBids = $$PREBID_GLOBAL$$.getHighestCpmBids('/19968336/header-bid-tag-0');
+ const adUnitcode = '/19968336/header-bid-tag-0';
+ targeting.setLatestAuctionForAdUnit(adUnitcode, auctionId)
+ const highestCpmBids = $$PREBID_GLOBAL$$.getHighestCpmBids(adUnitcode);
expect(highestCpmBids.length).to.equal(1);
- expect(highestCpmBids[0]).to.deep.equal(auctionManager.getBidsReceived()[1]);
+ const expectedBid = auctionManager.getBidsReceived()[1];
+ expectedBid.latestTargetedAuctionId = auctionId;
+ expect(highestCpmBids[0]).to.deep.equal(expectedBid);
});
it('returns an empty array when the given adUnit is not found', function () {
@@ -3541,7 +3628,7 @@ describe('Unit: Prebid Module', function () {
{
code: 'adUnit-code-1',
mediaTypes: { banner: { sizes: [[300, 250], [300, 600]] } },
- transactionId: '1234567890',
+ adUnitId: '1234567890',
bids: [
{ bidder: 'pubmatic', params: {placementId: '10433394'}, adUnitCode: 'adUnit-code-1' }
]
@@ -3550,15 +3637,15 @@ describe('Unit: Prebid Module', function () {
code: 'adUnit-code-2',
deferBilling: true,
mediaTypes: { banner: { sizes: [[300, 250], [300, 600]] } },
- transactionId: '0987654321',
+ adUnitId: '0987654321',
bids: [
{ bidder: 'pubmatic', params: {placementId: '10433394'}, adUnitCode: 'adUnit-code-2' }
]
}
];
- let winningBid1 = { adapterCode: 'pubmatic', bidder: 'pubmatic', params: {placementId: '10433394'}, adUnitCode: 'adUnit-code-1', transactionId: '1234567890', adId: 'abcdefg' }
- let winningBid2 = { adapterCode: 'pubmatic', bidder: 'pubmatic', params: {placementId: '10433394'}, adUnitCode: 'adUnit-code-2', transactionId: '0987654321' }
+ let winningBid1 = { adapterCode: 'pubmatic', bidder: 'pubmatic', params: {placementId: '10433394'}, adUnitCode: 'adUnit-code-1', adUnitId: '1234567890', adId: 'abcdefg' }
+ let winningBid2 = { adapterCode: 'pubmatic', bidder: 'pubmatic', params: {placementId: '10433394'}, adUnitCode: 'adUnit-code-2', adUnitId: '0987654321' }
let adUnitCodes = ['adUnit-code-1', 'adUnit-code-2'];
let auction = auctionModule.newAuction({adUnits, adUnitCodes, callback: function() {}, cbTimeout: 2000});
diff --git a/test/spec/unit/secureCreatives_spec.js b/test/spec/unit/secureCreatives_spec.js
index 7d5f9af35dd..a7be4e327f0 100644
--- a/test/spec/unit/secureCreatives_spec.js
+++ b/test/spec/unit/secureCreatives_spec.js
@@ -1,6 +1,4 @@
-import {
- _sendAdToCreative, getReplier, receiveMessage
-} from 'src/secureCreatives.js';
+import {getReplier, receiveMessage, resizeRemoteCreative} from 'src/secureCreatives.js';
import * as utils from 'src/utils.js';
import {getAdUnits, getBidRequests, getBidResponses} from 'test/fixtures/fixtures.js';
import {auctionManager} from 'src/auctionManager.js';
@@ -8,14 +6,26 @@ import * as auctionModule from 'src/auction.js';
import * as native from 'src/native.js';
import {fireNativeTrackers, getAllAssetsMessage} from 'src/native.js';
import * as events from 'src/events.js';
-import { config as configObj } from 'src/config.js';
+import {config as configObj} from 'src/config.js';
+import * as creativeRenderers from 'src/creativeRenderers.js';
import 'src/prebid.js';
+import 'modules/nativeRendering.js';
-import { expect } from 'chai';
+import {expect} from 'chai';
var CONSTANTS = require('src/constants.json');
describe('secureCreatives', () => {
+ let sandbox;
+
+ beforeEach(() => {
+ sandbox = sinon.sandbox.create();
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
function makeEvent(ev) {
return Object.assign({origin: 'mock-origin', ports: []}, ev)
}
@@ -54,40 +64,6 @@ describe('secureCreatives', () => {
});
});
- describe('_sendAdToCreative', () => {
- beforeEach(function () {
- sinon.stub(utils, 'logError');
- sinon.stub(utils, 'logWarn');
- });
-
- afterEach(function () {
- utils.logError.restore();
- utils.logWarn.restore();
- });
- it('should macro replace ${AUCTION_PRICE} with the winning bid for ad and adUrl', () => {
- const oldVal = window.googletag;
- const oldapntag = window.apntag;
- window.apntag = null
- window.googletag = null;
- const mockAdObject = {
- adId: 'someAdId',
- ad: '',
- adUrl: 'http://creative.prebid.org/${AUCTION_PRICE}',
- width: 300,
- height: 250,
- renderer: null,
- cpm: '1.00',
- adUnitCode: 'some_dom_id'
- };
- const reply = sinon.spy();
- _sendAdToCreative(mockAdObject, reply);
- expect(reply.args[0][0].ad).to.equal('');
- expect(reply.args[0][0].adUrl).to.equal('http://creative.prebid.org/1.00');
- window.googletag = oldVal;
- window.apntag = oldapntag;
- });
- });
-
describe('receiveMessage', function() {
const bidId = 1;
const warning = `Ad id ${bidId} has been rendered before`;
@@ -149,19 +125,15 @@ describe('secureCreatives', () => {
});
beforeEach(function() {
- spyAddWinningBid = sinon.spy(auctionManager, 'addWinningBid');
- spyLogWarn = sinon.spy(utils, 'logWarn');
- stubFireNativeTrackers = sinon.stub(native, 'fireNativeTrackers').callsFake(message => { return message.action; });
- stubGetAllAssetsMessage = sinon.stub(native, 'getAllAssetsMessage');
- stubEmit = sinon.stub(events, 'emit');
+ spyAddWinningBid = sandbox.spy(auctionManager, 'addWinningBid');
+ spyLogWarn = sandbox.spy(utils, 'logWarn');
+ stubFireNativeTrackers = sandbox.stub(native, 'fireNativeTrackers').callsFake(message => { return message.action; });
+ stubGetAllAssetsMessage = sandbox.stub(native, 'getAllAssetsMessage');
+ stubEmit = sandbox.stub(events, 'emit');
});
afterEach(function() {
- spyAddWinningBid.restore();
- spyLogWarn.restore();
- stubFireNativeTrackers.restore();
- stubGetAllAssetsMessage.restore();
- stubEmit.restore();
+ sandbox.restore();
resetAuction();
adResponse.adId = bidId;
});
@@ -305,6 +277,66 @@ describe('secureCreatives', () => {
adId: bidId
}));
});
+
+ it('should include renderers in responses', () => {
+ sandbox.stub(creativeRenderers, 'getCreativeRendererSource').returns('mock-renderer');
+ pushBidResponseToAuction({});
+ const ev = makeEvent({
+ source: {
+ postMessage: sinon.stub()
+ },
+ data: JSON.stringify({adId: bidId, message: 'Prebid Request'})
+ });
+ receiveMessage(ev);
+ sinon.assert.calledWith(ev.source.postMessage, sinon.match(ob => JSON.parse(ob).renderer === 'mock-renderer'));
+ });
+
+ if (FEATURES.NATIVE) {
+ it('should include native rendering data in responses', () => {
+ const bid = {
+ native: {
+ ortb: {
+ assets: [
+ {
+ id: 1,
+ data: {
+ type: 2,
+ value: 'vbody'
+ }
+ }
+ ]
+ },
+ body: 'vbody',
+ adTemplate: 'tpl',
+ rendererUrl: 'rurl'
+ }
+ }
+ pushBidResponseToAuction(bid);
+ const ev = makeEvent({
+ source: {
+ postMessage: sinon.stub()
+ },
+ data: JSON.stringify({adId: bidId, message: 'Prebid Request'})
+ })
+ receiveMessage(ev);
+ sinon.assert.calledWith(ev.source.postMessage, sinon.match(ob => {
+ const data = JSON.parse(ob);
+ ['width', 'height'].forEach(prop => expect(data[prop]).to.not.exist);
+ const native = data.native;
+ sinon.assert.match(native, {
+ ortb: bid.native.ortb,
+ adTemplate: bid.native.adTemplate,
+ rendererUrl: bid.native.rendererUrl,
+ })
+ expect(Object.fromEntries(native.assets.map(({key, value}) => [key, value]))).to.eql({
+ adTemplate: bid.native.adTemplate,
+ rendererUrl: bid.native.rendererUrl,
+ body: 'vbody'
+ });
+ return true;
+ }))
+ })
+ }
});
describe('Prebid Native', function() {
@@ -365,45 +397,6 @@ describe('secureCreatives', () => {
receiveMessage(ev);
stubEmit.withArgs(CONSTANTS.EVENTS.BID_WON, adResponse).calledOnce;
});
-
- it('Prebid native should fire trackers', function () {
- let adId = 2;
- pushBidResponseToAuction({adId});
-
- const data = {
- adId: adId,
- message: 'Prebid Native',
- action: 'click',
- };
-
- const ev = makeEvent({
- data: JSON.stringify(data),
- source: {
- postMessage: sinon.stub()
- },
- origin: 'any origin'
- });
-
- receiveMessage(ev);
-
- sinon.assert.neverCalledWith(spyLogWarn, warning);
- sinon.assert.calledOnce(stubFireNativeTrackers);
- sinon.assert.calledWith(stubEmit, CONSTANTS.EVENTS.BID_WON, adResponse);
- sinon.assert.calledOnce(spyAddWinningBid);
-
- resetHistories(ev.source.postMessage);
-
- delete data.action;
- ev.data = JSON.stringify(data);
- receiveMessage(ev);
-
- sinon.assert.neverCalledWith(spyLogWarn, warning);
- sinon.assert.calledOnce(stubFireNativeTrackers);
- sinon.assert.neverCalledWith(stubEmit, CONSTANTS.EVENTS.BID_WON);
- sinon.assert.notCalled(spyAddWinningBid);
-
- expect(adResponse).to.have.property('status', CONSTANTS.BID_STATUS.RENDERED);
- });
});
describe('Prebid Event', () => {
@@ -457,4 +450,53 @@ describe('secureCreatives', () => {
});
});
});
+
+ describe('resizeRemoteCreative', () => {
+ let origGpt;
+ before(() => {
+ origGpt = window.googletag;
+ });
+ after(() => {
+ window.googletag = origGpt;
+ });
+ function mockSlot(elementId, pathId) {
+ let targeting = {};
+ return {
+ getSlotElementId: sinon.stub().callsFake(() => elementId),
+ getAdUnitPath: sinon.stub().callsFake(() => pathId),
+ setTargeting: sinon.stub().callsFake((key, value) => {
+ value = Array.isArray(value) ? value : [value];
+ targeting[key] = value;
+ }),
+ getTargetingKeys: sinon.stub().callsFake(() => Object.keys(targeting)),
+ getTargeting: sinon.stub().callsFake((key) => targeting[key] || [])
+ }
+ }
+ let slots;
+ beforeEach(() => {
+ slots = [
+ mockSlot('div1', 'au1'),
+ mockSlot('div2', 'au2'),
+ mockSlot('div3', 'au3')
+ ]
+ window.googletag = {
+ pubads: sinon.stub().returns({
+ getSlots: sinon.stub().returns(slots)
+ })
+ };
+ sandbox.stub(document, 'getElementById');
+ })
+
+ it('should find correct gpt slot based on ad id rather than ad unit code when resizing secure creative', function () {
+ slots[1].setTargeting('hb_adid', ['adId']);
+ resizeRemoteCreative({
+ adId: 'adId',
+ width: 300,
+ height: 250,
+ });
+ [0, 2].forEach((i) => sinon.assert.notCalled(slots[i].getSlotElementId))
+ sinon.assert.called(slots[1].getSlotElementId);
+ sinon.assert.calledWith(document.getElementById, 'div2');
+ });
+ })
});
diff --git a/test/spec/unit/utils/ttlCollection_spec.js b/test/spec/unit/utils/ttlCollection_spec.js
index 29c6c438855..76cfa32d955 100644
--- a/test/spec/unit/utils/ttlCollection_spec.js
+++ b/test/spec/unit/utils/ttlCollection_spec.js
@@ -67,6 +67,33 @@ describe('ttlCollection', () => {
});
});
+ it('should run onExpiry when items are cleared', () => {
+ const i1 = {ttl: 1000, some: 'data'};
+ const i2 = {ttl: 2000, some: 'data'};
+ coll.add(i1);
+ coll.add(i2);
+ const cb = sinon.stub();
+ coll.onExpiry(cb);
+ return waitForPromises().then(() => {
+ clock.tick(500);
+ sinon.assert.notCalled(cb);
+ clock.tick(SLACK + 500);
+ sinon.assert.calledWith(cb, i1);
+ clock.tick(3000);
+ sinon.assert.calledWith(cb, i2);
+ })
+ });
+
+ it('should allow unregistration of onExpiry callbacks', () => {
+ const cb = sinon.stub();
+ coll.add({ttl: 500});
+ coll.onExpiry(cb)();
+ return waitForPromises().then(() => {
+ clock.tick(500 + SLACK);
+ sinon.assert.notCalled(cb);
+ })
+ })
+
it('should not wait too long if a shorter ttl shows up', () => {
coll.add({ttl: 4000});
coll.add({ttl: 1000});
diff --git a/test/spec/utils_spec.js b/test/spec/utils_spec.js
index 098582c0af6..c84fe124db6 100644
--- a/test/spec/utils_spec.js
+++ b/test/spec/utils_spec.js
@@ -1002,6 +1002,15 @@ describe('Utils', function () {
const obj = {key: 'value'};
expect(deepEqual({outer: obj}, {outer: new Typed(obj)}, {checkTypes: true})).to.be.false;
});
+ it('should work when adding properties to the prototype of Array', () => {
+ after(function () {
+ // eslint-disable-next-line no-extend-native
+ delete Array.prototype.unitTestTempProp;
+ });
+ // eslint-disable-next-line no-extend-native
+ Array.prototype.unitTestTempProp = 'testing';
+ expect(deepEqual([], [])).to.be.true;
+ });
describe('cyrb53Hash', function() {
it('should return the same hash for the same string', function() {
diff --git a/test/spec/videoCache_spec.js b/test/spec/videoCache_spec.js
index c746fdd2afd..fc6e71779cb 100644
--- a/test/spec/videoCache_spec.js
+++ b/test/spec/videoCache_spec.js
@@ -1,10 +1,10 @@
import chai from 'chai';
-import { getCacheUrl, store } from 'src/videoCache.js';
-import { config } from 'src/config.js';
-import { server } from 'test/mocks/xhr.js';
+import {getCacheUrl, store} from 'src/videoCache.js';
+import {config} from 'src/config.js';
+import {server} from 'test/mocks/xhr.js';
import {auctionManager} from '../../src/auctionManager.js';
import {AuctionIndex} from '../../src/auctionIndex.js';
-import { batchingCache } from '../../src/auction.js';
+import {batchingCache} from '../../src/auction.js';
const should = chai.should();
@@ -127,7 +127,7 @@ describe('The video cache', function () {
prebid.org wrapper
-
+
@@ -149,6 +149,20 @@ describe('The video cache', function () {
assertRequestMade({ vastUrl: 'my-mock-url.com', vastImpUrl: 'imptracker.com', ttl: 25 }, expectedValue)
});
+ it('should include multiple vastImpUrl when it\'s an array', function() {
+ const expectedValue = `
+
+
+ prebid.org wrapper
+
+
+
+
+
+ `;
+ assertRequestMade({ vastUrl: 'my-mock-url.com', vastImpUrl: ['https://vasttracking.mydomain.com/vast?cpm=1.2', 'imptracker.com'], ttl: 25, cpm: 1.2 }, expectedValue)
+ });
+
it('should make the expected request when store() is called on an ad with vastXml', function () {
const vastXml = ' ';
assertRequestMade({ vastXml: vastXml, ttl: 25 }, vastXml);
diff --git a/test/spec/video_spec.js b/test/spec/video_spec.js
index 35d0a4fef24..3252c58c687 100644
--- a/test/spec/video_spec.js
+++ b/test/spec/video_spec.js
@@ -82,10 +82,10 @@ describe('video.js', function () {
const bid = {
adId: '456xyz',
vastUrl: 'http://www.example.com/vastUrl',
- transactionId: 'au'
+ adUnitId: 'au'
};
const adUnits = [{
- transactionId: 'au',
+ adUnitId: 'au',
mediaTypes: {
video: {context: 'instream'}
}
@@ -96,10 +96,10 @@ describe('video.js', function () {
it('catches invalid instream bids', function () {
const bid = {
- transactionId: 'au'
+ adUnitId: 'au'
};
const adUnits = [{
- transactionId: 'au',
+ adUnitId: 'au',
mediaTypes: {
video: {context: 'instream'}
}
@@ -110,26 +110,26 @@ describe('video.js', function () {
it('catches invalid bids when prebid-cache is disabled', function () {
const adUnits = [{
- transactionId: 'au',
+ adUnitId: 'au',
bidder: 'vastOnlyVideoBidder',
mediaTypes: {video: {}},
}];
- const valid = isValidVideoBid({ transactionId: 'au', vastXml: 'vast ' }, {index: stubAuctionIndex({adUnits})});
+ const valid = isValidVideoBid({ adUnitId: 'au', vastXml: 'vast ' }, {index: stubAuctionIndex({adUnits})});
expect(valid).to.equal(false);
});
it('validates valid outstream bids', function () {
const bid = {
- transactionId: 'au',
+ adUnitId: 'au',
renderer: {
url: 'render.url',
render: () => true,
}
};
const adUnits = [{
- transactionId: 'au',
+ adUnitId: 'au',
mediaTypes: {
video: {context: 'outstream'}
}
@@ -140,10 +140,10 @@ describe('video.js', function () {
it('validates valid outstream bids with a publisher defined renderer', function () {
const bid = {
- transactionId: 'au',
+ adUnitId: 'au',
};
const adUnits = [{
- transactionId: 'au',
+ adUnitId: 'au',
mediaTypes: {
video: {
context: 'outstream',
@@ -160,10 +160,10 @@ describe('video.js', function () {
it('catches invalid outstream bids', function () {
const bid = {
- transactionId: 'au',
+ adUnitId: 'au',
};
const adUnits = [{
- transactionId: 'au',
+ adUnitId: 'au',
mediaTypes: {
video: {context: 'outstream'}
}
diff --git a/test/test_deps.js b/test/test_deps.js
index 35713106f8c..c8a3bcc9426 100644
--- a/test/test_deps.js
+++ b/test/test_deps.js
@@ -4,6 +4,16 @@ window.process = {
}
};
+window.addEventListener('error', function (ev) {
+ // eslint-disable-next-line no-console
+ console.error('Uncaught exception:', ev.error, ev.error?.stack);
+})
+
+window.addEventListener('unhandledrejection', function (ev) {
+ // eslint-disable-next-line no-console
+ console.error('Unhandled rejection:', ev.reason);
+})
+
require('test/helpers/consentData.js');
require('test/helpers/prebidGlobal.js');
require('test/mocks/adloaderStub.js');
diff --git a/wdio.conf.js b/wdio.conf.js
index 3d93f909971..d23fecd0b15 100644
--- a/wdio.conf.js
+++ b/wdio.conf.js
@@ -1,3 +1,5 @@
+const shared = require('./wdio.shared.conf.js');
+
const browsers = Object.fromEntries(
Object.entries(require('./browsers.json'))
.filter(([k, v]) => {
@@ -35,14 +37,7 @@ function getCapabilities() {
}
exports.config = {
- specs: [
- './test/spec/e2e/**/*.spec.js',
- ],
- exclude: [
- // TODO: decipher original intent for "longform" tests
- // they all appear to be almost exact copies
- './test/spec/e2e/longform/**/*'
- ],
+ ...shared.config,
services: [
['browserstack', {
browserstackLocal: true
@@ -53,17 +48,4 @@ exports.config = {
maxInstances: 5, // Do not increase this, since we have only 5 parallel tests in browserstack account
maxInstancesPerCapability: 1,
capabilities: getCapabilities(),
- logLevel: 'info', // put option here: info | trace | debug | warn| error | silent
- bail: 0,
- waitforTimeout: 60000, // Default timeout for all waitFor* commands.
- connectionRetryTimeout: 60000, // Default timeout in milliseconds for request if Selenium Grid doesn't send response
- connectionRetryCount: 3, // Default request retries count
- framework: 'mocha',
- mochaOpts: {
- ui: 'bdd',
- timeout: 60000,
- compilers: ['js:babel-register'],
- },
- // if you see error, update this to spec reporter and logLevel above to get detailed report.
- reporters: ['spec']
}
diff --git a/wdio.local.conf.js b/wdio.local.conf.js
new file mode 100644
index 00000000000..772448472bf
--- /dev/null
+++ b/wdio.local.conf.js
@@ -0,0 +1,13 @@
+const shared = require('./wdio.shared.conf.js');
+
+exports.config = {
+ ...shared.config,
+ capabilities: [
+ {
+ browserName: 'chrome',
+ 'goog:chromeOptions': {
+ args: ['headless', 'disable-gpu'],
+ },
+ },
+ ],
+};
diff --git a/wdio.shared.conf.js b/wdio.shared.conf.js
new file mode 100644
index 00000000000..34e1ee9c675
--- /dev/null
+++ b/wdio.shared.conf.js
@@ -0,0 +1,23 @@
+exports.config = {
+ specs: [
+ './test/spec/e2e/**/*.spec.js',
+ ],
+ exclude: [
+ // TODO: decipher original intent for "longform" tests
+ // they all appear to be almost exact copies
+ './test/spec/e2e/longform/**/*'
+ ],
+ logLevel: 'info', // put option here: info | trace | debug | warn| error | silent
+ bail: 0,
+ waitforTimeout: 60000, // Default timeout for all waitFor* commands.
+ connectionRetryTimeout: 60000, // Default timeout in milliseconds for request if Selenium Grid doesn't send response
+ connectionRetryCount: 3, // Default request retries count
+ framework: 'mocha',
+ mochaOpts: {
+ ui: 'bdd',
+ timeout: 60000,
+ compilers: ['js:babel-register'],
+ },
+ // if you see error, update this to spec reporter and logLevel above to get detailed report.
+ reporters: ['spec']
+}
diff --git a/webpack.conf.js b/webpack.conf.js
index 0ead550e446..c934b09d439 100644
--- a/webpack.conf.js
+++ b/webpack.conf.js
@@ -128,10 +128,37 @@ module.exports = {
return [lib, def];
})
);
+ const core = path.resolve('./src');
+ const paapiMod = path.resolve('./modules/paapi.js');
+ const nodeModules = path.resolve('./node_modules');
+
return Object.assign(libraries, {
+ common_deps: {
+ name: 'common_deps',
+ test(module) {
+ return module.resource && module.resource.startsWith(nodeModules);
+ }
+ },
+ core: {
+ name: 'chunk-core',
+ test: (module) => {
+ return module.resource && module.resource.startsWith(core);
+ }
+ },
+ paapi: {
+ // fledgeForGpt imports paapi to keep backwards compat for NPM consumers
+ // this makes the paapi module its own chunk, pulled in by both paapi and fledgeForGpt entry points,
+ // to avoid duplication
+ // TODO: remove this in prebid 9
+ name: 'chunk-paapi',
+ test: (module) => {
+ return module.resource === paapiMod;
+ }
+ }
+ }, {
default: false,
defaultVendors: false
- })
+ });
})()
}
},
diff --git a/webpack.creative.js b/webpack.creative.js
new file mode 100644
index 00000000000..86f5f24d580
--- /dev/null
+++ b/webpack.creative.js
@@ -0,0 +1,25 @@
+const path = require('path');
+
+module.exports = {
+ mode: 'production',
+ resolve: {
+ modules: [
+ path.resolve('.'),
+ 'node_modules'
+ ],
+ },
+ entry: {
+ 'creative': {
+ import: './creative/crossDomain.js',
+ },
+ 'renderers/display': {
+ import: './creative/renderers/display/renderer.js'
+ },
+ 'renderers/native': {
+ import: './creative/renderers/native/renderer.js'
+ }
+ },
+ output: {
+ path: path.resolve('./build/creative'),
+ },
+}