prebid.js 6.20.0 → 6.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.circleci/config.yml +0 -1
- package/dist/33acrossBidAdapter.js +1 -1
- package/dist/adagioBidAdapter.js +1 -1
- package/dist/adbookpspBidAdapter.js +1 -1
- package/dist/adgenerationBidAdapter.js +1 -1
- package/dist/adomikAnalyticsAdapter.js +1 -1
- package/dist/adotBidAdapter.js +1 -1
- package/dist/adrelevantisBidAdapter.js +1 -1
- package/dist/adxcgBidAdapter.js +1 -1
- package/dist/ajaBidAdapter.js +1 -1
- package/dist/amxBidAdapter.js +1 -1
- package/dist/amxIdSystem.js +1 -1
- package/dist/apacdexBidAdapter.js +1 -1
- package/dist/appierAnalyticsAdapter.js +1 -1
- package/dist/appnexusBidAdapter.js +1 -1
- package/dist/asoBidAdapter.js +1 -1
- package/dist/audiencerunBidAdapter.js +1 -1
- package/dist/axonixBidAdapter.js +1 -1
- package/dist/betweenBidAdapter.js +1 -1
- package/dist/bidglassBidAdapter.js +1 -1
- package/dist/big-richmediaBidAdapter.js +1 -1
- package/dist/bridgewellBidAdapter.js +1 -1
- package/dist/brightMountainMediaBidAdapter.js +1 -1
- package/dist/cointrafficBidAdapter.js +1 -1
- package/dist/colossussspBidAdapter.js +1 -1
- package/dist/concertBidAdapter.js +1 -1
- package/dist/connectadBidAdapter.js +1 -1
- package/dist/consentManagement.js +1 -1
- package/dist/consentManagementUsp.js +1 -1
- package/dist/consumableBidAdapter.js +1 -1
- package/dist/conversantBidAdapter.js +1 -1
- package/dist/craftBidAdapter.js +1 -1
- package/dist/criteoBidAdapter.js +1 -1
- package/dist/dspxBidAdapter.js +1 -1
- package/dist/e_volutionBidAdapter.js +1 -1
- package/dist/eplanningBidAdapter.js +1 -1
- package/dist/ftrackIdSystem.js +1 -1
- package/dist/glimpseBidAdapter.js +1 -1
- package/dist/gmosspBidAdapter.js +1 -1
- package/dist/goldbachBidAdapter.js +1 -1
- package/dist/gridBidAdapter.js +1 -1
- package/dist/gridNMBidAdapter.js +1 -1
- package/dist/gumgumBidAdapter.js +1 -1
- package/dist/h12mediaBidAdapter.js +1 -1
- package/dist/id5IdSystem.js +1 -1
- package/dist/improvedigitalBidAdapter.js +1 -1
- package/dist/inmarBidAdapter.js +1 -1
- package/dist/insticatorBidAdapter.js +1 -1
- package/dist/ixBidAdapter.js +1 -1
- package/dist/justpremiumBidAdapter.js +1 -1
- package/dist/konduitAnalyticsAdapter.js +1 -1
- package/dist/liveyieldAnalyticsAdapter.js +1 -1
- package/dist/logicadBidAdapter.js +1 -1
- package/dist/loglyliftBidAdapter.js +1 -1
- package/dist/malltvAnalyticsAdapter.js +1 -1
- package/dist/marsmediaBidAdapter.js +1 -1
- package/dist/mediafuseBidAdapter.js +1 -1
- package/dist/mediasquareBidAdapter.js +1 -1
- package/dist/mgidBidAdapter.js +1 -1
- package/dist/minutemediaBidAdapter.js +1 -1
- package/dist/mobfoxpbBidAdapter.js +1 -0
- package/dist/nextMillenniumBidAdapter.js +1 -1
- package/dist/nexx360BidAdapter.js +1 -1
- package/dist/not-for-prod/prebid.js +118 -117
- package/dist/oguryBidAdapter.js +1 -1
- package/dist/oneVideoBidAdapter.js +1 -1
- package/dist/onetagBidAdapter.js +1 -1
- package/dist/ooloAnalyticsAdapter.js +1 -1
- package/dist/otmBidAdapter.js +1 -1
- package/dist/outbrainBidAdapter.js +1 -1
- package/dist/parrableIdSystem.js +1 -1
- package/dist/pixfutureBidAdapter.js +1 -1
- package/dist/prebid-core.js +3 -3
- package/dist/prebidServerBidAdapter.js +1 -1
- package/dist/publinkIdSystem.js +1 -1
- package/dist/pubmaticBidAdapter.js +1 -1
- package/dist/pubwiseAnalyticsAdapter.js +1 -1
- package/dist/pxyzBidAdapter.js +1 -1
- package/dist/quantcastBidAdapter.js +1 -1
- package/dist/readpeakBidAdapter.js +1 -1
- package/dist/relaidoBidAdapter.js +1 -1
- package/dist/rhythmoneBidAdapter.js +1 -1
- package/dist/riseBidAdapter.js +1 -1
- package/dist/rubiconAnalyticsAdapter.js +1 -1
- package/dist/rubiconBidAdapter.js +1 -1
- package/dist/seedingAllianceBidAdapter.js +1 -1
- package/dist/seedtagBidAdapter.js +1 -1
- package/dist/sharethroughAnalyticsAdapter.js +1 -1
- package/dist/sharethroughBidAdapter.js +1 -1
- package/dist/smaatoBidAdapter.js +1 -1
- package/dist/smartadserverBidAdapter.js +1 -1
- package/dist/smartxBidAdapter.js +1 -1
- package/dist/smilewantedBidAdapter.js +1 -1
- package/dist/sonobiBidAdapter.js +1 -1
- package/dist/sortableBidAdapter.js +1 -1
- package/dist/sovrnAnalyticsAdapter.js +1 -1
- package/dist/sovrnBidAdapter.js +1 -1
- package/dist/sspBCBidAdapter.js +1 -1
- package/dist/sublimeBidAdapter.js +1 -1
- package/dist/synacormediaBidAdapter.js +1 -1
- package/dist/targetVideoBidAdapter.js +1 -1
- package/dist/teadsBidAdapter.js +1 -1
- package/dist/trionBidAdapter.js +1 -1
- package/dist/tripleliftBidAdapter.js +1 -1
- package/dist/trustxBidAdapter.js +1 -1
- package/dist/ttdBidAdapter.js +1 -1
- package/dist/ucfunnelAnalyticsAdapter.js +1 -1
- package/dist/underdogmediaBidAdapter.js +1 -1
- package/dist/undertoneBidAdapter.js +1 -1
- package/dist/vidazooBidAdapter.js +1 -1
- package/dist/videobyteBidAdapter.js +1 -1
- package/dist/visxBidAdapter.js +1 -1
- package/dist/vuukleBidAdapter.js +1 -1
- package/dist/widespaceBidAdapter.js +1 -1
- package/dist/winrBidAdapter.js +1 -1
- package/dist/yahoosspBidAdapter.js +1 -1
- package/dist/yieldmoBidAdapter.js +1 -1
- package/dist/yieldoneAnalyticsAdapter.js +1 -1
- package/modules/adomikAnalyticsAdapter.js +67 -43
- package/modules/adotBidAdapter.js +1 -1
- package/modules/apacdexBidAdapter.js +52 -41
- package/modules/audiencerunBidAdapter.js +75 -22
- package/modules/betweenBidAdapter.js +1 -1
- package/modules/cointrafficBidAdapter.js +1 -1
- package/modules/colossussspBidAdapter.js +5 -1
- package/modules/consentManagement.js +4 -4
- package/modules/consentManagementUsp.js +2 -2
- package/modules/e_volutionBidAdapter.js +19 -1
- package/modules/ftrackIdSystem.js +16 -2
- package/modules/ftrackIdSystem.md +12 -1
- package/modules/malltvAnalyticsAdapter.js +1 -1
- package/modules/mobfoxpbBidAdapter.js +135 -0
- package/modules/mobfoxpbBidAdapter.md +3 -3
- package/modules/nextMillenniumBidAdapter.js +6 -2
- package/modules/nexx360BidAdapter.js +14 -4
- package/modules/otmBidAdapter.js +43 -35
- package/modules/prebidServerBidAdapter/index.js +58 -14
- package/modules/pubmaticBidAdapter.js +34 -2
- package/modules/seedingAllianceBidAdapter.js +8 -4
- package/package.json +1 -1
- package/src/adapters/bidderFactory.js +17 -0
- package/src/auction.js +1 -7
- package/test/spec/auctionmanager_spec.js +2 -0
- package/test/spec/modules/adomikAnalyticsAdapter_spec.js +133 -33
- package/test/spec/modules/adotBidAdapter_spec.js +1 -1
- package/test/spec/modules/apacdexBidAdapter_spec.js +6 -6
- package/test/spec/modules/audiencerunBidAdapter_spec.js +185 -97
- package/test/spec/modules/cointrafficBidAdapter_spec.js +1 -1
- package/test/spec/modules/colossussspBidAdapter_spec.js +97 -3
- package/test/spec/modules/consentManagementUsp_spec.js +1 -0
- package/test/spec/modules/consentManagement_spec.js +22 -0
- package/test/spec/modules/e_volutionBidAdapter_spec.js +67 -10
- package/test/spec/modules/ftrackIdSystem_spec.js +75 -1
- package/test/spec/modules/mobfoxpbBidAdapter_spec.js +307 -0
- package/test/spec/modules/nexx360BidAdapter_spec.js +49 -0
- package/test/spec/modules/otmBidAdapter_spec.js +32 -11
- package/test/spec/modules/prebidServerBidAdapter_spec.js +200 -0
- package/test/spec/modules/pubmaticBidAdapter_spec.js +129 -0
- package/test/spec/unit/core/bidderFactory_spec.js +137 -0
|
@@ -2,7 +2,7 @@ import {expect} from 'chai';
|
|
|
2
2
|
import {spec} from '../../../modules/e_volutionBidAdapter.js';
|
|
3
3
|
|
|
4
4
|
describe('EvolutionTechBidAdapter', function () {
|
|
5
|
-
let
|
|
5
|
+
let bids = [{
|
|
6
6
|
bidId: '23fhj33i987f',
|
|
7
7
|
bidder: 'e_volution',
|
|
8
8
|
params: {
|
|
@@ -12,21 +12,55 @@ describe('EvolutionTechBidAdapter', function () {
|
|
|
12
12
|
banner: {
|
|
13
13
|
sizes: [[300, 250]],
|
|
14
14
|
}
|
|
15
|
+
},
|
|
16
|
+
userId: {
|
|
17
|
+
id5id: 'id5id'
|
|
18
|
+
}
|
|
19
|
+
}, {
|
|
20
|
+
bidId: '23fhj33i987f',
|
|
21
|
+
bidder: 'e_volution',
|
|
22
|
+
params: {
|
|
23
|
+
placementId: 0
|
|
24
|
+
},
|
|
25
|
+
mediaTypes: {
|
|
26
|
+
video: {
|
|
27
|
+
playerSize: [300, 250]
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
userId: {
|
|
31
|
+
id5id: 'id5id'
|
|
32
|
+
}
|
|
33
|
+
}, {
|
|
34
|
+
bidId: '23fhj33i987f',
|
|
35
|
+
bidder: 'e_volution',
|
|
36
|
+
params: {
|
|
37
|
+
placementId: 0
|
|
38
|
+
},
|
|
39
|
+
mediaTypes: {
|
|
40
|
+
native: {}
|
|
41
|
+
},
|
|
42
|
+
userId: {
|
|
43
|
+
id5id: 'id5id'
|
|
15
44
|
}
|
|
45
|
+
}];
|
|
46
|
+
|
|
47
|
+
const bidderRequest = {
|
|
48
|
+
uspConsent: 'uspConsent',
|
|
49
|
+
gdprConsent: 'gdprConsent'
|
|
16
50
|
};
|
|
17
51
|
|
|
18
52
|
describe('isBidRequestValid', function () {
|
|
19
53
|
it('Should return true if there are bidId, params and placementId parameters present', function () {
|
|
20
|
-
expect(spec.isBidRequestValid(
|
|
54
|
+
expect(spec.isBidRequestValid(bids[0])).to.be.true;
|
|
21
55
|
});
|
|
22
56
|
it('Should return false if at least one of parameters is not present', function () {
|
|
23
|
-
delete
|
|
24
|
-
expect(spec.isBidRequestValid(
|
|
57
|
+
delete bids[0].params.placementId;
|
|
58
|
+
expect(spec.isBidRequestValid(bids[0])).to.be.false;
|
|
25
59
|
});
|
|
26
60
|
});
|
|
27
61
|
|
|
28
62
|
describe('buildRequests', function () {
|
|
29
|
-
let serverRequest = spec.buildRequests(
|
|
63
|
+
let serverRequest = spec.buildRequests(bids, bidderRequest);
|
|
30
64
|
it('Creates a ServerRequest object with method, URL and data', function () {
|
|
31
65
|
expect(serverRequest).to.exist;
|
|
32
66
|
expect(serverRequest.method).to.exist;
|
|
@@ -42,18 +76,35 @@ describe('EvolutionTechBidAdapter', function () {
|
|
|
42
76
|
it('Returns valid data if array of bids is valid', function () {
|
|
43
77
|
let data = serverRequest.data;
|
|
44
78
|
expect(data).to.be.an('object');
|
|
45
|
-
expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements');
|
|
79
|
+
expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements', 'ccpa', 'gdpr');
|
|
46
80
|
expect(data.deviceWidth).to.be.a('number');
|
|
47
81
|
expect(data.deviceHeight).to.be.a('number');
|
|
48
82
|
expect(data.language).to.be.a('string');
|
|
49
83
|
expect(data.secure).to.be.within(0, 1);
|
|
50
84
|
expect(data.host).to.be.a('string');
|
|
51
85
|
expect(data.page).to.be.a('string');
|
|
86
|
+
expect(data.ccpa).to.be.equal('uspConsent');
|
|
87
|
+
expect(data.gdpr).to.be.equal('gdprConsent');
|
|
88
|
+
|
|
52
89
|
let placement = data['placements'][0];
|
|
53
|
-
expect(placement).to.have.keys('placementId', 'bidId', 'traffic', 'sizes', 'bidfloor');
|
|
90
|
+
expect(placement).to.have.keys('placementId', 'bidId', 'traffic', 'sizes', 'bidfloor', 'eids');
|
|
54
91
|
expect(placement.placementId).to.equal(0);
|
|
55
92
|
expect(placement.bidId).to.equal('23fhj33i987f');
|
|
56
93
|
expect(placement.traffic).to.equal('banner');
|
|
94
|
+
|
|
95
|
+
placement = data['placements'][1];
|
|
96
|
+
expect(placement).to.have.keys('placementId', 'bidId', 'traffic', 'bidfloor', 'eids', 'wPlayer', 'hPlayer',
|
|
97
|
+
'minduration', 'maxduration', 'mimes', 'protocols', 'startdelay', 'placement', 'skip', 'skipafter', 'minbitrate',
|
|
98
|
+
'maxbitrate', 'delivery', 'playbackmethod', 'api', 'linearity');
|
|
99
|
+
expect(placement.placementId).to.equal(0);
|
|
100
|
+
expect(placement.bidId).to.equal('23fhj33i987f');
|
|
101
|
+
expect(placement.traffic).to.equal('video');
|
|
102
|
+
|
|
103
|
+
placement = data['placements'][2];
|
|
104
|
+
expect(placement).to.have.keys('placementId', 'bidId', 'traffic', 'bidfloor', 'eids', 'native');
|
|
105
|
+
expect(placement.placementId).to.equal(0);
|
|
106
|
+
expect(placement.bidId).to.equal('23fhj33i987f');
|
|
107
|
+
expect(placement.traffic).to.equal('native');
|
|
57
108
|
});
|
|
58
109
|
it('Returns empty data if no valid requests are passed', function () {
|
|
59
110
|
serverRequest = spec.buildRequests([]);
|
|
@@ -76,7 +127,9 @@ describe('EvolutionTechBidAdapter', function () {
|
|
|
76
127
|
netRevenue: true,
|
|
77
128
|
currency: 'USD',
|
|
78
129
|
dealId: '1',
|
|
79
|
-
meta: {
|
|
130
|
+
meta: {
|
|
131
|
+
adomain: [ 'example.com' ]
|
|
132
|
+
}
|
|
80
133
|
}]
|
|
81
134
|
};
|
|
82
135
|
let bannerResponses = spec.interpretResponse(banner);
|
|
@@ -106,7 +159,9 @@ describe('EvolutionTechBidAdapter', function () {
|
|
|
106
159
|
netRevenue: true,
|
|
107
160
|
currency: 'USD',
|
|
108
161
|
dealId: '1',
|
|
109
|
-
meta: {
|
|
162
|
+
meta: {
|
|
163
|
+
adomain: [ 'example.com' ]
|
|
164
|
+
}
|
|
110
165
|
}]
|
|
111
166
|
};
|
|
112
167
|
let videoResponses = spec.interpretResponse(video);
|
|
@@ -139,7 +194,9 @@ describe('EvolutionTechBidAdapter', function () {
|
|
|
139
194
|
creativeId: '2',
|
|
140
195
|
netRevenue: true,
|
|
141
196
|
currency: 'USD',
|
|
142
|
-
meta: {
|
|
197
|
+
meta: {
|
|
198
|
+
adomain: [ 'example.com' ]
|
|
199
|
+
}
|
|
143
200
|
}]
|
|
144
201
|
};
|
|
145
202
|
let nativeResponses = spec.interpretResponse(native);
|
|
@@ -8,7 +8,11 @@ let server;
|
|
|
8
8
|
let configMock = {
|
|
9
9
|
name: 'ftrack',
|
|
10
10
|
params: {
|
|
11
|
-
url: 'https://d9.flashtalking.com/d9core'
|
|
11
|
+
url: 'https://d9.flashtalking.com/d9core',
|
|
12
|
+
ids: {
|
|
13
|
+
'device id': true,
|
|
14
|
+
'single device id': true
|
|
15
|
+
}
|
|
12
16
|
},
|
|
13
17
|
storage: {
|
|
14
18
|
name: 'ftrackId',
|
|
@@ -171,6 +175,76 @@ describe('FTRACK ID System', () => {
|
|
|
171
175
|
appendChildStub.restore();
|
|
172
176
|
});
|
|
173
177
|
|
|
178
|
+
describe(`should use the "ids" setting in the config:`, () => {
|
|
179
|
+
it(`should use default IDs if config.params.id is not populated`, () => {
|
|
180
|
+
let configMock1 = JSON.parse(JSON.stringify(configMock));
|
|
181
|
+
delete configMock1.params.ids;
|
|
182
|
+
ftrackIdSubmodule.getId(configMock1, null, null).callback();
|
|
183
|
+
|
|
184
|
+
expect(window.D9r).to.have.property('DeviceID', true);
|
|
185
|
+
expect(window.D9r).to.have.property('SingleDeviceID', true);
|
|
186
|
+
expect(window.D9r).to.not.have.property('HHID');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe(`should use correct ID settings if config.params.id is populated`, () => {
|
|
190
|
+
it(`- any ID set as strings should not be added to window.D9r`, () => {
|
|
191
|
+
let configMock1 = JSON.parse(JSON.stringify(configMock));
|
|
192
|
+
configMock1.params.ids['device id'] = 'test device ID';
|
|
193
|
+
configMock1.params.ids['single device id'] = 'test single device ID';
|
|
194
|
+
configMock1.params.ids['household id'] = 'test household ID';
|
|
195
|
+
ftrackIdSubmodule.getId(configMock1, null, null).callback();
|
|
196
|
+
|
|
197
|
+
expect(window.D9r).to.not.have.property('DeviceID');
|
|
198
|
+
expect(window.D9r).to.not.have.property('SingleDeviceID');
|
|
199
|
+
expect(window.D9r).to.not.have.property('HHID');
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
it(`- any ID set to false should not be added to window.D9r`, () => {
|
|
203
|
+
let configMock1 = JSON.parse(JSON.stringify(configMock));
|
|
204
|
+
configMock1.params.ids['device id'] = false;
|
|
205
|
+
configMock1.params.ids['single device id'] = false;
|
|
206
|
+
configMock1.params.ids['household id'] = false;
|
|
207
|
+
ftrackIdSubmodule.getId(configMock1, null, null).callback();
|
|
208
|
+
|
|
209
|
+
expect(window.D9r).to.not.have.property('DeviceID');
|
|
210
|
+
expect(window.D9r).to.not.have.property('SingleDeviceID');
|
|
211
|
+
expect(window.D9r).to.not.have.property('HHID');
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it(`- only device id`, () => {
|
|
215
|
+
let configMock1 = JSON.parse(JSON.stringify(configMock));
|
|
216
|
+
delete configMock1.params.ids['single device id'];
|
|
217
|
+
ftrackIdSubmodule.getId(configMock1, null, null).callback();
|
|
218
|
+
|
|
219
|
+
expect(window.D9r).to.have.property('DeviceID', true);
|
|
220
|
+
expect(window.D9r).to.not.have.property('SingleDeviceID');
|
|
221
|
+
expect(window.D9r).to.not.have.property('HHID');
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it(`- only single device id`, () => {
|
|
225
|
+
let configMock1 = JSON.parse(JSON.stringify(configMock));
|
|
226
|
+
delete configMock1.params.ids['device id'];
|
|
227
|
+
ftrackIdSubmodule.getId(configMock1, null, null).callback();
|
|
228
|
+
|
|
229
|
+
expect(window.D9r).to.not.have.property('DeviceID');
|
|
230
|
+
expect(window.D9r).to.have.property('SingleDeviceID', true);
|
|
231
|
+
expect(window.D9r).to.not.have.property('HHID');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it(`- only household ID`, () => {
|
|
235
|
+
let configMock1 = JSON.parse(JSON.stringify(configMock));
|
|
236
|
+
delete configMock1.params.ids['device id'];
|
|
237
|
+
delete configMock1.params.ids['single device id'];
|
|
238
|
+
configMock1.params.ids['household id'] = true;
|
|
239
|
+
ftrackIdSubmodule.getId(configMock1, null, null).callback();
|
|
240
|
+
|
|
241
|
+
expect(window.D9r).to.not.have.property('DeviceID');
|
|
242
|
+
expect(window.D9r).to.not.have.property('SingleDeviceID');
|
|
243
|
+
expect(window.D9r).to.have.property('HHID', true);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
})
|
|
247
|
+
|
|
174
248
|
it(`should populate localstorage and return the IDS (end-to-end test)`, () => {
|
|
175
249
|
let ftrackId,
|
|
176
250
|
ftrackIdExp,
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {spec} from '../../../modules/mobfoxpbBidAdapter.js';
|
|
3
|
+
import { BANNER, VIDEO, NATIVE } from '../../../src/mediaTypes.js';
|
|
4
|
+
|
|
5
|
+
describe('MobfoxHBBidAdapter', function () {
|
|
6
|
+
const bid = {
|
|
7
|
+
bidId: '23fhj33i987f',
|
|
8
|
+
bidder: 'mobfoxpb',
|
|
9
|
+
mediaTypes: {
|
|
10
|
+
[BANNER]: {
|
|
11
|
+
sizes: [[300, 250]]
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
params: {
|
|
15
|
+
placementId: 783,
|
|
16
|
+
traffic: BANNER
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const bidderRequest = {
|
|
21
|
+
refererInfo: {
|
|
22
|
+
referer: 'test.com'
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
describe('isBidRequestValid', function () {
|
|
27
|
+
it('Should return true if there are bidId, params and key parameters present', function () {
|
|
28
|
+
expect(spec.isBidRequestValid(bid)).to.be.true;
|
|
29
|
+
});
|
|
30
|
+
it('Should return false if at least one of parameters is not present', function () {
|
|
31
|
+
delete bid.params.placementId;
|
|
32
|
+
expect(spec.isBidRequestValid(bid)).to.be.false;
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe('buildRequests', function () {
|
|
37
|
+
let serverRequest = spec.buildRequests([bid], bidderRequest);
|
|
38
|
+
it('Creates a ServerRequest object with method, URL and data', function () {
|
|
39
|
+
expect(serverRequest).to.exist;
|
|
40
|
+
expect(serverRequest.method).to.exist;
|
|
41
|
+
expect(serverRequest.url).to.exist;
|
|
42
|
+
expect(serverRequest.data).to.exist;
|
|
43
|
+
});
|
|
44
|
+
it('Returns POST method', function () {
|
|
45
|
+
expect(serverRequest.method).to.equal('POST');
|
|
46
|
+
});
|
|
47
|
+
it('Returns valid URL', function () {
|
|
48
|
+
expect(serverRequest.url).to.equal('https://bes.mobfox.com/pbjs');
|
|
49
|
+
});
|
|
50
|
+
it('Returns valid data if array of bids is valid', function () {
|
|
51
|
+
let data = serverRequest.data;
|
|
52
|
+
expect(data).to.be.an('object');
|
|
53
|
+
expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements');
|
|
54
|
+
expect(data.deviceWidth).to.be.a('number');
|
|
55
|
+
expect(data.deviceHeight).to.be.a('number');
|
|
56
|
+
expect(data.language).to.be.a('string');
|
|
57
|
+
expect(data.secure).to.be.within(0, 1);
|
|
58
|
+
expect(data.host).to.be.a('string');
|
|
59
|
+
expect(data.page).to.be.a('string');
|
|
60
|
+
expect(data.gdpr).to.not.exist;
|
|
61
|
+
expect(data.ccpa).to.not.exist;
|
|
62
|
+
let placement = data['placements'][0];
|
|
63
|
+
expect(placement).to.have.keys('placementId', 'bidId', 'traffic', 'sizes', 'schain', 'bidfloor');
|
|
64
|
+
expect(placement.placementId).to.equal(783);
|
|
65
|
+
expect(placement.bidId).to.equal('23fhj33i987f');
|
|
66
|
+
expect(placement.traffic).to.equal(BANNER);
|
|
67
|
+
expect(placement.schain).to.be.an('object');
|
|
68
|
+
expect(placement.sizes).to.be.an('array');
|
|
69
|
+
expect(placement.bidfloor).to.equal(0);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('Returns valid data for mediatype video', function () {
|
|
73
|
+
const playerSize = [300, 300];
|
|
74
|
+
bid.mediaTypes = {};
|
|
75
|
+
bid.params.traffic = VIDEO;
|
|
76
|
+
bid.mediaTypes[VIDEO] = {
|
|
77
|
+
playerSize
|
|
78
|
+
};
|
|
79
|
+
serverRequest = spec.buildRequests([bid], bidderRequest);
|
|
80
|
+
let data = serverRequest.data;
|
|
81
|
+
expect(data).to.be.an('object');
|
|
82
|
+
let placement = data['placements'][0];
|
|
83
|
+
expect(placement).to.be.an('object');
|
|
84
|
+
expect(placement).to.have.keys('placementId', 'bidId', 'traffic', 'playerSize', 'wPlayer', 'hPlayer', 'schain', 'bidfloor',
|
|
85
|
+
'minduration', 'maxduration', 'mimes', 'protocols', 'startdelay', 'placement',
|
|
86
|
+
'skip', 'skipafter', 'minbitrate', 'maxbitrate', 'delivery', 'playbackmethod', 'api', 'linearity');
|
|
87
|
+
expect(placement.traffic).to.equal(VIDEO);
|
|
88
|
+
expect(placement.wPlayer).to.equal(playerSize[0]);
|
|
89
|
+
expect(placement.hPlayer).to.equal(playerSize[1]);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('Returns valid data for mediatype native', function () {
|
|
93
|
+
const native = {
|
|
94
|
+
title: {
|
|
95
|
+
required: true
|
|
96
|
+
},
|
|
97
|
+
body: {
|
|
98
|
+
required: true
|
|
99
|
+
},
|
|
100
|
+
icon: {
|
|
101
|
+
required: true,
|
|
102
|
+
size: [64, 64]
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
bid.mediaTypes = {};
|
|
107
|
+
bid.params.traffic = NATIVE;
|
|
108
|
+
bid.mediaTypes[NATIVE] = native;
|
|
109
|
+
serverRequest = spec.buildRequests([bid], bidderRequest);
|
|
110
|
+
let data = serverRequest.data;
|
|
111
|
+
expect(data).to.be.an('object');
|
|
112
|
+
let placement = data['placements'][0];
|
|
113
|
+
expect(placement).to.be.an('object');
|
|
114
|
+
expect(placement).to.have.keys('placementId', 'bidId', 'traffic', 'native', 'schain', 'bidfloor');
|
|
115
|
+
expect(placement.traffic).to.equal(NATIVE);
|
|
116
|
+
expect(placement.native).to.equal(native);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('Returns data with gdprConsent and without uspConsent', function () {
|
|
120
|
+
bidderRequest.gdprConsent = 'test';
|
|
121
|
+
serverRequest = spec.buildRequests([bid], bidderRequest);
|
|
122
|
+
let data = serverRequest.data;
|
|
123
|
+
expect(data.gdpr).to.exist;
|
|
124
|
+
expect(data.gdpr).to.be.a('string');
|
|
125
|
+
expect(data.gdpr).to.equal(bidderRequest.gdprConsent);
|
|
126
|
+
expect(data.ccpa).to.not.exist;
|
|
127
|
+
delete bidderRequest.gdprConsent;
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('Returns data with uspConsent and without gdprConsent', function () {
|
|
131
|
+
bidderRequest.uspConsent = 'test';
|
|
132
|
+
serverRequest = spec.buildRequests([bid], bidderRequest);
|
|
133
|
+
let data = serverRequest.data;
|
|
134
|
+
expect(data.ccpa).to.exist;
|
|
135
|
+
expect(data.ccpa).to.be.a('string');
|
|
136
|
+
expect(data.ccpa).to.equal(bidderRequest.uspConsent);
|
|
137
|
+
expect(data.gdpr).to.not.exist;
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('Returns empty data if no valid requests are passed', function () {
|
|
141
|
+
serverRequest = spec.buildRequests([]);
|
|
142
|
+
let data = serverRequest.data;
|
|
143
|
+
expect(data.placements).to.be.an('array').that.is.empty;
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
describe('interpretResponse', function () {
|
|
147
|
+
it('Should interpret banner response', function () {
|
|
148
|
+
const banner = {
|
|
149
|
+
body: [{
|
|
150
|
+
mediaType: 'banner',
|
|
151
|
+
width: 300,
|
|
152
|
+
height: 250,
|
|
153
|
+
cpm: 0.4,
|
|
154
|
+
ad: 'Test',
|
|
155
|
+
requestId: '23fhj33i987f',
|
|
156
|
+
ttl: 120,
|
|
157
|
+
creativeId: '2',
|
|
158
|
+
netRevenue: true,
|
|
159
|
+
currency: 'USD',
|
|
160
|
+
dealId: '1'
|
|
161
|
+
}]
|
|
162
|
+
};
|
|
163
|
+
let bannerResponses = spec.interpretResponse(banner);
|
|
164
|
+
expect(bannerResponses).to.be.an('array').that.is.not.empty;
|
|
165
|
+
let dataItem = bannerResponses[0];
|
|
166
|
+
expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId',
|
|
167
|
+
'netRevenue', 'currency', 'dealId', 'mediaType', 'meta');
|
|
168
|
+
expect(dataItem.requestId).to.equal('23fhj33i987f');
|
|
169
|
+
expect(dataItem.cpm).to.equal(0.4);
|
|
170
|
+
expect(dataItem.width).to.equal(300);
|
|
171
|
+
expect(dataItem.height).to.equal(250);
|
|
172
|
+
expect(dataItem.ad).to.equal('Test');
|
|
173
|
+
expect(dataItem.ttl).to.equal(120);
|
|
174
|
+
expect(dataItem.creativeId).to.equal('2');
|
|
175
|
+
expect(dataItem.netRevenue).to.be.true;
|
|
176
|
+
expect(dataItem.currency).to.equal('USD');
|
|
177
|
+
});
|
|
178
|
+
it('Should interpret video response', function () {
|
|
179
|
+
const video = {
|
|
180
|
+
body: [{
|
|
181
|
+
vastUrl: 'test.com',
|
|
182
|
+
mediaType: 'video',
|
|
183
|
+
cpm: 0.5,
|
|
184
|
+
requestId: '23fhj33i987f',
|
|
185
|
+
ttl: 120,
|
|
186
|
+
creativeId: '2',
|
|
187
|
+
netRevenue: true,
|
|
188
|
+
currency: 'USD',
|
|
189
|
+
dealId: '1'
|
|
190
|
+
}]
|
|
191
|
+
};
|
|
192
|
+
let videoResponses = spec.interpretResponse(video);
|
|
193
|
+
expect(videoResponses).to.be.an('array').that.is.not.empty;
|
|
194
|
+
|
|
195
|
+
let dataItem = videoResponses[0];
|
|
196
|
+
expect(dataItem).to.have.all.keys('requestId', 'cpm', 'vastUrl', 'ttl', 'creativeId',
|
|
197
|
+
'netRevenue', 'currency', 'dealId', 'mediaType', 'meta');
|
|
198
|
+
expect(dataItem.requestId).to.equal('23fhj33i987f');
|
|
199
|
+
expect(dataItem.cpm).to.equal(0.5);
|
|
200
|
+
expect(dataItem.vastUrl).to.equal('test.com');
|
|
201
|
+
expect(dataItem.ttl).to.equal(120);
|
|
202
|
+
expect(dataItem.creativeId).to.equal('2');
|
|
203
|
+
expect(dataItem.netRevenue).to.be.true;
|
|
204
|
+
expect(dataItem.currency).to.equal('USD');
|
|
205
|
+
});
|
|
206
|
+
it('Should interpret native response', function () {
|
|
207
|
+
const native = {
|
|
208
|
+
body: [{
|
|
209
|
+
mediaType: 'native',
|
|
210
|
+
native: {
|
|
211
|
+
clickUrl: 'test.com',
|
|
212
|
+
title: 'Test',
|
|
213
|
+
image: 'test.com',
|
|
214
|
+
impressionTrackers: ['test.com'],
|
|
215
|
+
},
|
|
216
|
+
ttl: 120,
|
|
217
|
+
cpm: 0.4,
|
|
218
|
+
requestId: '23fhj33i987f',
|
|
219
|
+
creativeId: '2',
|
|
220
|
+
netRevenue: true,
|
|
221
|
+
currency: 'USD',
|
|
222
|
+
}]
|
|
223
|
+
};
|
|
224
|
+
let nativeResponses = spec.interpretResponse(native);
|
|
225
|
+
expect(nativeResponses).to.be.an('array').that.is.not.empty;
|
|
226
|
+
|
|
227
|
+
let dataItem = nativeResponses[0];
|
|
228
|
+
expect(dataItem).to.have.keys('requestId', 'cpm', 'ttl', 'creativeId', 'netRevenue', 'currency', 'mediaType', 'native', 'meta');
|
|
229
|
+
expect(dataItem.native).to.have.keys('clickUrl', 'impressionTrackers', 'title', 'image')
|
|
230
|
+
expect(dataItem.requestId).to.equal('23fhj33i987f');
|
|
231
|
+
expect(dataItem.cpm).to.equal(0.4);
|
|
232
|
+
expect(dataItem.native.clickUrl).to.equal('test.com');
|
|
233
|
+
expect(dataItem.native.title).to.equal('Test');
|
|
234
|
+
expect(dataItem.native.image).to.equal('test.com');
|
|
235
|
+
expect(dataItem.native.impressionTrackers).to.be.an('array').that.is.not.empty;
|
|
236
|
+
expect(dataItem.native.impressionTrackers[0]).to.equal('test.com');
|
|
237
|
+
expect(dataItem.ttl).to.equal(120);
|
|
238
|
+
expect(dataItem.creativeId).to.equal('2');
|
|
239
|
+
expect(dataItem.netRevenue).to.be.true;
|
|
240
|
+
expect(dataItem.currency).to.equal('USD');
|
|
241
|
+
});
|
|
242
|
+
it('Should return an empty array if invalid banner response is passed', function () {
|
|
243
|
+
const invBanner = {
|
|
244
|
+
body: [{
|
|
245
|
+
width: 300,
|
|
246
|
+
cpm: 0.4,
|
|
247
|
+
ad: 'Test',
|
|
248
|
+
requestId: '23fhj33i987f',
|
|
249
|
+
ttl: 120,
|
|
250
|
+
creativeId: '2',
|
|
251
|
+
netRevenue: true,
|
|
252
|
+
currency: 'USD',
|
|
253
|
+
dealId: '1'
|
|
254
|
+
}]
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
let serverResponses = spec.interpretResponse(invBanner);
|
|
258
|
+
expect(serverResponses).to.be.an('array').that.is.empty;
|
|
259
|
+
});
|
|
260
|
+
it('Should return an empty array if invalid video response is passed', function () {
|
|
261
|
+
const invVideo = {
|
|
262
|
+
body: [{
|
|
263
|
+
mediaType: 'video',
|
|
264
|
+
cpm: 0.5,
|
|
265
|
+
requestId: '23fhj33i987f',
|
|
266
|
+
ttl: 120,
|
|
267
|
+
creativeId: '2',
|
|
268
|
+
netRevenue: true,
|
|
269
|
+
currency: 'USD',
|
|
270
|
+
dealId: '1'
|
|
271
|
+
}]
|
|
272
|
+
};
|
|
273
|
+
let serverResponses = spec.interpretResponse(invVideo);
|
|
274
|
+
expect(serverResponses).to.be.an('array').that.is.empty;
|
|
275
|
+
});
|
|
276
|
+
it('Should return an empty array if invalid native response is passed', function () {
|
|
277
|
+
const invNative = {
|
|
278
|
+
body: [{
|
|
279
|
+
mediaType: 'native',
|
|
280
|
+
clickUrl: 'test.com',
|
|
281
|
+
title: 'Test',
|
|
282
|
+
impressionTrackers: ['test.com'],
|
|
283
|
+
ttl: 120,
|
|
284
|
+
requestId: '23fhj33i987f',
|
|
285
|
+
creativeId: '2',
|
|
286
|
+
netRevenue: true,
|
|
287
|
+
currency: 'USD',
|
|
288
|
+
}]
|
|
289
|
+
};
|
|
290
|
+
let serverResponses = spec.interpretResponse(invNative);
|
|
291
|
+
expect(serverResponses).to.be.an('array').that.is.empty;
|
|
292
|
+
});
|
|
293
|
+
it('Should return an empty array if invalid response is passed', function () {
|
|
294
|
+
const invalid = {
|
|
295
|
+
body: [{
|
|
296
|
+
ttl: 120,
|
|
297
|
+
creativeId: '2',
|
|
298
|
+
netRevenue: true,
|
|
299
|
+
currency: 'USD',
|
|
300
|
+
dealId: '1'
|
|
301
|
+
}]
|
|
302
|
+
};
|
|
303
|
+
let serverResponses = spec.interpretResponse(invalid);
|
|
304
|
+
expect(serverResponses).to.be.an('array').that.is.empty;
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
});
|
|
@@ -146,6 +146,37 @@ describe('Nexx360 bid adapter tests', function () {
|
|
|
146
146
|
}]
|
|
147
147
|
},
|
|
148
148
|
};
|
|
149
|
+
|
|
150
|
+
it('We verify isBidRequestValid with uncorrect bidfloorCurrency', function() {
|
|
151
|
+
const bid = { params: {
|
|
152
|
+
'account': '1067',
|
|
153
|
+
'tagId': 'luvxjvgn',
|
|
154
|
+
'bidfloorCurrency': 'AAA',
|
|
155
|
+
}};
|
|
156
|
+
expect(spec.isBidRequestValid(bid)).to.be.equal(false);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('We verify isBidRequestValid with uncorrect bidfloor', function() {
|
|
160
|
+
const bid = { params: {
|
|
161
|
+
'account': '1067',
|
|
162
|
+
'tagId': 'luvxjvgn',
|
|
163
|
+
'bidfloorCurrency': 'EUR',
|
|
164
|
+
'bidfloor': 'EUR',
|
|
165
|
+
}};
|
|
166
|
+
expect(spec.isBidRequestValid(bid)).to.be.equal(false);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('We verify isBidRequestValid with uncorrect keywords', function() {
|
|
170
|
+
const bid = { params: {
|
|
171
|
+
'account': '1067',
|
|
172
|
+
'tagId': 'luvxjvgn',
|
|
173
|
+
'bidfloorCurrency': 'EUR',
|
|
174
|
+
'bidfloor': 0.8,
|
|
175
|
+
'keywords': 'test',
|
|
176
|
+
}};
|
|
177
|
+
expect(spec.isBidRequestValid(bid)).to.be.equal(false);
|
|
178
|
+
});
|
|
179
|
+
|
|
149
180
|
it('Verify banner build request', function () {
|
|
150
181
|
const request = spec.buildRequests(DISPLAY_BID_REQUEST, DEFAULT_OPTIONS);
|
|
151
182
|
expect(request).to.have.property('url').and.to.equal('https://fast.nexx360.io/prebid');
|
|
@@ -162,6 +193,24 @@ describe('Nexx360 bid adapter tests', function () {
|
|
|
162
193
|
expect(requestContent.adUnits[0]).to.have.property('auctionId').and.to.equal('05e0a3a1-9f57-41f6-bbcb-2ba9c9e3d2d5');
|
|
163
194
|
expect(requestContent.adUnits[0]).to.have.property('mediatypes').exist;
|
|
164
195
|
expect(requestContent.adUnits[0].mediatypes).to.have.property('banner').exist;
|
|
196
|
+
expect(requestContent.adUnits[0]).to.have.property('bidfloor').and.to.equal(0);
|
|
197
|
+
expect(requestContent.adUnits[0]).to.have.property('bidfloorCurrency').and.to.equal('USD');
|
|
198
|
+
expect(requestContent.adUnits[0]).to.have.property('keywords');
|
|
199
|
+
expect(requestContent.adUnits[0].keywords.length).to.be.eql(0);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('We add bidfloor and keywords', function() {
|
|
203
|
+
const DISPLAY_BID_REQUEST_2 = [ ...DISPLAY_BID_REQUEST ];
|
|
204
|
+
DISPLAY_BID_REQUEST_2[0].params.keywords = { interest: 'cars' };
|
|
205
|
+
DISPLAY_BID_REQUEST_2[0].params.bidfloor = 2.1;
|
|
206
|
+
const request = spec.buildRequests(DISPLAY_BID_REQUEST, DEFAULT_OPTIONS);
|
|
207
|
+
const requestContent = JSON.parse(request.data);
|
|
208
|
+
expect(requestContent.adUnits[0]).to.have.property('bidfloor').and.to.equal(2.1);
|
|
209
|
+
expect(requestContent.adUnits[0]).to.have.property('bidfloorCurrency').and.to.equal('USD');
|
|
210
|
+
expect(requestContent.adUnits[0]).to.have.property('keywords');
|
|
211
|
+
expect(requestContent.adUnits[0].keywords.length).to.be.eql(1);
|
|
212
|
+
expect(requestContent.adUnits[0].keywords[0].key).to.be.eql('interest');
|
|
213
|
+
expect(requestContent.adUnits[0].keywords[0].value[0]).to.be.eql('cars');
|
|
165
214
|
});
|
|
166
215
|
|
|
167
216
|
it('Verify banner parse response', function () {
|
|
@@ -2,7 +2,7 @@ import {expect} from 'chai';
|
|
|
2
2
|
import {spec} from 'modules/otmBidAdapter';
|
|
3
3
|
|
|
4
4
|
describe('otmBidAdapter', function () {
|
|
5
|
-
it('
|
|
5
|
+
it('pub_params', function () {
|
|
6
6
|
expect(spec.isBidRequestValid({
|
|
7
7
|
bidder: 'otm',
|
|
8
8
|
params: {
|
|
@@ -12,31 +12,52 @@ describe('otmBidAdapter', function () {
|
|
|
12
12
|
})).to.equal(true);
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
-
it('
|
|
16
|
-
|
|
15
|
+
it('generated_params common case', function () {
|
|
16
|
+
const bidRequestData = [{
|
|
17
17
|
bidId: 'bid1234',
|
|
18
18
|
bidder: 'otm',
|
|
19
19
|
params: {
|
|
20
20
|
tid: '123',
|
|
21
|
-
bidfloor: 20
|
|
21
|
+
bidfloor: 20,
|
|
22
|
+
domain: 'github.com'
|
|
22
23
|
},
|
|
23
24
|
sizes: [[240, 400]]
|
|
24
25
|
}];
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
const request = spec.buildRequests(bidRequestData);
|
|
28
|
+
const req_data = request[0].data;
|
|
28
29
|
|
|
29
30
|
expect(req_data.bidid).to.equal('bid1234');
|
|
31
|
+
expect(req_data.domain).to.equal('github.com');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('generated_params should return top level origin as domain if not defined', function () {
|
|
35
|
+
const bidRequestData = [{
|
|
36
|
+
bidId: 'bid1234',
|
|
37
|
+
bidder: 'otm',
|
|
38
|
+
params: {
|
|
39
|
+
tid: '123',
|
|
40
|
+
bidfloor: 20
|
|
41
|
+
},
|
|
42
|
+
sizes: [[240, 400]]
|
|
43
|
+
}];
|
|
44
|
+
|
|
45
|
+
const bidderRequest = {refererInfo: {referer: `https://github.com:3000/`}}
|
|
46
|
+
|
|
47
|
+
const request = spec.buildRequests(bidRequestData, bidderRequest);
|
|
48
|
+
const req_data = request[0].data;
|
|
49
|
+
|
|
50
|
+
expect(req_data.domain).to.equal(`github.com:3000`);
|
|
30
51
|
});
|
|
31
52
|
|
|
32
|
-
it('
|
|
33
|
-
|
|
53
|
+
it('response_params common case', function () {
|
|
54
|
+
const bidRequestData = {
|
|
34
55
|
data: {
|
|
35
56
|
bidId: 'bid1234'
|
|
36
57
|
}
|
|
37
58
|
};
|
|
38
59
|
|
|
39
|
-
|
|
60
|
+
const serverResponse = {
|
|
40
61
|
body: [
|
|
41
62
|
{
|
|
42
63
|
'auctionid': '3c6f8e22-541b-485c-9214-e974d9fb1b6f',
|
|
@@ -53,9 +74,9 @@ describe('otmBidAdapter', function () {
|
|
|
53
74
|
]
|
|
54
75
|
};
|
|
55
76
|
|
|
56
|
-
|
|
77
|
+
const bids = spec.interpretResponse(serverResponse, bidRequestData);
|
|
57
78
|
expect(bids).to.have.lengthOf(1);
|
|
58
|
-
|
|
79
|
+
const bid = bids[0];
|
|
59
80
|
expect(bid.cpm).to.equal(847.097);
|
|
60
81
|
expect(bid.currency).to.equal('RUB');
|
|
61
82
|
expect(bid.width).to.equal(240);
|