Skip to content

Commit 72e0e97

Browse files
MaxSmileWantedjsnellbaker
authored andcommitted
New bid adapter for SmileWanted (prebid#3601)
* New bid adapter for SmileWanted - Smilewanted BidAdapter module and test spec added * Update to correct feedback from PR prebid#3601 - Add comments - Default value for currencyCode - replacing "utils.getTopWindowUrl()" with bidderRequest.refererInfo - Update unit tests * Delete of the commented spec
1 parent d00c92a commit 72e0e97

File tree

3 files changed

+335
-0
lines changed

3 files changed

+335
-0
lines changed

modules/smilewantedBidAdapter.js

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import * as utils from '../src/utils';
2+
import { config } from '../src/config';
3+
import { registerBidder } from '../src/adapters/bidderFactory';
4+
5+
export const spec = {
6+
code: 'smilewanted',
7+
aliases: ['smile', 'sw'],
8+
9+
/**
10+
* Determines whether or not the given bid request is valid.
11+
*
12+
* @param {object} bid The bid to validate.
13+
* @return boolean True if this is a valid bid, and false otherwise.
14+
*/
15+
isBidRequestValid: function(bid) {
16+
return !!(bid.params && bid.params.zoneId);
17+
},
18+
19+
/**
20+
* Make a server request from the list of BidRequests.
21+
*
22+
* @param {BidRequest[]} validBidRequests A non-empty list of valid bid requests that should be sent to the Server.
23+
* @return ServerRequest Info describing the request to the server.
24+
*/
25+
buildRequests: function(validBidRequests, bidderRequest) {
26+
return validBidRequests.map(bid => {
27+
var payload = {
28+
zoneId: bid.params.zoneId,
29+
currencyCode: config.getConfig('currency.adServerCurrency') || 'EUR',
30+
bidfloor: bid.params.bidfloor || 0.0,
31+
tagId: bid.adUnitCode,
32+
sizes: bid.sizes.map(size => ({
33+
w: size[0],
34+
h: size[1]
35+
})),
36+
transactionId: bid.transactionId,
37+
timeout: config.getConfig('bidderTimeout'),
38+
bidId: bid.bidId,
39+
prebidVersion: '$prebid.version$'
40+
};
41+
42+
if (bidderRequest && bidderRequest.refererInfo) {
43+
payload.pageDomain = bidderRequest.refererInfo.referer || '';
44+
}
45+
46+
if (bidderRequest && bidderRequest.gdprConsent) {
47+
payload.gdpr_consent = bidderRequest.gdprConsent.consentString;
48+
payload.gdpr = bidderRequest.gdprConsent.gdprApplies; // we're handling the undefined case server side
49+
}
50+
var payloadString = JSON.stringify(payload);
51+
return {
52+
method: 'POST',
53+
url: 'https://prebid.smilewanted.com',
54+
data: payloadString,
55+
};
56+
});
57+
},
58+
59+
/**
60+
* Unpack the response from the server into a list of bids.
61+
*
62+
* @param {*} serverResponse A successful response from the server.
63+
* @return {Bid[]} An array of bids which were nested inside the server.
64+
*/
65+
interpretResponse: function(serverResponse, bidRequest) {
66+
const bidResponses = [];
67+
var response = serverResponse.body;
68+
try {
69+
if (response) {
70+
const bidResponse = {
71+
requestId: JSON.parse(bidRequest.data).bidId,
72+
cpm: response.cpm,
73+
width: response.width,
74+
height: response.height,
75+
creativeId: response.creativeId,
76+
dealId: response.dealId,
77+
currency: response.currency,
78+
netRevenue: response.isNetCpm,
79+
ttl: response.ttl,
80+
adUrl: response.adUrl,
81+
ad: response.ad
82+
};
83+
84+
bidResponses.push(bidResponse);
85+
}
86+
} catch (error) {
87+
utils.logError('Error while parsing smilewanted response', error);
88+
}
89+
return bidResponses;
90+
},
91+
92+
/**
93+
* User syncs.
94+
*
95+
* @param {*} syncOptions Publisher prebid configuration.
96+
* @param {*} serverResponses A successful response from the server.
97+
* @return {Syncs[]} An array of syncs that should be executed.
98+
*/
99+
getUserSyncs: function(syncOptions, serverResponses) {
100+
const syncs = []
101+
if (syncOptions.iframeEnabled && serverResponses.length > 0) {
102+
if (serverResponses[0].body.cSyncUrl === 'https://csync.smilewanted.com') {
103+
syncs.push({
104+
type: 'iframe',
105+
url: serverResponses[0].body.cSyncUrl
106+
});
107+
}
108+
}
109+
return syncs;
110+
}
111+
}
112+
113+
registerBidder(spec);

modules/smilewantedBidAdapter.md

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Overview
2+
3+
```
4+
Module Name: SmileWanted Bidder Adapter
5+
Module Type: Bidder Adapter
6+
Maintainer: [email protected]
7+
```
8+
9+
# Description
10+
11+
To use us as a bidder you must have an account and an active "zoneId" on our SmileWanted platform.
12+
13+
# Test Parameters
14+
15+
## Web
16+
```
17+
var adUnits = [
18+
{
19+
code: 'test-div',
20+
sizes: [[300, 250]],
21+
bids: [
22+
{
23+
bidder: "smilewanted",
24+
params: {
25+
zoneId: 1
26+
}
27+
}
28+
]
29+
}
30+
];
31+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
import { expect } from 'chai';
2+
import { spec } from 'modules/smilewantedBidAdapter';
3+
import { newBidder } from 'src/adapters/bidderFactory';
4+
import { config } from 'src/config';
5+
import * as utils from 'src/utils';
6+
import { requestBidsHook } from 'modules/consentManagement';
7+
8+
// Default params with optional ones
9+
describe('smilewantedBidAdapterTests', function () {
10+
var DEFAULT_PARAMS = [{
11+
adUnitCode: 'sw_300x250',
12+
bidId: '12345',
13+
sizes: [
14+
[300, 250],
15+
[300, 200]
16+
],
17+
bidder: 'smilewanted',
18+
params: {
19+
zoneId: '1234',
20+
bidfloor: 2.50
21+
},
22+
requestId: 'request_abcd1234',
23+
transactionId: 'trans_abcd1234'
24+
}];
25+
26+
var BID_RESPONSE = {
27+
body: {
28+
cpm: 3,
29+
width: 300,
30+
height: 250,
31+
creativeId: 'crea_sw_1',
32+
currency: 'EUR',
33+
isNetCpm: true,
34+
ttl: 300,
35+
adUrl: 'https://www.smilewanted.com',
36+
ad: '< --- sw script --- >',
37+
cSyncUrl: 'https://csync.smilewanted.com'
38+
}
39+
};
40+
41+
it('SmileWanted - Verify build request', function () {
42+
config.setConfig({
43+
'currency': {
44+
'adServerCurrency': 'EUR'
45+
}
46+
});
47+
const request = spec.buildRequests(DEFAULT_PARAMS);
48+
expect(request[0]).to.have.property('url').and.to.equal('https://prebid.smilewanted.com');
49+
expect(request[0]).to.have.property('method').and.to.equal('POST');
50+
const requestContent = JSON.parse(request[0].data);
51+
expect(requestContent).to.have.property('zoneId').and.to.equal('1234');
52+
expect(requestContent).to.have.property('currencyCode').and.to.equal('EUR');
53+
expect(requestContent).to.have.property('bidfloor').and.to.equal(2.50);
54+
expect(requestContent).to.have.property('sizes');
55+
expect(requestContent.sizes[0]).to.have.property('w').and.to.equal(300);
56+
expect(requestContent.sizes[0]).to.have.property('h').and.to.equal(250);
57+
expect(requestContent.sizes[1]).to.have.property('w').and.to.equal(300);
58+
expect(requestContent.sizes[1]).to.have.property('h').and.to.equal(200);
59+
expect(requestContent).to.have.property('transactionId').and.to.not.equal(null).and.to.not.be.undefined;
60+
});
61+
62+
it('SmileWanted - Verify build request with referrer', function () {
63+
const request = spec.buildRequests(DEFAULT_PARAMS, {
64+
refererInfo: {
65+
referer: 'http://localhost/Prebid.js/integrationExamples/gpt/hello_world.html'
66+
}
67+
});
68+
const requestContent = JSON.parse(request[0].data);
69+
expect(requestContent).to.have.property('pageDomain').and.to.equal('http://localhost/Prebid.js/integrationExamples/gpt/hello_world.html');
70+
});
71+
72+
describe('gdpr tests', function () {
73+
afterEach(function () {
74+
config.resetConfig();
75+
$$PREBID_GLOBAL$$.requestBids.removeAll();
76+
});
77+
78+
it('SmileWanted - Verify build request with GDPR', function () {
79+
config.setConfig({
80+
'currency': {
81+
'adServerCurrency': 'EUR'
82+
},
83+
consentManagement: {
84+
cmp: 'iab',
85+
consentRequired: true,
86+
timeout: 1000,
87+
allowAuctionWithoutConsent: true
88+
}
89+
});
90+
const request = spec.buildRequests(DEFAULT_PARAMS, {
91+
gdprConsent: {
92+
consentString: 'BOO_ch7OO_ch7AKABBENA2-AAAAZ97_______9______9uz_Gv_r_f__33e8_39v_h_7_u___m_-zzV4-_lvQV1yPA1OrfArgFA',
93+
gdprApplies: true
94+
}
95+
});
96+
const requestContent = JSON.parse(request[0].data);
97+
expect(requestContent).to.have.property('gdpr').and.to.equal(true);
98+
expect(requestContent).to.have.property('gdpr_consent').and.to.equal('BOO_ch7OO_ch7AKABBENA2-AAAAZ97_______9______9uz_Gv_r_f__33e8_39v_h_7_u___m_-zzV4-_lvQV1yPA1OrfArgFA');
99+
});
100+
101+
it('SmileWanted - Verify build request with GDPR without gdprApplies', function () {
102+
config.setConfig({
103+
'currency': {
104+
'adServerCurrency': 'EUR'
105+
},
106+
consentManagement: {
107+
cmp: 'iab',
108+
consentRequired: true,
109+
timeout: 1000,
110+
allowAuctionWithoutConsent: true
111+
}
112+
});
113+
const request = spec.buildRequests(DEFAULT_PARAMS, {
114+
gdprConsent: {
115+
consentString: 'BOO_ch7OO_ch7AKABBENA2-AAAAZ97_______9______9uz_Gv_r_f__33e8_39v_h_7_u___m_-zzV4-_lvQV1yPA1OrfArgFA'
116+
}
117+
});
118+
const requestContent = JSON.parse(request[0].data);
119+
expect(requestContent).to.not.have.property('gdpr');
120+
expect(requestContent).to.have.property('gdpr_consent').and.to.equal('BOO_ch7OO_ch7AKABBENA2-AAAAZ97_______9______9uz_Gv_r_f__33e8_39v_h_7_u___m_-zzV4-_lvQV1yPA1OrfArgFA');
121+
});
122+
});
123+
124+
it('SmileWanted - Verify parse response', function () {
125+
const request = spec.buildRequests(DEFAULT_PARAMS);
126+
const bids = spec.interpretResponse(BID_RESPONSE, request[0]);
127+
expect(bids).to.have.lengthOf(1);
128+
const bid = bids[0];
129+
expect(bid.cpm).to.equal(3);
130+
expect(bid.adUrl).to.equal('https://www.smilewanted.com');
131+
expect(bid.ad).to.equal('< --- sw script --- >');
132+
expect(bid.width).to.equal(300);
133+
expect(bid.height).to.equal(250);
134+
expect(bid.creativeId).to.equal('crea_sw_1');
135+
expect(bid.currency).to.equal('EUR');
136+
expect(bid.netRevenue).to.equal(true);
137+
expect(bid.ttl).to.equal(300);
138+
expect(bid.requestId).to.equal(DEFAULT_PARAMS[0].bidId);
139+
140+
expect(function () {
141+
spec.interpretResponse(BID_RESPONSE, {
142+
data: 'invalid Json'
143+
})
144+
}).to.not.throw();
145+
});
146+
147+
it('SmileWanted - Verify bidder code', function () {
148+
expect(spec.code).to.equal('smilewanted');
149+
});
150+
151+
it('SmileWanted - Verify bidder aliases', function () {
152+
expect(spec.aliases).to.have.lengthOf(2);
153+
expect(spec.aliases[0]).to.equal('smile');
154+
expect(spec.aliases[1]).to.equal('sw');
155+
});
156+
157+
it('SmileWanted - Verify if bid request valid', function () {
158+
expect(spec.isBidRequestValid(DEFAULT_PARAMS[0])).to.equal(true);
159+
expect(spec.isBidRequestValid({
160+
params: {
161+
zoneId: 1234
162+
}
163+
})).to.equal(true);
164+
});
165+
166+
it('SmileWanted - Verify if params(zoneId) is not passed', function () {
167+
expect(spec.isBidRequestValid({})).to.equal(false);
168+
expect(spec.isBidRequestValid({
169+
params: {}
170+
})).to.equal(false);
171+
});
172+
173+
it('SmileWanted - Verify user sync', function () {
174+
var syncs = spec.getUserSyncs({
175+
iframeEnabled: true
176+
}, [BID_RESPONSE]);
177+
expect(syncs).to.have.lengthOf(1);
178+
expect(syncs[0].type).to.equal('iframe');
179+
expect(syncs[0].url).to.equal('https://csync.smilewanted.com');
180+
181+
syncs = spec.getUserSyncs({
182+
iframeEnabled: false
183+
}, [BID_RESPONSE]);
184+
expect(syncs).to.have.lengthOf(0);
185+
186+
syncs = spec.getUserSyncs({
187+
iframeEnabled: true
188+
}, []);
189+
expect(syncs).to.have.lengthOf(0);
190+
});
191+
});

0 commit comments

Comments
 (0)