Skip to content

Commit

Permalink
Rubicon Bid Adapter: add outstream rendering (prebid#6469)
Browse files Browse the repository at this point in the history
* Magnite renderer support for Oustream ads

* add functions for hiding ad units

* Add unit tests

* adding open source location of renderer

* better minification

Co-authored-by: bretg <bgorsline@gmail.com>
  • Loading branch information
2 people authored and stsepelin committed May 28, 2021
1 parent 7260125 commit 6c41930
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 0 deletions.
66 changes: 66 additions & 0 deletions modules/rubiconBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import {registerBidder} from '../src/adapters/bidderFactory.js';
import {config} from '../src/config.js';
import {BANNER, VIDEO} from '../src/mediaTypes.js';
import find from 'core-js-pure/features/array/find.js';
import { Renderer } from '../src/Renderer.js';
import { getGlobal } from '../src/prebidGlobal.js';

const DEFAULT_INTEGRATION = 'pbjs_lite';
const DEFAULT_PBS_INTEGRATION = 'pbjs';
const DEFAULT_RENDERER_URL = 'https://video-outstream.rubiconproject.com/apex-2.0.0.js';
// renderer code at https://github.com/rubicon-project/apex2

let rubiConf = {};
// we are saving these as global to this module so that if a pub accidentally overwrites the entire
Expand Down Expand Up @@ -651,6 +654,11 @@ export const spec = {
if (bid.adm) { bidObject.vastXml = bid.adm; }
if (bid.nurl) { bidObject.vastUrl = bid.nurl; }
if (!bidObject.vastUrl && bid.nurl) { bidObject.vastUrl = bid.nurl; }

const videoContext = utils.deepAccess(bidRequest, 'mediaTypes.video.context');
if (videoContext.toLowerCase() === 'outstream') {
bidObject.renderer = outstreamRenderer(bidObject);
}
} else {
utils.logWarn('Rubicon: video response received non-video media type');
}
Expand Down Expand Up @@ -810,6 +818,64 @@ function _renderCreative(script, impId) {
</html>`;
}

function hideGoogleAdsDiv(adUnit) {
const el = adUnit.querySelector("div[id^='google_ads']");
if (el) {
el.style.setProperty('display', 'none');
}
}

function hideSmartAdServerIframe(adUnit) {
const el = adUnit.querySelector("script[id^='sas_script']");
const nextSibling = el && el.nextSibling;
if (nextSibling && nextSibling.localName === 'iframe') {
nextSibling.style.setProperty('display', 'none');
}
}

function renderBid(bid) {
// hide existing ad units
const adUnitElement = document.getElementById(bid.adUnitCode);
hideGoogleAdsDiv(adUnitElement);
hideSmartAdServerIframe(adUnitElement);

// configure renderer
const config = bid.renderer.getConfig();
bid.renderer.push(() => {
window.MagniteApex.renderAd({
width: bid.width,
height: bid.height,
vastUrl: bid.vastUrl,
placement: {
attachTo: `#${bid.adUnitCode}`,
align: config.align || 'center',
position: config.position || 'append'
},
closeButton: config.closeButton || false,
label: config.label || undefined,
collapse: config.collapse || true
});
});
}

function outstreamRenderer(rtbBid) {
const renderer = Renderer.install({
id: rtbBid.adId,
url: rubiConf.rendererUrl || DEFAULT_RENDERER_URL,
config: rubiConf.rendererConfig || {},
loaded: false,
adUnitCode: rtbBid.adUnitCode
});

try {
renderer.setRender(renderBid);
} catch (err) {
utils.logWarn('Prebid Error calling setRender on renderer', err);
}

return renderer;
}

function parseSizes(bid, mediaType) {
let params = bid.params;
if (mediaType === 'video') {
Expand Down
147 changes: 147 additions & 0 deletions test/spec/modules/rubiconBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3050,6 +3050,153 @@ describe('the rubicon adapter', function () {
});
});

describe('for outstream video', function () {
const sandbox = sinon.createSandbox();
beforeEach(function () {
createVideoBidderRequestOutstream();
config.setConfig({rubicon: {
rendererConfig: {
align: 'left',
closeButton: true
},
rendererUrl: 'https://example.test/renderer.js'
}});
window.MagniteApex = {
renderAd: function() {
return null;
}
}
});

afterEach(function () {
sandbox.restore();
delete window.MagniteApex;
});

it('should register a successful bid', function () {
let response = {
cur: 'USD',
seatbid: [{
bid: [{
id: '0',
impid: 'outstream_video1',
adomain: ['test.com'],
price: 2,
crid: '4259970',
ext: {
bidder: {
rp: {
mime: 'application/javascript',
size_id: 201,
advid: 12345
}
},
prebid: {
targeting: {
hb_uuid: '0c498f63-5111-4bed-98e2-9be7cb932a64'
},
type: 'video'
}
}
}],
group: 0,
seat: 'rubicon'
}],
};

let bids = spec.interpretResponse({body: response}, {
bidRequest: bidderRequest.bids[0]
});

expect(bids).to.be.lengthOf(1);

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].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');
expect(bids[0].meta.mediaType).to.equal('video');
expect(String(bids[0].meta.advertiserDomains)).to.equal('test.com');
expect(bids[0].meta.advertiserId).to.equal(12345);
expect(bids[0].bidderCode).to.equal('rubicon');
expect(bids[0].currency).to.equal('USD');
expect(bids[0].width).to.equal(640);
expect(bids[0].height).to.equal(320);
// check custom renderer
expect(typeof bids[0].renderer).to.equal('object');
expect(bids[0].renderer.getConfig()).to.deep.equal({
align: 'left',
closeButton: true
});
expect(bids[0].renderer.url).to.equal('https://example.test/renderer.js');
});

it('should render ad with Magnite renderer', function () {
let response = {
cur: 'USD',
seatbid: [{
bid: [{
id: '0',
impid: 'outstream_video1',
adomain: ['test.com'],
price: 2,
crid: '4259970',
ext: {
bidder: {
rp: {
mime: 'application/javascript',
size_id: 201,
advid: 12345
}
},
prebid: {
targeting: {
hb_uuid: '0c498f63-5111-4bed-98e2-9be7cb932a64'
},
type: 'video'
}
},
nurl: 'https://test.com/vast.xml'
}],
group: 0,
seat: 'rubicon'
}],
};

sinon.spy(window.MagniteApex, 'renderAd');

let bids = spec.interpretResponse({body: response}, {
bidRequest: bidderRequest.bids[0]
});
const bid = bids[0];
bid.adUnitCode = 'outstream_video1_placement';
const adUnit = document.createElement('div');
adUnit.id = bid.adUnitCode;
document.body.appendChild(adUnit);

bid.renderer.render(bid);

const renderCall = window.MagniteApex.renderAd.getCall(0);
expect(renderCall.args[0]).to.deep.equal({
closeButton: true,
collapse: true,
height: 320,
label: undefined,
placement: {
align: 'left',
attachTo: '#outstream_video1_placement',
position: 'append',
},
vastUrl: 'https://test.com/vast.xml',
width: 640
});
// cleanup
adUnit.remove();
});
});

describe('config with integration type', () => {
it('should use the integration type provided in the config instead of the default', () => {
config.setConfig({rubicon: {int_type: 'testType'}});
Expand Down

0 comments on commit 6c41930

Please sign in to comment.