Skip to content

Commit

Permalink
Added LoopMe Adapter (prebid#3586)
Browse files Browse the repository at this point in the history
* Added LoopMe Adapter

* Replace Object.entries with entries
  • Loading branch information
EpanchinE authored and jsnellbaker committed Mar 1, 2019
1 parent d36d458 commit 5112950
Show file tree
Hide file tree
Showing 3 changed files with 229 additions and 0 deletions.
99 changes: 99 additions & 0 deletions modules/loopmeBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import * as utils from 'src/utils';
import { registerBidder } from 'src/adapters/bidderFactory';
import { BANNER } from 'src/mediaTypes';

const LOOPME_ENDPOINT = 'https://loopme.me/api/hb';

const entries = (obj) => {
let output = [];
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
output.push([key, obj[key]])
}
}
return output;
}

export const spec = {
code: 'loopme',
supportedMediaTypes: [BANNER],
/**
* @param {object} bid
* @return boolean
*/
isBidRequestValid: function(bid) {
if (typeof bid.params !== 'object') {
return false;
}

return !!bid.params.ak;
},
/**
* @param {BidRequest[]} bidRequests
* @param bidderRequest
* @return ServerRequest[]
*/
buildRequests: function(bidRequests, bidderRequest) {
return bidRequests.map(bidRequest => {
bidRequest.startTime = new Date().getTime();
let payload = bidRequest.params;

if (bidderRequest && bidderRequest.gdprConsent) {
payload.user_consent = bidderRequest.gdprConsent.consentString;
}

let queryString = entries(payload)
.map(item => `${item[0]}=${encodeURI(item[1])}`)
.join('&');

const sizes =
'&sizes=' +
utils
.getAdUnitSizes(bidRequest)
.map(size => `${size[0]}x${size[1]}`)
.join('&sizes=');

queryString = `${queryString}${sizes}`;

return {
method: 'GET',
url: `${LOOPME_ENDPOINT}`,
options: { withCredentials: false },
bidId: bidRequest.bidId,
data: queryString
};
});
},
/**
* @param {*} responseObj
* @param {BidRequest} bidRequest
* @return {Bid[]} An array of bids which
*/
interpretResponse: function(response = {}, bidRequest) {
const responseObj = response.body;

if (
responseObj == null ||
typeof responseObj !== 'object' ||
!responseObj.hasOwnProperty('ad')
) {
return [];
}

return [
{
requestId: bidRequest.bidId,
cpm: responseObj.cpm,
width: responseObj.width,
height: responseObj.height,
ad: responseObj.ad,
ttl: responseObj.ttl,
currency: responseObj.currency,
creativeId: responseObj.creativeId,
dealId: responseObj.dealId,
netRevenue: responseObj.netRevenue
}
];
}
};
registerBidder(spec);
29 changes: 29 additions & 0 deletions modules/loopmeBidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Overview

```
Module Name: LoopMe Bid Adapter
Module Type: Bidder Adapter
Maintainer: support@loopme.com
```

# Description

Connect to LoopMe's exchange for bids.

# Test Parameters
```
var adUnits = [{
code: 'test-div',
mediaTypes: {
banner: {
sizes: [[300, 250], [300,600]],
}
},
bids: [{
bidder: 'loopme',
params: {
ak: 'cc885e3acc'
}
}]
}];
```
101 changes: 101 additions & 0 deletions test/spec/modules/loopmeBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { expect } from 'chai';
import { spec } from '../../../modules/loopmeBidAdapter';
import * as utils from 'src/utils';

describe('LoopMeAdapter', function () {
const bidRequests = [{
bidder: 'loopme',
params: {
ak: 'b510d5bcda'
},
mediaTypes: {
banner: {
sizes: [[300, 250]]
}
},
adUnitCode: 'ad-1',
bidId: '2652ca954bce9'
}];

describe('isBidRequestValid', function () {
it('should return true if the ak parameter is present', function () {
expect(spec.isBidRequestValid(bidRequests[0])).to.be.true;
});

it('should return false if the ak parameter is not present', function () {
let bidRequest = utils.deepClone(bidRequests[0]);
delete bidRequest.params.ak;
expect(spec.isBidRequestValid(bidRequest)).to.be.false;
});

it('should return false if the params object is not present', function () {
let bidRequest = utils.deepClone(bidRequests);
delete bidRequest[0].params;
expect(spec.isBidRequestValid(bidRequest)).to.be.false;
});
});

describe('buildRequests', function () {
it('should generate a valid single GET request for multiple bid requests', function () {
const request = spec.buildRequests(bidRequests)[0];
expect(request.method).to.equal('GET');
expect(request.url).to.equal('https://loopme.me/api/hb');
expect(request.bidId).to.equal('2652ca954bce9');
expect(request.data).to.exist;

const requestData = request.data;
expect(requestData).to.contain('ak=b510d5bcda');
expect(requestData).to.contain('sizes=300x250');
});

it('should add GDPR data to request if available', function () {
const bidderRequest = {
gdprConsent: {
consentString: 'AAABBB'
}
};
const request = spec.buildRequests(bidRequests, bidderRequest)[0];
const requestData = request.data;

expect(requestData).to.contain('user_consent=AAABBB');
});
});

describe('interpretResponse', function () {
it('should return an empty array if an invalid response is passed', function () {
const interpretedResponse = spec.interpretResponse({});
expect(interpretedResponse).to.be.an('array').that.is.empty;
});

it('should return valid response when passed valid server response', function () {
const serverResponse = {
body: {
'requestId': '2652ca954bce9',
'cpm': 1,
'width': 480,
'height': 320,
'creativeId': '20154',
'currency': 'USD',
'netRevenue': false,
'ttl': 360,
'ad': `<div>Hello</div>`
}
};

const request = spec.buildRequests(bidRequests)[0];
const interpretedResponse = spec.interpretResponse(serverResponse, request);

expect(interpretedResponse).to.have.lengthOf(1);

expect(interpretedResponse[0].requestId).to.equal(serverResponse.body.requestId);
expect(interpretedResponse[0].cpm).to.equal(serverResponse.body.cpm);
expect(interpretedResponse[0].width).to.equal(serverResponse.body.width);
expect(interpretedResponse[0].height).to.equal(serverResponse.body.height);
expect(interpretedResponse[0].creativeId).to.equal(serverResponse.body.creativeId);
expect(interpretedResponse[0].currency).to.equal(serverResponse.body.currency);
expect(interpretedResponse[0].netRevenue).to.equal(serverResponse.body.netRevenue);
expect(interpretedResponse[0].ad).to.equal(serverResponse.body.ad);
expect(interpretedResponse[0].ttl).to.equal(serverResponse.body.ttl);
});
});
});

0 comments on commit 5112950

Please sign in to comment.