diff --git a/modules/lassoBidAdapter.js b/modules/lassoBidAdapter.js new file mode 100644 index 00000000000..b2f3ccf9a7c --- /dev/null +++ b/modules/lassoBidAdapter.js @@ -0,0 +1,133 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { ajax } from '../src/ajax.js'; +import { config } from '../src/config.js'; + +const BIDDER_CODE = 'lasso'; +const ENDPOINT_URL = 'https://trc.lhmos.com/prebid'; +const GET_IUD_URL = 'https://secure.adnxs.com/getuid?'; +const COOKIE_NAME = 'aim-xr'; +const storage = getStorageManager({bidderCode: BIDDER_CODE}); + +export const spec = { + code: BIDDER_CODE, + isBidRequestValid: function(bid) { + return !!(bid.params && bid.params.adUnitId); + }, + + buildRequests: function(validBidRequests, bidderRequest) { + if (validBidRequests.length === 0) { + return []; + } + + let aimXR = ''; + if (storage.cookiesAreEnabled) { + aimXR = storage.getCookie(COOKIE_NAME, undefined); + } + + return validBidRequests.map(bidRequest => { + let sizes = [] + if (bidRequest.mediaTypes && bidRequest.mediaTypes[BANNER] && bidRequest.mediaTypes[BANNER].sizes) { + sizes = bidRequest.mediaTypes[BANNER].sizes; + } + + const payload = { + auctionStart: bidderRequest.auctionStart, + url: encodeURIComponent(window.location.href), + bidderRequestId: bidRequest.bidderRequestId, + adUnitCode: bidRequest.adUnitCode, + auctionId: bidRequest.auctionId, + bidId: bidRequest.bidId, + transactionId: bidRequest.transactionId, + device: JSON.stringify(getDeviceData()), + sizes, + aimXR, + uid: '$UID', + params: JSON.stringify(bidRequest.params), + crumbs: JSON.stringify(bidRequest.crumbs), + prebidVersion: '$prebid.version$', + version: 1, + coppa: config.getConfig('coppa') == true ? 1 : 0, + ccpa: bidderRequest.uspConsent || undefined + } + + return { + method: 'GET', + url: getBidRequestUrl(aimXR), + data: payload, + options: { + withCredentials: false + }, + }; + }); + }, + + interpretResponse: function(serverResponse) { + const response = serverResponse && serverResponse.body; + const bidResponses = []; + + if (!response) { + return bidResponses; + } + + const bidResponse = { + requestId: response.bidid, + cpm: response.bid.price, + currency: response.cur, + width: response.bid.w, + height: response.bid.h, + creativeId: response.bid.crid, + netRevenue: response.netRevenue, + ttl: response.ttl, + ad: response.bid.ad, + mediaType: response.bid.mediaType, + meta: { + secondaryCatIds: response.bid.cat, + advertiserDomains: response.bid.advertiserDomains, + advertiserName: response.meta.advertiserName, + mediaType: response.bid.mediaType + } + }; + bidResponses.push(bidResponse); + return bidResponses; + }, + + onTimeout: function(timeoutData) { + if (timeoutData === null) { + return; + } + ajax(ENDPOINT_URL + '/timeout', null, JSON.stringify(timeoutData), { + method: 'POST', + withCredentials: false + }); + }, + + onBidWon: function(bid) { + ajax(ENDPOINT_URL + '/won', null, JSON.stringify(bid), { + method: 'POST', + withCredentials: false + }); + }, + + supportedMediaTypes: [BANNER] +} + +function getBidRequestUrl(aimXR) { + if (!aimXR) { + return GET_IUD_URL + ENDPOINT_URL + '/request'; + } + return ENDPOINT_URL + '/request' +} + +function getDeviceData() { + const win = window.top; + return { + ua: navigator.userAgent, + width: win.innerWidth || win.document.documentElement.clientWidth || win.document.body.clientWidth, + height: win.innerHeight || win.document.documentElement.clientHeight || win.document.body.clientHeight, + browserLanguage: navigator.language, + } +} + +registerBidder(spec); diff --git a/modules/lassoBidAdapter.md b/modules/lassoBidAdapter.md new file mode 100644 index 00000000000..43927fe890c --- /dev/null +++ b/modules/lassoBidAdapter.md @@ -0,0 +1,29 @@ +# Overview + +**Module Name**: Lasso Bidder Adapter +**Module Type**: Bidder Adapter +**Maintainer**: headerbidding@lassomarketing.io + +# Description + +Connects to Lasso demand source to fetch bids. +Only banner format supported. + +# Test Parameters + +``` +var adUnits = [{ + code: 'banner-ad-unit', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [{ + bidder: 'lasso', + params: { + adUnitId: '0' + } + }] +}]; +``` diff --git a/test/spec/modules/lassoBidAdapter_spec.js b/test/spec/modules/lassoBidAdapter_spec.js new file mode 100644 index 00000000000..5825927a931 --- /dev/null +++ b/test/spec/modules/lassoBidAdapter_spec.js @@ -0,0 +1,177 @@ +import { expect } from 'chai'; +import { spec } from 'modules/lassoBidAdapter.js'; +import { server } from '../../mocks/xhr'; + +const ENDPOINT_URL = 'https://trc.lhmos.com/prebid'; + +const bid = { + bidder: 'lasso', + params: { + adUnitId: 123456 + }, + auctionStart: Date.now(), + adUnitCode: 'adunit-code', + auctionId: 'cfa6f46d-4584-46e1-9c00-54769abb51e3', + bidderRequestId: 'a123b456c789d', + bidId: '123a456b789', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + sizes: [[300, 250]], + src: 'client', + transactionId: '26740296-0111-4b7a-80df-7196823026f4' +}; + +const bidderRequest = { + auctionId: 'cfa6f46d-4584-46e1-9c00-54769abb51e3', + auctionStart: Date.now(), + start: Date.now(), + biddeCode: 'lasso', + bidderRequestId: 'a123b456c789d', + bids: [bid], + timeout: 10000 +}; + +describe('lassoBidAdapter', function () { + describe('All needed functions are available', function() { + it(`isBidRequestValid is present and type function`, function () { + expect(spec.isBidRequestValid).to.exist.and.to.be.a('function') + }); + + it(`buildRequests is present and type function`, function () { + expect(spec.buildRequests).to.exist.and.to.be.a('function') + }); + + it(`interpretResponse is present and type function`, function () { + expect(spec.interpretResponse).to.exist.and.to.be.a('function') + }); + + it(`onTimeout is present and type function`, function () { + expect(spec.onTimeout).to.exist.and.to.be.a('function') + }); + + it(`onBidWon is present and type function`, function () { + expect(spec.onBidWon).to.exist.and.to.be.a('function') + }); + }); + + describe('isBidRequestValid', function () { + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + it('should return true when there are extra params', function () { + const bid = Object.assign({}, bid, { + params: { + adUnitId: 123456, + zone: 1, + publisher: 'test' + } + }) + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + it('should return false when there are no params', function () { + const invalidBid = { ...bid }; + delete invalidBid.params; + expect(spec.isBidRequestValid(invalidBid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + const validBidRequests = spec.buildRequests([bid], bidderRequest); + expect(validBidRequests).to.be.an('array').that.is.not.empty; + + const bidRequest = validBidRequests[0]; + + it('Returns valid bidRequest', function () { + expect(bidRequest).to.exist; + expect(bidRequest.method).to.exist; + expect(bidRequest.url).to.exist; + expect(bidRequest.data).to.exist; + }); + + it('Returns GET method', function() { + expect(bidRequest.method).to.exist; + expect(bidRequest.method).to.equal('GET'); + }); + }); + + describe('interpretResponse', function () { + let serverResponse = { + body: { + bidid: '123456789', + id: '33302780340222111', + bid: { + price: 1, + w: 728, + h: 90, + crid: 123456, + ad: '', + mediaType: 'banner' + }, + meta: { + cat: ['1', '2', '3', '4'], + advertiserDomains: ['lassomarketing.io'], + advertiserName: 'Lasso' + }, + cur: 'USD', + netRevenue: false, + ttl: 300, + } + }; + + it('should get the correct bid response', function () { + let expectedResponse = { + requestId: '123456789', + cpm: 1, + currency: 'USD', + width: 728, + height: 90, + creativeId: 123456, + netRevenue: false, + ttl: 300, + ad: '', + mediaType: 'banner', + meta: { + secondaryCatIds: ['1', '2', '3', '4'], + advertiserDomains: ['lassomarketing.io'], + advertiserName: 'Lasso', + mediaType: 'banner' + } + }; + let result = spec.interpretResponse(serverResponse); + expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse)); + }); + }); + + describe('onTimeout', () => { + it('should send timeout', () => { + const timeoutData = { + bidder: 'lasso', + auctionId: 'cfa6f46d-4584-46e1-9c00-54769abb51e3', + dUnitCode: 'adunit-code', + bidId: '123a456b789', + params: { + adUnitId: 123456, + }, + timeout: 3000 + }; + spec.onTimeout(timeoutData); + + expect(server.requests[0].method).to.equal('POST'); + expect(server.requests[0].url).to.equal(ENDPOINT_URL + '/timeout'); + expect(JSON.parse(server.requests[0].requestBody)).to.deep.equal(timeoutData); + }); + }); + + describe('onBidWon', () => { + it('should send bid won request', () => { + spec.onBidWon(bid); + + expect(server.requests[0].method).to.equal('POST'); + expect(server.requests[0].url).to.equal(ENDPOINT_URL + '/won'); + expect(JSON.parse(server.requests[0].requestBody)).to.deep.equal(bid); + }); + }); +});