Skip to content
32 changes: 3 additions & 29 deletions modules/openxBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,37 +162,11 @@ function isBidRequestValid(bidRequest) {
}

function buildRequests(bidRequests, bidderRequest) {
const videoRequests = bidRequests.filter(bidRequest => isVideoBidRequest(bidRequest));
const bannerAndNativeRequests = bidRequests.filter(bidRequest => isBannerBidRequest(bidRequest) || isNativeBidRequest(bidRequest))
// In case of multi-format bids remove `video` from mediaTypes as for video a separate bid request is built
.map(bid => ({ ...bid, mediaTypes: { ...bid.mediaTypes, video: undefined } }));

const requests = bannerAndNativeRequests.length ? [createRequest(bannerAndNativeRequests, bidderRequest, null)] : [];
videoRequests.forEach(bid => {
requests.push(createRequest([bid], bidderRequest, VIDEO));
});
return requests;
}

function createRequest(bidRequests, bidderRequest, mediaType) {
return {
return [{
method: 'POST',
url: config.getConfig('openxOrtbUrl') || REQUEST_URL,
data: converter.toORTB({ bidRequests, bidderRequest, context: { mediaType } })
}
}

function isVideoBidRequest(bidRequest) {
return utils.deepAccess(bidRequest, 'mediaTypes.video');
}

function isNativeBidRequest(bidRequest) {
return utils.deepAccess(bidRequest, 'mediaTypes.native');
}

function isBannerBidRequest(bidRequest) {
const isNotVideoOrNativeBid = !isVideoBidRequest(bidRequest) && !isNativeBidRequest(bidRequest)
return utils.deepAccess(bidRequest, 'mediaTypes.banner') || isNotVideoOrNativeBid;
data: converter.toORTB({ bidRequests, bidderRequest })
}];
}

function interpretResponse(resp, req) {
Expand Down
136 changes: 106 additions & 30 deletions test/spec/modules/openxBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -416,16 +416,12 @@ describe('OpenxRtbAdapter', function () {
playerSize: [640, 480]
};
const requests = spec.buildRequests([multiformat], mockBidderRequest);
expect(requests).to.have.length(2);
expect(requests).to.have.length(1);
expect(requests[0].data.imp).to.have.length(1);
expect(requests[0].data.imp[0].banner).to.exist;
expect(requests[0].data.imp[0].video).to.not.exist;
expect(requests[0].data.imp[0].native).to.not.exist;
expect(requests[1].data.imp).to.have.length(1);
expect(requests[1].data.imp[0].banner).to.not.exist;
expect(requests[1].data.imp[0].native).to.not.exist;
if (FEATURES.VIDEO) {
expect(requests[1].data.imp[0].video).to.exist;
expect(requests[0].data.imp[0].video).to.exist;
}
})

Expand Down Expand Up @@ -454,21 +450,38 @@ describe('OpenxRtbAdapter', function () {
sizes: [[300, 250]]
}
const requests = spec.buildRequests([multiformat], mockBidderRequest);
expect(requests).to.have.length(2);
expect(requests).to.have.length(1);
expect(requests[0].data.imp).to.have.length(1);
expect(requests[0].data.imp[0].banner).to.exist;
expect(requests[0].data.imp[0].video).to.not.exist;
if (FEATURES.NATIVE) {
expect(requests[0].data.imp[0].native).to.exist;
}
expect(requests[1].data.imp).to.have.length(1);
expect(requests[1].data.imp[0].banner).to.not.exist;
expect(requests[1].data.imp[0].native).to.not.exist;
if (FEATURES.VIDEO) {
expect(requests[1].data.imp[0].video).to.exist;
expect(requests[0].data.imp[0].video).to.exist;
}
})

it('should send banner, video and native bids in a single HTTP request', function () {
const allBids = [...bidRequestsWithMediaTypes, nativeBidRequest];
const request = spec.buildRequests(allBids, mockBidderRequest);

expect(request).to.have.length(1);
expect(request[0].data.imp).to.have.length(3);

const bannerImp = request[0].data.imp.find(imp => imp.id === bidRequestsWithMediaTypes[0].bidId);
expect(bannerImp.banner).to.exist;

if (FEATURES.VIDEO) {
const videoImp = request[0].data.imp.find(imp => imp.id === bidRequestsWithMediaTypes[1].bidId);
expect(videoImp.video).to.exist;
}

if (FEATURES.NATIVE) {
const nativeImp = request[0].data.imp.find(imp => imp.id === nativeBidRequest.bidId);
expect(nativeImp.native).to.exist;
}
});

