Skip to content

Commit 937ea8a

Browse files
Hendrik Isekeidettman
Hendrik Iseke
authored andcommitted
New Orbidder Prebid Adapter (#3434)
* initial orbidder version in personal github repo * use adUnits from orbidder_example.html * replace obsolete functions * forgot to commit the test * check if bidderRequest object is available * try to fix weird safari/ie issue
1 parent 339c93d commit 937ea8a

File tree

3 files changed

+298
-0
lines changed

3 files changed

+298
-0
lines changed

modules/orbidderBidAdapter.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import {detectReferer} from 'src/refererDetection';
2+
import {ajax} from 'src/ajax';
3+
import {registerBidder} from 'src/adapters/bidderFactory';
4+
5+
export const spec = {
6+
code: 'orbidder',
7+
orbidderHost: (() => {
8+
let ret = 'https://orbidder.otto.de';
9+
try {
10+
ret = localStorage.getItem('ov_orbidder_host') || ret;
11+
} catch (e) {
12+
}
13+
return ret;
14+
})(),
15+
16+
isBidRequestValid(bid) {
17+
return !!(bid.sizes && bid.bidId);
18+
},
19+
20+
buildRequests(validBidRequests, bidderRequest) {
21+
return validBidRequests.map((bidRequest) => {
22+
let referer = '';
23+
if (bidderRequest && bidderRequest.refererInfo) {
24+
referer = bidderRequest.refererInfo.referer || '';
25+
}
26+
const ret = {
27+
url: `${this.orbidderHost}/bid`,
28+
method: 'POST',
29+
data: {
30+
pageUrl: referer,
31+
bidId: bidRequest.bidId,
32+
auctionId: bidRequest.auctionId,
33+
transactionId: bidRequest.transactionId,
34+
adUnitCode: bidRequest.adUnitCode,
35+
sizes: bidRequest.sizes,
36+
params: bidRequest.params
37+
}
38+
};
39+
if (bidRequest && bidRequest.gdprConsent) {
40+
ret.data.gdprConsent = {
41+
consentString: bidRequest.gdprConsent.consentString,
42+
consentRequired: (typeof bidRequest.gdprConsent.gdprApplies === 'boolean')
43+
? bidRequest.gdprConsent.gdprApplies
44+
: true
45+
};
46+
}
47+
return ret;
48+
});
49+
},
50+
51+
interpretResponse(serverResponse) {
52+
const bidResponses = [];
53+
serverResponse = serverResponse.body;
54+
if (serverResponse && (serverResponse.length > 0)) {
55+
serverResponse.forEach((bid) => {
56+
const bidResponse = {};
57+
for (const requiredKey of ['requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', 'netRevenue', 'currency']) {
58+
if (!bid.hasOwnProperty(requiredKey)) {
59+
return [];
60+
}
61+
bidResponse[requiredKey] = bid[requiredKey];
62+
}
63+
bidResponses.push(bidResponse);
64+
});
65+
}
66+
return bidResponses;
67+
},
68+
69+
onBidWon(winObj) {
70+
const getRefererInfo = detectReferer(window);
71+
const refererInfo = getRefererInfo();
72+
winObj.pageUrl = refererInfo.referer;
73+
ajax(`${this.orbidderHost}/win`, null, JSON.stringify(winObj));
74+
}
75+
};
76+
77+
registerBidder(spec);

modules/orbidderBidAdapter.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#Overview
2+
3+
```
4+
Module Name: Orbidder Bid Adapter
5+
Module Type: Bidder Adapter
6+
Maintainer: [email protected]
7+
```
8+
9+
# Description
10+
11+
Module that connects to orbidder demand sources
12+
13+
# Test Parameters
14+
```
15+
var adUnits = [{
16+
code: '/105091519/bidder_test',
17+
mediaTypes: {
18+
banner: {
19+
sizes: [728, 90]
20+
}
21+
},
22+
bids: [{
23+
bidder: 'orbidder'
24+
}]
25+
}];
26+
```
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
import {expect} from 'chai';
2+
import {spec} from 'modules/orbidderBidAdapter';
3+
import {newBidder} from 'src/adapters/bidderFactory';
4+
import * as ajax from 'src/ajax';
5+
6+
describe('orbidderBidAdapter', () => {
7+
const adapter = newBidder(spec);
8+
const bidRequest = {
9+
bidId: 'd66fa86787e0b0ca900a96eacfd5f0bb',
10+
auctionId: 'ccc4c7cdfe11cfbd74065e6dd28413d8',
11+
transactionId: 'd58851660c0c4461e4aa06344fc9c0c6',
12+
adUnitCode: 'adunit-code',
13+
sizes: [[300, 250], [300, 600]],
14+
params: {
15+
'foo': 'bar'
16+
}
17+
};
18+
19+
const buildRequest = function (buildRequest) {
20+
return spec.buildRequests(
21+
[buildRequest],
22+
{
23+
refererInfo: {
24+
referer: 'http://localhost:9876/'
25+
}
26+
})[0];
27+
}
28+
29+
describe('inherited functions', () => {
30+
it('exists and is a function', () => {
31+
expect(adapter.callBids).to.exist.and.to.be.a('function');
32+
});
33+
});
34+
35+
describe('isBidRequestValid', () => {
36+
it('should return true when required params found', () => {
37+
expect(spec.isBidRequestValid(bidRequest)).to.equal(true);
38+
});
39+
40+
it('should return false when required params are not passed', () => {
41+
let bidRequest = Object.assign({}, bidRequest);
42+
delete bidRequest.params;
43+
expect(spec.isBidRequestValid(bidRequest)).to.equal(false);
44+
});
45+
});
46+
47+
describe('buildRequests', () => {
48+
const request = buildRequest(bidRequest);
49+
50+
it('sends bid request to endpoint via https using post', () => {
51+
expect(request.method).to.equal('POST');
52+
expect(request.url.indexOf('https://')).to.equal(0);
53+
expect(request.url).to.equal(`${spec.orbidderHost}/bid`);
54+
});
55+
56+
it('sends correct bid parameters', () => {
57+
// we add one, because we add referer information from bidderRequest object
58+
expect(Object.keys(request.data).length).to.equal(Object.keys(bidRequest).length + 1);
59+
expect(request.data.pageUrl).to.equal('http://localhost:9876/');
60+
// expect(request.data.referrer).to.equal('');
61+
Object.keys(bidRequest).forEach((key) => {
62+
expect(bidRequest[key]).to.equal(request.data[key]);
63+
});
64+
});
65+
66+
it('handles empty gdpr object', () => {
67+
let bidRequest = Object.assign({}, bidRequest);
68+
bidRequest.gdprConsent = {};
69+
70+
const request = buildRequest(bidRequest);
71+
expect(request.data.gdprConsent.consentRequired).to.be.equal(true);
72+
});
73+
74+
it('handles non-existent gdpr object', () => {
75+
let bidRequest = Object.assign({}, bidRequest);
76+
bidRequest.gdprConsent = null;
77+
78+
const request = buildRequest(bidRequest);
79+
expect(request.data.gdprConsent).to.be.undefined;
80+
});
81+
82+
it('handles properly filled gdpr object where gdpr applies', () => {
83+
const consentString = 'someWeirdString';
84+
const bidRequest = Object.assign({}, bidRequest);
85+
bidRequest.gdprConsent = {
86+
gdprApplies: true,
87+
consentString: 'someWeirdString'
88+
};
89+
90+
const request = buildRequest(bidRequest);
91+
const gdprConsent = request.data.gdprConsent;
92+
expect(gdprConsent.consentRequired).to.be.equal(true);
93+
expect(gdprConsent.consentString).to.be.equal(consentString);
94+
});
95+
96+
it('handles properly filled gdpr object where gdpr does not apply', () => {
97+
const consentString = 'someWeirdString';
98+
const bidRequest = Object.assign({}, bidRequest);
99+
bidRequest.gdprConsent = {
100+
gdprApplies: false,
101+
consentString: 'someWeirdString'
102+
};
103+
104+
const request = buildRequest(bidRequest);
105+
const gdprConsent = request.data.gdprConsent;
106+
expect(gdprConsent.consentRequired).to.be.equal(false);
107+
expect(gdprConsent.consentString).to.be.equal(consentString);
108+
});
109+
});
110+
111+
describe('onBidWon', () => {
112+
let ajaxStub;
113+
const winObj = {
114+
test: 1,
115+
pageUrl: 'www.someurl.de',
116+
referrer: 'www.somereferrer.de'
117+
};
118+
119+
beforeEach(() => {
120+
ajaxStub = sinon.stub(ajax, 'ajax');
121+
});
122+
123+
afterEach(() => {
124+
ajaxStub.restore();
125+
});
126+
127+
it('calls orbidder\'s win endpoint', () => {
128+
spec.onBidWon(winObj);
129+
expect(ajaxStub.calledOnce).to.equal(true);
130+
expect(ajaxStub.firstCall.args[0].indexOf('https://')).to.equal(0);
131+
expect(ajaxStub.firstCall.args[0]).to.equal(`${spec.orbidderHost}/win`);
132+
expect(ajaxStub.firstCall.args[2]).to.equal(JSON.stringify(winObj));
133+
});
134+
});
135+
136+
describe('interpretResponse', () => {
137+
it('should get correct bid response', () => {
138+
const serverResponse = [
139+
{
140+
'width': 300,
141+
'height': 250,
142+
'creativeId': '29681110',
143+
'ad': '<!-- Creative -->',
144+
'cpm': 0.5,
145+
'requestId': '30b31c1838de1e',
146+
'ttl': 60,
147+
'netRevenue': true,
148+
'currency': 'EUR'
149+
}
150+
];
151+
152+
const expectedResponse = [
153+
{
154+
'requestId': '30b31c1838de1e',
155+
'cpm': 0.5,
156+
'creativeId': '29681110',
157+
'width': 300,
158+
'height': 250,
159+
'ttl': 60,
160+
'currency': 'EUR',
161+
'ad': '<!-- Creative -->',
162+
'netRevenue': true
163+
}
164+
];
165+
166+
const result = spec.interpretResponse({body: serverResponse});
167+
168+
expect(result.length).to.equal(expectedResponse.length);
169+
Object.keys(expectedResponse[0]).forEach((key) => {
170+
expect(result[0][key]).to.equal(expectedResponse[0][key]);
171+
});
172+
});
173+
174+
it('handles broken server response', () => {
175+
const serverResponse = [
176+
{
177+
'ad': '<!-- Creative -->',
178+
'cpm': 0.5,
179+
'requestId': '30b31c1838de1e',
180+
'ttl': 60
181+
}
182+
];
183+
const result = spec.interpretResponse({body: serverResponse});
184+
185+
expect(result.length).to.equal(0);
186+
});
187+
188+
it('handles nobid responses', () => {
189+
const serverResponse = [];
190+
const result = spec.interpretResponse({body: serverResponse});
191+
192+
expect(result.length).to.equal(0);
193+
});
194+
});
195+
});

0 commit comments

Comments
 (0)