Skip to content

Commit

Permalink
Add Widespace adapter (#846)
Browse files Browse the repository at this point in the history
* Widespace adapter
* Widespace adapter tests
* Tests are passing
* Added widespace to adaptors.json
* Should be double quotes
* Removed debug log
* Updated  Wdespace test with a sid parameter that will receive test ad´s.
* Updated tests
* Dont reset pbjs._bidsRequested beforeEach
* I added 300x300 to allowed ad sizes as we don't have 300x250 or 300x600 ad sizes.
  • Loading branch information
jonasmattsson1 authored and matthewlane committed Dec 16, 2016
1 parent ce3b07e commit d6ebd87
Show file tree
Hide file tree
Showing 4 changed files with 304 additions and 1 deletion.
1 change: 1 addition & 0 deletions adapters.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"centro",
"roxot",
"vertoz",
"widespace",
{
"appnexus": {
"alias": "brealtime"
Expand Down
9 changes: 8 additions & 1 deletion integrationExamples/gpt/pbjs_example_gpt.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
var adUnits = [
{
code: 'div-gpt-ad-12345678-0',
sizes: [[300, 250], [300, 600]],
sizes: [[300, 250], [300, 300], [300, 600]],
bids: [
// 1 ad unit can be targeted by multiple bids.
{
Expand Down Expand Up @@ -224,6 +224,13 @@
zoneId : '30164',
host : 'cpm.metaadserving.com'
}
},
{
bidder: 'widespace',
params: {
sid: '7b6589bf-95c8-4656-90b9-af9737bb9ad3',
cur: 'EUR'
}
}
]
}, {
Expand Down
103 changes: 103 additions & 0 deletions src/adapters/widespace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@

import { getBidRequest } from '../utils.js';

var utils = require('../utils.js');
var adloader = require('../adloader.js');
var bidmanager = require('../bidmanager.js');
var bidfactory = require('../bidfactory.js');


function WidespaceAdapter() {
let useSSL = 'https:' === document.location.protocol,
baseURL = (useSSL ? 'https:' : 'http:') + '//engine.widespace.com/map/engine/hb/dynamic?',
callbackName = '$$PREBID_GLOBAL$$.widespaceHandleCB';

function _callBids(params) {
let bids = params && params.bids || [];

for (var i = 0; i < bids.length; i++) {
const bid = bids[i],
callbackUid = bid.bidId,
sid = bid.params.sid,
currency = bid.params.currency;

//Handle Sizes string
let sizeQueryString = '';
let parsedSizes = utils.parseSizesInput(bid.sizes);

sizeQueryString = parsedSizes.reduce((prev, curr) => {
return prev ? `${prev},${curr}` : curr;
}, sizeQueryString);

var requestURL = baseURL;
requestURL = utils.tryAppendQueryString(requestURL, 'hb.name', 'prebidjs');
requestURL = utils.tryAppendQueryString(requestURL, 'hb.callback', callbackName);
requestURL = utils.tryAppendQueryString(requestURL, 'hb.callbackUid', callbackUid);
requestURL = utils.tryAppendQueryString(requestURL, 'hb.sizes', sizeQueryString);
requestURL = utils.tryAppendQueryString(requestURL, 'sid', sid);
requestURL = utils.tryAppendQueryString(requestURL, 'hb.currency', currency);


// Expose the callback
$$PREBID_GLOBAL$$.widespaceHandleCB = window[callbackName] = handleCallback;

adloader.loadScript(requestURL);
}
}

//Handle our callback
var handleCallback = function handleCallback(bidsArray) {
if (!bidsArray) { return; }

var bidObject,
bidCode = 'widespace';

for (var i = 0, l = bidsArray.length; i < l; i++) {
var bid = bidsArray[i],
placementCode = '',
validSizes = [];

bid.sizes = {height: bid.height, width: bid.height};

var inBid = getBidRequest(bid.callbackUid);

if (inBid) {
bidCode = inBid.bidder;
placementCode = inBid.placementCode;
validSizes = inBid.sizes;
}
if (bid && bid.callbackUid && bid.status !=='noad' && verifySize(bid.sizes, validSizes)) {
bidObject = bidfactory.createBid(1);
bidObject.bidderCode = bidCode;
bidObject.cpm = bid.cpm;
bidObject.cur = bid.currency;
bidObject.creative_id = bid.adId;
bidObject.ad = bid.code;
bidObject.width = bid.width;
bidObject.height = bid.height;
bidmanager.addBidResponse(placementCode, bidObject);
} else {
bidObject = bidfactory.createBid(2);
bidObject.bidderCode = bidCode;
bidmanager.addBidResponse(placementCode, bidObject);
}
}


function verifySize(bid, validSizes) {
for (var j = 0, k = validSizes.length; j < k; j++) {
if (bid.width === validSizes[j][0] &&
bid.height === validSizes[j][1]) {
return true;
}
}
return false;
}
};

return {
callBids: _callBids
};
}

module.exports = WidespaceAdapter;
192 changes: 192 additions & 0 deletions test/spec/adapters/widespace_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
import { expect } from 'chai';
import adLoader from '../../../src/adloader';
import bidManager from '../../../src/bidmanager';
import Adapter from '../../../src/adapters/widespace';


const ENDPOINT = '//engine.widespace.com/map/engine/hb/dynamic';

const TEST = {
BIDDER_CODE: 'widespace',
CPM: 2.0,
PLACEMENT_CODE: 'aPlacementCode',
SID: 'f666bfaf-69cf-4ed9-9262-08247bb274e4',
CUR: 'EUR'
};

const BID_REQUEST = {
"bidderCode": TEST.BIDDER_CODE,
"requestId": "e155185b-3eac-4f3c-8182-cdb57a69df3c",
"bidderRequestId": "38993e482321e7",
"bids": [
{
"bidder": TEST.BIDDER_CODE,
"params": {
"sid": TEST.SID,
"cur": TEST.CUR
},
"placementCode": TEST.PLACEMENT_CODE,
"sizes": [
[320, 320],
[320, 250]
],
"bidId": "45c7f5afb996c1",
"bidderRequestId": "7101db09af0db3",
"requestId": "e155185b-3eac-4f3c-8182-cdb57a69df3d"
}
],
"start": 1479664180396,
"timeout": 5000
};


const BID_RESPONSE = [{
"status": "ok",
"reqId": "140590112507",
"adId": 13963,
"width": 320,
"height": 320,
"cpm": 2.0,
"currency": "EUR",
"code": "<p>This is a banner</p>",
"callbackUid": "45c7f5afb996c1",
"callback": "pbjs.widespaceHandleCB"
}];

const BID_NOAD_RESPONSE = [{
"status": "noad",
"reqId": "143509454349",
"adId": 22,
"width": 1,
"height": 1,
"cpm": 0.0,
"currency": "EUR",
"code": "",
"callbackUid": "45c7f5afb996c1",
"callback": "pbjs.widespaceHandleCB"
}]


describe('WidespaceAdapter', () => {

let adapter;
let sandbox;

beforeEach(() => {
adapter = new Adapter();
sandbox = sinon.sandbox.create();
});

afterEach(() => {
sandbox.restore();
});


describe('callBids', () => {
it('should exists and be a function', () => {
expect(adapter.callBids).to.exist.and.to.be.a('function');
});


describe('with valid request parameters', () => {
beforeEach(() => {
sandbox.stub(adLoader, 'loadScript');
adapter.callBids(BID_REQUEST);
});

it('should call the endpoint once per valid bid', () => {
sinon.assert.callCount(adLoader.loadScript, 1);
});

it('should include required request parameters', () => {
const endpointRequest = expect(adLoader.loadScript.firstCall.args[0]);
endpointRequest.to.include('sid');
endpointRequest.to.include('hb.callbackUid');
endpointRequest.to.include('hb.callback');
endpointRequest.to.include('hb.sizes');
endpointRequest.to.include('hb.name');
});
});

describe('with unvalid request parameters', () => {
beforeEach(() => {
sandbox.stub(adLoader, 'loadScript');
});

it('should not call the endpoint with if there is no request parameters', () => {
adapter.callBids({});
sinon.assert.callCount(adLoader.loadScript, 0);
});
});
});


describe('widespaceHandleCB', () => {
it('should exist and be a function', () => {
expect(pbjs.widespaceHandleCB).to.exist.and.to.be.a('function');
});
});

describe('respond with a successful bid', () => {
let successfulBid,
placementCode;

beforeEach(() => {
sandbox.stub(bidManager, 'addBidResponse');
sandbox.stub(adLoader, 'loadScript');

adapter.callBids(BID_REQUEST);
pbjs._bidsRequested.push(BID_REQUEST);
pbjs.widespaceHandleCB(BID_RESPONSE);

successfulBid = bidManager.addBidResponse.firstCall.args[1];
placementCode = bidManager.addBidResponse.firstCall.args[0];

});

it('should add one bid', () => {
sinon.assert.calledOnce(bidManager.addBidResponse);
});

it('should use the CPM returned by the server', () => {
expect(successfulBid).to.have.property('cpm', TEST.CPM);
});

it('should have an OK statusCode', () => {
expect(successfulBid.getStatusCode()).to.eql(1);
});

it('should have a valid size', () => {
const bidSize = [successfulBid.width,successfulBid.height]
expect(bidSize).to.eql(BID_REQUEST.bids[0].sizes[0]);

});

it('should recive right placementCode', () => {
expect(placementCode).to.eql(TEST.PLACEMENT_CODE);
});
});


describe('respond with a no-ad', () => {
let noadBid;

beforeEach(() => {
sandbox.stub(bidManager, 'addBidResponse');
sandbox.stub(adLoader, 'loadScript');

adapter.callBids(BID_REQUEST);
pbjs._bidsRequested.push(BID_REQUEST);
pbjs.widespaceHandleCB(BID_NOAD_RESPONSE);

noadBid = bidManager.addBidResponse.firstCall.args[1];
});

it('should have an error statusCode', () => {
expect(noadBid.getStatusCode()).to.eql(2);
});
});



});

0 comments on commit d6ebd87

Please sign in to comment.