it('should send bid request to openx url via POST', function () {
const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
expect(request[0].url).to.equal(REQUEST_URL);
Expand All @@ -482,19 +495,26 @@ describe('OpenxRtbAdapter', function () {
expect(request[0].data.ext.platformId).to.be.undefined;
});

it('should send platform id, if available', function () {
it('should send platform id from first bid, if available', function () {
bidRequestsWithMediaTypes[0].params.platform = '1cabba9e-cafe-3665-beef-f00f00f00f00';
bidRequestsWithMediaTypes[1].params.platform = '51ca3159-abc2-4035-8e00-fe26eaa09397';

const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
expect(request.length).to.equal(1);
expect(request[0].data.ext.platform).to.equal(bidRequestsWithMediaTypes[0].params.platform);
expect(request[1].data.ext.platform).to.equal(bidRequestsWithMediaTypes[1].params.platform);
});

it('should send delDomain from first bid when bids have different delDomains', function () {
bidRequestsWithMediaTypes[0].params.delDomain = 'domain-a.test';
bidRequestsWithMediaTypes[1].params.delDomain = 'domain-b.test';
const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
expect(request[0].data.ext.delDomain).to.equal('domain-a.test');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[question] Now bids with different delDomains into one request and only first bid's delDomain is sent and others are dropped?

});

it('should send openx adunit codes', function () {
const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
expect(request[0].data.imp[0].tagid).to.equal(bidRequestsWithMediaTypes[0].params.unit);
expect(request[1].data.imp[0].tagid).to.equal(bidRequestsWithMediaTypes[1].params.unit);
expect(request[0].data.imp[1].tagid).to.equal(bidRequestsWithMediaTypes[1].params.unit);
});

it('should send out custom params on bids that have customParams specified', function () {
Expand Down Expand Up @@ -563,7 +583,7 @@ describe('OpenxRtbAdapter', function () {
expect(request[0].data.imp[0].bidfloorcur).to.equal('USD');
});

it('should send not send floors', function () {
it('should not send floors', function () {
adServerCurrencyStub.returns('EUR');
const bidRequest = Object.assign({},
bidRequestsWithMediaTypes[0],
Expand Down Expand Up @@ -906,7 +926,6 @@ describe('OpenxRtbAdapter', function () {
it('should send a signal to specify that US Privacy applies to this request', async function () {
const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest));
expect(request[0].data.regs.ext.us_privacy).to.equal('1YYN');
expect(request[1].data.regs.ext.us_privacy).to.equal('1YYN');
});

it('should not send the regs object, when consent string is undefined', async function () {
Expand Down Expand Up @@ -948,29 +967,25 @@ describe('OpenxRtbAdapter', function () {
bidderRequest.bids = bidRequests;
const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest));
expect(request[0].data.regs.ext.gdpr).to.equal(1);
expect(request[1].data.regs.ext.gdpr).to.equal(1);
});

it('should send the consent string', async function () {
bidderRequest.bids = bidRequests;
const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest));
expect(request[0].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
expect(request[1].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
});

it('should send the addtlConsent string', async function () {
bidderRequest.bids = bidRequests;
const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest));
expect(request[0].data.user.ext.ConsentedProvidersSettings.consented_providers).to.equal(bidderRequest.gdprConsent.addtlConsent);
expect(request[1].data.user.ext.ConsentedProvidersSettings.consented_providers).to.equal(bidderRequest.gdprConsent.addtlConsent);
});

it('should send a signal to specify that GDPR does not apply to this request', async function () {
bidderRequest.gdprConsent.gdprApplies = false;
bidderRequest.bids = bidRequests;
const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest));
expect(request[0].data.regs.ext.gdpr).to.equal(0);
expect(request[1].data.regs.ext.gdpr).to.equal(0);
});

it('when GDPR application is undefined, should not send a signal to specify whether GDPR applies to this request, ' +
Expand All @@ -980,15 +995,14 @@ describe('OpenxRtbAdapter', function () {
const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest));
expect(request[0].data.regs?.ext?.gdpr).to.not.be.ok;
expect(request[0].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
expect(request[1].data.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString);
});

it('when consent string is undefined, should not send the consent string, ', async function () {
delete bidderRequest.gdprConsent.consentString;
bidderRequest.bids = bidRequests;
const request = spec.buildRequests(bidRequests, await addFPDToBidderRequest(bidderRequest));
expect(request[0].data.imp[0].ext.consent).to.equal(undefined);
expect(request[1].data.imp[0].ext.consent).to.equal(undefined);
expect(request[0].data.imp[1].ext.consent).to.equal(undefined);
});
});

Expand All @@ -1004,8 +1018,6 @@ describe('OpenxRtbAdapter', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.regs.gpp).to.equal('test-gpp-string');
expect(request[0].data.regs.gpp_sid).to.deep.equal([6]);
expect(request[1].data.regs.gpp).to.equal('test-gpp-string');
expect(request[1].data.regs.gpp_sid).to.deep.equal([6]);
});

it('should not send GPP string and GPP section IDs in bid request when not available', async function () {
Expand All @@ -1016,8 +1028,6 @@ describe('OpenxRtbAdapter', function () {
const request = spec.buildRequests(bidRequests, bidderRequest);
expect(request[0].data.regs.gpp).to.not.exist;
expect(request[0].data.regs.gpp_sid).to.not.exist;
expect(request[1].data.regs.gpp).to.not.exist;
expect(request[1].data.regs.gpp_sid).to.not.exist;
});
});
});
Expand Down Expand Up @@ -1255,7 +1265,7 @@ describe('OpenxRtbAdapter', function () {
context('video', function () {
it('should send bid request with a mediaTypes specified with video type', function () {
const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest);
expect(request[1].data.imp[0]).to.have.any.keys(VIDEO);
expect(request[0].data.imp[1]).to.have.any.keys(VIDEO);
});

it('Update imp.video with OpenRTB options from mimeTypes and params', function() {
Expand Down Expand Up @@ -1292,8 +1302,8 @@ describe('OpenxRtbAdapter', function () {
h: 250
};
const requests = spec.buildRequests([bid01], bidderRequest);
expect(requests).to.have.lengthOf(2);
expect(requests[1].data.imp[0].video).to.deep.equal(expected);
expect(requests).to.have.lengthOf(1);
expect(requests[0].data.imp[0].video).to.deep.equal(expected);
});
});
}
Expand Down Expand Up @@ -1577,6 +1587,7 @@ describe('OpenxRtbAdapter', function () {
crid: 'test-creative-id',
dealid: 'test-deal-id',
adm: '<VAST version="4.0"><Ad></Ad></VAST>',
mtype: 2,
}]
}],
cur: 'AUS'
Expand Down Expand Up @@ -1697,6 +1708,71 @@ describe('OpenxRtbAdapter', function () {
});
}

