diff --git a/adapters.json b/adapters.json index e9a65ac4fa6..89a3c3f66be 100644 --- a/adapters.json +++ b/adapters.json @@ -54,6 +54,7 @@ "vertoz", "widespace", "admixer", + "atomx", "tapsense", { "appnexus": { diff --git a/integrationExamples/gpt/pbjs_example_gpt.html b/integrationExamples/gpt/pbjs_example_gpt.html index 19f4e6cc8a0..5f3b25e1303 100644 --- a/integrationExamples/gpt/pbjs_example_gpt.html +++ b/integrationExamples/gpt/pbjs_example_gpt.html @@ -249,6 +249,12 @@ params: { zone: '2eb6bd58-865c-47ce-af7f-a918108c3fd2' // REQUIRED zone oid } + }, + { + bidder: 'atomx', + params: { + id: 7395 + } } ] }, { diff --git a/src/adapters/atomx.js b/src/adapters/atomx.js new file mode 100644 index 00000000000..4935382123a --- /dev/null +++ b/src/adapters/atomx.js @@ -0,0 +1,75 @@ +var CONSTANTS = require('../constants.json'); +var bidfactory = require('../bidfactory.js'); +var bidmanager = require('../bidmanager.js'); +var adloader = require('src/adloader.js'); +var Ajax = require('../ajax'); +var utils = require('../utils.js'); + +/** + * Adapter for requesting bids from Atomx. + * + * @returns {{callBids: _callBids, responseCallback: _responseCallback}} + */ +var AtomxAdapter = function AtomxAdapter() { + function _callBids(data) { + if (!window.atomx_prebid) { + adloader.loadScript(window.location.protocol + '//s.ato.mx/b.js', function() { _bid(data); }, true); + } else { + _bid(data); + } + } + + function _bid(data) { + var url = window.atomx_prebid(); + var bids = data.bids || []; + for (var i = 0, ln = bids.length; i < ln; i++) { + var bid = bids[i]; + if (bid.params && bid.params.id) { + Ajax.ajax(url, _responseCallback.bind(this, bid), { + id: bid.params.id, + size: utils.parseSizesInput(bid.sizes)[0], + prebid: bid.placementCode + }, {method: 'GET'}); + } else { + var bidObject = bidfactory.createBid(CONSTANTS.STATUS.NO_BID, bid); + bidObject.bidderCode = 'atomx'; + bidmanager.addBidResponse(bid.placementCode, bidObject); + } + } + } + + function _responseCallback(bid, data) { + var bidObject; + try { + data = JSON.parse(data); + + if (data.cpm && data.cpm > 0) { + bidObject = bidfactory.createBid(CONSTANTS.STATUS.GOOD, bid); + bidObject.bidderCode = 'atomx'; + bidObject.cpm = data.cpm * 1000; + if (data.adm) { + bidObject.ad = data.adm; + } else { + bidObject.adUrl = data.url; + } + bidObject.width = data.width; + bidObject.height = data.height; + bidmanager.addBidResponse(bid.placementCode, bidObject); + return; + } + } catch (_error) { + utils.logError(_error); + } + + bidObject = bidfactory.createBid(CONSTANTS.STATUS.NO_BID, bid); + bidObject.bidderCode = 'atomx'; + bidmanager.addBidResponse(bid.placementCode, bidObject); + } + + return { + callBids: _callBids, + responseCallback: _responseCallback + }; +}; + +module.exports = AtomxAdapter; diff --git a/test/spec/adapters/atomx_spec.js b/test/spec/adapters/atomx_spec.js new file mode 100644 index 00000000000..fb4bdc83f1b --- /dev/null +++ b/test/spec/adapters/atomx_spec.js @@ -0,0 +1,151 @@ +window.pbjs = window.pbjs || {}; +var chai = require('chai'); +var Adapter = require('src/adapters/atomx')(); +var Ajax = require('src/ajax'); +var adLoader = require('src/adloader'); +var bidmanager = require('src/bidmanager.js'); +var CONSTANTS = require('src/constants.json'); + +describe('Atomx adapter', function () { + var validData_1 = { + bids: [ + { + bidder: 'atomx', + bidId: 'bid_id', + params: {id: 1234}, + placementCode: 'ad-unit-1', + sizes: [[300, 250],[800, 600]] + } + ] + }; + var validData_2 = { + bids: [ + { + bidder: 'adtomx', + bidId: 'bid_id', + params: {id: 5678}, + placementCode: 'ad-unit-1', + sizes: [300, 250] + } + ] + }; + + var invalidData = { + bids: [ + { + bidder: 'atomx', + bidId: 'bid_id', + params: {}, + placementCode: 'ad-unit-1', + sizes: [[300, 250]] + } + ] + }; + + var responseWithAd = JSON.stringify({ + 'cpm': 2.2, + 'url': 'http://p.ato.mx/placement?id=1234', + 'width': 300, + 'height': 250, + 'code': 'ad-unit-1' + }); + var responseWithoutAd = JSON.stringify({ + 'cpm': 0, + 'url': 'http://p.ato.mx/placement?id=1234', + 'width': 300, + 'height': 250, + 'code': 'ad-unit-1' + }); + + var responseEmpty = ''; + var validJsonParams = { + id: '1234', + prebid: 'ad-unit-1', + size: '300x250' + }; + + describe('loads the tag code', function() { + var stubLoadScript = sinon.stub(adLoader, "loadScript"); + Adapter.callBids(validData_1); + sinon.assert.calledOnce(stubLoadScript); + let url = stubLoadScript.firstCall.args[0]; + let callback = stubLoadScript.firstCall.args[1]; + expect(url).to.equal('http://s.ato.mx/b.js'); + expect(callback).to.be.a('function'); + }); + describe('bid request with valid data', function () { + var stubAjax; + beforeEach(function () { + window.atomx_prebid = function() { + return '/placement'; + }; + stubAjax = sinon.stub(Ajax, 'ajax'); + }); + afterEach(function () { + stubAjax.restore(); + }); + it('bid request should be called. sizes style -> [[],[]]', function () { + Adapter.callBids(validData_1); + sinon.assert.calledOnce(stubAjax); + }); + it('bid request should be called. sizes style -> []', function () { + Adapter.callBids(validData_2); + sinon.assert.calledOnce(stubAjax); + }); + it('ajax params should be matched', function () { + Adapter.callBids(validData_1); + sinon.assert.calledWith(stubAjax, sinon.match('/placement', function () { + }, validJsonParams, {method: "GET"})); + }); + }); + describe('bid request with invalid data', function () { + var addBidResponse, stubAjax; + beforeEach(function () { + window.atomx_prebid = function() { + return '/placement'; + }; + addBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + stubAjax = sinon.stub(Ajax, 'ajax'); + }); + afterEach(function () { + addBidResponse.restore(); + stubAjax.restore(); + }); + it('ajax shouldn\'t be called', function () { + Adapter.callBids(invalidData); + sinon.assert.notCalled(stubAjax); + }); + it('bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID + '"', function () { + Adapter.callBids(invalidData); + expect(addBidResponse.firstCall.args[1].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + expect(addBidResponse.firstCall.args[1].bidderCode).to.equal('atomx'); + }); + }); + describe('bid response', function () { + var addBidResponse; + beforeEach(function () { + addBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + }); + afterEach(function () { + addBidResponse.restore(); + }); + it('with ad. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.GOOD + '"', function () { + Adapter.responseCallback(validData_1.bids[0], responseWithAd); + var arg = addBidResponse.firstCall.args[1]; + expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(arg.bidderCode).to.equal('atomx'); + }); + it('without ad. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID, function () { + Adapter.responseCallback(validData_1.bids[0], responseWithoutAd); + var arg = addBidResponse.firstCall.args[1]; + expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + expect(arg.bidderCode).to.equal('atomx'); + }); + it('empty. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID, function () { + Adapter.responseCallback(validData_1.bids[0], responseEmpty); + var arg = addBidResponse.firstCall.args[1]; + expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + expect(arg.bidderCode).to.equal('atomx'); + }) + }); +});