context('when multiple bid requests (banner + video) are in one request and both bids are returned', function() {
it('should correctly return both banner and video bids', function () {
const bidRequestConfigs = [
{
bidder: 'openx',
params: {
unit: '1',
delDomain: 'test-del-domain'
},
adUnitCode: 'au-1',
mediaTypes: {
banner: {
sizes: [[300, 250]]
}
},
bidId: 'bid-id-banner',
bidderRequestId: 'br-1',
auctionId: 'a-1'
},
{
bidder: 'openx',
params: {
unit: '2',
delDomain: 'test-del-domain'
},
adUnitCode: 'au-2',
mediaTypes: {
video: {
playerSize: [640, 480]
}
},
bidId: 'bid-id-video',
bidderRequestId: 'br-1',
auctionId: 'a-1'
}
];
const bidRequest = spec.buildRequests(bidRequestConfigs, { refererInfo: {} })[0];
const bidResponse = {
seatbid: [{
bid: [
{
impid: 'bid-id-banner',
price: 1,
adm: '<div>ad</div>',
mtype: 1
},
{
impid: 'bid-id-video',
price: 2,
adm: '<VAST/>',
mtype: 2
}
]
}],
cur: 'USD'
};
const result = spec.interpretResponse({ body: bidResponse }, bidRequest);
expect(result.bids).to.have.length(2);
expect(result.bids[0].mediaType).to.equal(BANNER);
expect(result.bids[1].mediaType).to.equal(VIDEO);
expect(result.bids[0].requestId).to.equal('bid-id-banner');
expect(result.bids[1].requestId).to.equal('bid-id-video');
});
});

if (FEATURES.NATIVE) {
context('when native request and the response is a native', function() {
beforeEach(function () {
Expand Down
Loading