From 8acb398329837f76bc4aee557a5d7b6320535b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=A8=E7=94=B0=20=E6=84=9B=E4=B8=80=E9=83=8E?= Date: Tue, 8 Jan 2019 18:20:43 +0900 Subject: [PATCH 1/5] add open8 adapter --- modules/open8BidAdapter.js | 152 +++++++++++++++++ modules/open8BidAdapter.md | 48 ++++++ test/spec/modules/open8BidAdapter_spec.js | 195 ++++++++++++++++++++++ 3 files changed, 395 insertions(+) create mode 100644 modules/open8BidAdapter.js create mode 100644 modules/open8BidAdapter.md create mode 100644 test/spec/modules/open8BidAdapter_spec.js diff --git a/modules/open8BidAdapter.js b/modules/open8BidAdapter.js new file mode 100644 index 00000000000..6dd0eb7aa9a --- /dev/null +++ b/modules/open8BidAdapter.js @@ -0,0 +1,152 @@ +import { Renderer } from 'src/Renderer'; +import * as utils from 'src/utils'; +import { registerBidder } from 'src/adapters/bidderFactory'; +import { VIDEO, BANNER } from 'src/mediaTypes'; + +const BIDDER_CODE = 'open8'; +const URL = '//as.vt.open8.com/v1/control/prebid'; +const AD_TYPE = { + VIDEO: 1, + BANNER: 2 +}; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [VIDEO, BANNER], + + isBidRequestValid: function(bid) { + return !!(bid.params.slotId); + }, + + buildRequests: function(validBidRequests, bidderRequest) { + var requests = []; + for (var i = 0; i < validBidRequests.length; i++) { + var bid = validBidRequests[i]; + var queryString = ''; + var slotId = utils.getBidIdParameter('slotId', bid.params); + queryString = utils.tryAppendQueryString(queryString, 'slot_id', slotId); + queryString = utils.tryAppendQueryString(queryString, 'imp_id', Math.random()); + queryString = utils.tryAppendQueryString(queryString, 'bid_id', bid.bidId); + + requests.push({ + method: 'GET', + url: URL, + data: queryString + }); + } + return requests; + }, + + interpretResponse: function(serverResponse, request) { + var bidderResponse = serverResponse.body; + + if (!bidderResponse.isAdReturn) { + return []; + } + + var ad = bidderResponse.ad; + + const bid = { + slotId: bidderResponse.slotId, + userId: bidderResponse.userId, + impId: bidderResponse.impId, + media: bidderResponse.media, + requestId: ad.bidId, + cpm: ad.price, + creativeId: ad.creativeId, + dealId: ad.dealId, + currency: ad.currency || 'JPY', + netRevenue: true, // TODO + ttl: 360, // 6 minutes + } + + if (ad.adType === AD_TYPE.VIDEO) { + const videoAd = bidderResponse.ad.video; + Object.assign(bid, { + vastXml: videoAd.vastXml, + width: videoAd.w, + height: videoAd.h, + renderer: newRenderer(bidderResponse), + adResponse: bidderResponse, + mediaType: VIDEO + }); + } else if (ad.adType === AD_TYPE.BANNER) { + const bannerAd = bidderResponse.ad.banner; + Object.assign(bid, { + width: bannerAd.w, + height: bannerAd.h, + ad: bannerAd.adm, + mediaType: BANNER + }); + try { + bannerAd.imps.forEach(impTrackUrl => { + const tracker = utils.createTrackPixelHtml(impTrackUrl); + bid.ad += tracker; + }); + } catch (error) { + utils.logError('Error appending imp tracking pixel', error); + } + } + return [bid]; + }, + + getUserSyncs: function(syncOptions, serverResponses) { + const syncs = []; + if (syncOptions.iframeEnabled && serverResponses.length) { + const syncIFs = serverResponses[0].body.syncIFs; + if (syncIFs) { + syncIFs.forEach(sync => { + syncs.push({ + type: 'iframe', + url: sync + }); + }); + } + } + if (syncOptions.pixelEnabled && serverResponses.length) { + const syncPixs = serverResponses[0].body.syncPixels; + if (syncPixs) { + syncPixs.forEach(sync => { + syncs.push({ + type: 'image', + url: sync + }); + }); + } + } + return syncs; + }, +} + +function newRenderer(bidderResponse) { + const renderer = Renderer.install({ + id: bidderResponse.ad.bidId, + url: bidderResponse.ad.video.purl, + loaded: false, + }); + + try { + renderer.setRender(outstreamRender); + } catch (err) { + utils.logWarn('Prebid Error calling setRender on newRenderer', err); + } + + return renderer; +} + +function outstreamRender(bid) { + bid.renderer.push(() => { + window.o8.renderAd({ + vastXml: bid.vastXml, + adUnitCode: bid.adUnitCode, + slotId: bid.slotId, + impId: bid.impId, + userId: bid.userId, + media: bid.media, + adResponse: bid.adResponse, + mediaType: bid.mediaType + }); + }); +} + +registerBidder(spec); diff --git a/modules/open8BidAdapter.md b/modules/open8BidAdapter.md new file mode 100644 index 00000000000..6a0fd54142c --- /dev/null +++ b/modules/open8BidAdapter.md @@ -0,0 +1,48 @@ +# Overview + +**Module Name**: Innity Bidder Adapter +**Module Type**: Bidder Adapter +**Maintainer**: engtat@innity.com + + # Description + +Innity Bidder Adapter for Prebid.js. + +# Test Parameters +``` +var adUnits = [ + // Banner adUnit + { + code: 'banner-div', + mediaTypes: { + banner: { + sizes: [ + [300, 250] + ], + } + }, + bids: [{ + bidder: 'open8', + params: { + slotId: 4 + } + }] + }, + // Video outstream adUnit + { + code: 'video-outstream', + sizes: [[300, 250]], + mediaTypes: { + video: { + context: 'outstream' + } + }, + bids: [{ + bidder: 'open8', + params: { + slotId: 2 + } + }] + }]; + +``` \ No newline at end of file diff --git a/test/spec/modules/open8BidAdapter_spec.js b/test/spec/modules/open8BidAdapter_spec.js new file mode 100644 index 00000000000..81fee823354 --- /dev/null +++ b/test/spec/modules/open8BidAdapter_spec.js @@ -0,0 +1,195 @@ +import { spec } from 'modules/open8BidAdapter'; +import { newBidder } from 'src/adapters/bidderFactory'; + +const ENDPOINT = '//as.vt.open8.com/v1/control/prebid'; + +describe('Open8Adapter', function() { + const adapter = newBidder(spec); + + describe('isBidRequestValid', function() { + let bid = { + 'bidder': 'open8', + 'params': { + 'slotId': '123456' + }, + 'adUnitCode': 'adunit', + 'sizes': [[300, 250]], + 'bidId': 'bidid1234', + 'bidderRequestId': 'requestid1234', + 'auctionId': 'auctionid1234', + }; + + it('should return true when required params found', function() { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when required params are not passed', function() { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = { + ' slotId': 0 + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', function() { + let bidRequests = [ + { + 'bidder': 'open8', + 'params': { + 'slotId': '123456' + }, + 'adUnitCode': 'adunit', + 'sizes': [[300, 250]], + 'bidId': 'bidid1234', + 'bidderRequestId': 'requestid1234', + 'auctionId': 'auctionid1234', + } + ]; + + it('sends bid request to ENDPOINT via GET', function() { + const requests = spec.buildRequests(bidRequests); + expect(requests[0].url).to.equal(ENDPOINT); + expect(requests[0].method).to.equal('GET'); + }); + }); + describe('interpretResponse', function() { + let response = { + slotId: 2, + userId: 'userid1234', + impId: 0.9876543, + media: 'TEST_MEDIA', + isAdReturn: true, + syncPixels: ['https://open8test.blob.core.windows.net/public/dbm/dotimage.gif'], // ['https://cm.g.doubleclick.net/pixel?google_nid=open8_dbm&google_cm&google_sc'], + syncIFs: [], + ad: { + bidId: 'TEST_BID_ID', + price: 1234.56, + creativeId: 'creativeid1234', + dealId: 'TEST_DEAL_ID', + currency: 'JPY', + adType: 2, + banner: { + w: 300, + h: 250, + adm: '
', + imps: [ + '//example.com/imp' + ] + } + } + }; + + it('should get correct banner bid response', function() { + let expectedResponse = [ + { + 'slotId': 2, + 'userId': 'userid1234', + 'impId': 0.9876543, + 'media': 'TEST_MEDIA', + 'requestId': 'requestid1234', + 'cpm': 1234.56, + 'creativeId': 'creativeid1234', + 'dealId': 'TEST_DEAL_ID', + 'width': 300, + 'height': 250, + 'ad': "
", + 'mediaType': 'banner', + 'currency': 'JPY', + 'ttl': 360, + 'netRevenue': true + } + ]; + + let bidderRequest; + let result = spec.interpretResponse({ body: response }, { bidderRequest }); + expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); + }); + + it('handles video responses', function() { + let response = { + slotId: 2, + userId: 'userid1234', + impId: Math.random(), + media: 'TEST_MEDIA', + isAdReturn: true, + syncPixels: ['https://open8test.blob.core.windows.net/public/dbm/dotimage.gif'], // ['https://cm.g.doubleclick.net/pixel?google_nid=open8_dbm&google_cm&google_sc'], + syncIFs: [], + ad: { + bidId: 'TEST_BID_ID', + price: 1234.56, + creativeId: 'creativeid1234', + dealId: 'TEST_DEAL_ID', + currency: 'JPY', + adType: 1, + video: { + purl: 'https://open8test.blob.core.windows.net/public/dbm/prebid-bigoverlay.js', + vastXml: '', + w: 320, + h: 180 + }, + } + }; + + let bidderRequest; + let result = spec.interpretResponse({ body: response }, { bidderRequest }); + expect(result[0]).to.have.property('vastXml'); + expect(result[0]).to.have.property('renderer'); + expect(result[0]).to.have.property('mediaType', 'video'); + }); + + it('handles nobid responses', function() { + let response = { + isAdReturn: false, + 'ad': {} + }; + + let bidderRequest; + let result = spec.interpretResponse({ body: response }, { bidderRequest }); + expect(result.length).to.equal(0); + }); + }); + + describe('getUserSyncs', function() { + const bidResponse1 = { + body: { + 'isAdReturn': true, + 'ad': { /* ad body */ }, + 'syncPixels': [ + 'https://example.test/1' + ] + } + }; + + const bidResponse2 = { + body: { + 'isAdReturn': true, + 'ad': { /* ad body */ }, + 'syncPixels': [ + 'https://example.test/2' + ] + } + }; + + it('should use a sync url from first response', function() { + const syncs = spec.getUserSyncs({ pixelEnabled: true }, [bidResponse1, bidResponse2]); + expect(syncs).to.deep.equal([ + { + type: 'image', + url: 'https://example.test/1' + } + ]); + }); + + it('handle empty response (e.g. timeout)', function() { + const syncs = spec.getUserSyncs({ pixelEnabled: true }, []); + expect(syncs).to.deep.equal([]); + }); + + it('returns empty syncs when not enabled', function() { + const syncs = spec.getUserSyncs({ pixelEnabled: false }, [bidResponse1]); + expect(syncs).to.deep.equal([]); + }); + }); +}); From ce8a726abda6dd9b098b544239338fafe6565dbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=A8=E7=94=B0=20=E6=84=9B=E4=B8=80=E9=83=8E?= Date: Fri, 18 Jan 2019 19:09:52 +0900 Subject: [PATCH 2/5] slotkey and fix --- modules/open8BidAdapter.js | 273 ++++++++------- modules/open8BidAdapter.md | 8 +- test/spec/modules/open8BidAdapter_spec.js | 407 ++++++++++++---------- 3 files changed, 366 insertions(+), 322 deletions(-) diff --git a/modules/open8BidAdapter.js b/modules/open8BidAdapter.js index 6dd0eb7aa9a..6b4629f911e 100644 --- a/modules/open8BidAdapter.js +++ b/modules/open8BidAdapter.js @@ -6,147 +6,158 @@ import { VIDEO, BANNER } from 'src/mediaTypes'; const BIDDER_CODE = 'open8'; const URL = '//as.vt.open8.com/v1/control/prebid'; const AD_TYPE = { - VIDEO: 1, - BANNER: 2 + VIDEO: 1, + BANNER: 2 }; export const spec = { - code: BIDDER_CODE, - supportedMediaTypes: [VIDEO, BANNER], - - isBidRequestValid: function(bid) { - return !!(bid.params.slotId); - }, - - buildRequests: function(validBidRequests, bidderRequest) { - var requests = []; - for (var i = 0; i < validBidRequests.length; i++) { - var bid = validBidRequests[i]; - var queryString = ''; - var slotId = utils.getBidIdParameter('slotId', bid.params); - queryString = utils.tryAppendQueryString(queryString, 'slot_id', slotId); - queryString = utils.tryAppendQueryString(queryString, 'imp_id', Math.random()); - queryString = utils.tryAppendQueryString(queryString, 'bid_id', bid.bidId); - - requests.push({ - method: 'GET', - url: URL, - data: queryString - }); - } - return requests; - }, - - interpretResponse: function(serverResponse, request) { - var bidderResponse = serverResponse.body; - - if (!bidderResponse.isAdReturn) { - return []; - } - - var ad = bidderResponse.ad; - - const bid = { - slotId: bidderResponse.slotId, - userId: bidderResponse.userId, - impId: bidderResponse.impId, - media: bidderResponse.media, - requestId: ad.bidId, - cpm: ad.price, - creativeId: ad.creativeId, - dealId: ad.dealId, - currency: ad.currency || 'JPY', - netRevenue: true, // TODO - ttl: 360, // 6 minutes - } - - if (ad.adType === AD_TYPE.VIDEO) { - const videoAd = bidderResponse.ad.video; - Object.assign(bid, { - vastXml: videoAd.vastXml, - width: videoAd.w, - height: videoAd.h, - renderer: newRenderer(bidderResponse), - adResponse: bidderResponse, - mediaType: VIDEO - }); - } else if (ad.adType === AD_TYPE.BANNER) { - const bannerAd = bidderResponse.ad.banner; - Object.assign(bid, { - width: bannerAd.w, - height: bannerAd.h, - ad: bannerAd.adm, - mediaType: BANNER - }); - try { - bannerAd.imps.forEach(impTrackUrl => { - const tracker = utils.createTrackPixelHtml(impTrackUrl); - bid.ad += tracker; - }); - } catch (error) { - utils.logError('Error appending imp tracking pixel', error); - } - } - return [bid]; - }, - - getUserSyncs: function(syncOptions, serverResponses) { - const syncs = []; - if (syncOptions.iframeEnabled && serverResponses.length) { - const syncIFs = serverResponses[0].body.syncIFs; - if (syncIFs) { - syncIFs.forEach(sync => { - syncs.push({ - type: 'iframe', - url: sync - }); - }); - } - } - if (syncOptions.pixelEnabled && serverResponses.length) { - const syncPixs = serverResponses[0].body.syncPixels; - if (syncPixs) { - syncPixs.forEach(sync => { - syncs.push({ - type: 'image', - url: sync - }); - }); - } - } - return syncs; - }, + code: BIDDER_CODE, + supportedMediaTypes: [VIDEO, BANNER], + + isBidRequestValid: function(bid) { + return !!(bid.params.slotKey); + }, + + buildRequests: function(validBidRequests, bidderRequest) { + var requests = []; + for (var i = 0; i < validBidRequests.length; i++) { + var bid = validBidRequests[i]; + var queryString = ''; + var slotKey = utils.getBidIdParameter('slotKey', bid.params); + queryString = utils.tryAppendQueryString(queryString, 'slot_key', slotKey); + queryString = utils.tryAppendQueryString(queryString, 'imp_id', generateImpId()); + queryString = utils.tryAppendQueryString(queryString, 'bid_id', bid.bidId); + + requests.push({ + method: 'GET', + url: URL, + data: queryString + }); + } + return requests; + }, + + interpretResponse: function(serverResponse, request) { + var bidderResponse = serverResponse.body; + + if (!bidderResponse.isAdReturn) { + return []; + } + + var ad = bidderResponse.ad; + + const bid = { + slotKey: bidderResponse.slotKey, + userId: bidderResponse.userId, + impId: bidderResponse.impId, + media: bidderResponse.media, + requestId: ad.bidId, + cpm: ad.price, + creativeId: ad.creativeId, + dealId: ad.dealId, + currency: ad.currency || 'JPY', + netRevenue: true, // TODO + ttl: 360, // 6 minutes + } + + if (ad.adType === AD_TYPE.VIDEO) { + const videoAd = bidderResponse.ad.video; + Object.assign(bid, { + vastXml: videoAd.vastXml, + width: videoAd.w, + height: videoAd.h, + renderer: newRenderer(bidderResponse), + adResponse: bidderResponse, + mediaType: VIDEO + }); + } else if (ad.adType === AD_TYPE.BANNER) { + const bannerAd = bidderResponse.ad.banner; + Object.assign(bid, { + width: bannerAd.w, + height: bannerAd.h, + ad: bannerAd.adm, + mediaType: BANNER + }); + try { + bannerAd.imps.forEach(impTrackUrl => { + const tracker = utils.createTrackPixelHtml(impTrackUrl); + bid.ad += tracker; + }); + } catch (error) { + utils.logError('Error appending imp tracking pixel', error); + } + } + return [bid]; + }, + + getUserSyncs: function(syncOptions, serverResponses) { + const syncs = []; + if (syncOptions.iframeEnabled && serverResponses.length) { + const syncIFs = serverResponses[0].body.syncIFs; + if (syncIFs) { + syncIFs.forEach(sync => { + syncs.push({ + type: 'iframe', + url: sync + }); + }); + } + } + if (syncOptions.pixelEnabled && serverResponses.length) { + const syncPixs = serverResponses[0].body.syncPixels; + if (syncPixs) { + syncPixs.forEach(sync => { + syncs.push({ + type: 'image', + url: sync + }); + }); + } + } + return syncs; + }, +} + +function generateImpId() { + var l = 16; + var c = 'abcdefghijklmnopqrstuvwsyz0123456789'; + var cl = c.length; + var r = ''; + for (var i = 0; i < l; i++) { + r += c[Math.floor(Math.random() * cl)]; + } + return r; } function newRenderer(bidderResponse) { - const renderer = Renderer.install({ - id: bidderResponse.ad.bidId, - url: bidderResponse.ad.video.purl, - loaded: false, - }); - - try { - renderer.setRender(outstreamRender); - } catch (err) { - utils.logWarn('Prebid Error calling setRender on newRenderer', err); - } - - return renderer; + const renderer = Renderer.install({ + id: bidderResponse.ad.bidId, + url: bidderResponse.ad.video.purl, + loaded: false, + }); + + try { + renderer.setRender(outstreamRender); + } catch (err) { + utils.logWarn('Prebid Error calling setRender on newRenderer', err); + } + + return renderer; } function outstreamRender(bid) { - bid.renderer.push(() => { - window.o8.renderAd({ - vastXml: bid.vastXml, - adUnitCode: bid.adUnitCode, - slotId: bid.slotId, - impId: bid.impId, - userId: bid.userId, - media: bid.media, - adResponse: bid.adResponse, - mediaType: bid.mediaType - }); + bid.renderer.push(() => { + window.op8.renderPrebid({ + vastXml: bid.vastXml, + adUnitCode: bid.adUnitCode, + slotKey: bid.slotKey, + impId: bid.impId, + userId: bid.userId, + media: bid.media, + adResponse: bid.adResponse, + mediaType: bid.mediaType }); + }); } registerBidder(spec); diff --git a/modules/open8BidAdapter.md b/modules/open8BidAdapter.md index 6a0fd54142c..b7d7204bfb7 100644 --- a/modules/open8BidAdapter.md +++ b/modules/open8BidAdapter.md @@ -24,14 +24,16 @@ var adUnits = [ bids: [{ bidder: 'open8', params: { - slotId: 4 + slotKey: '504c2e89' } }] }, // Video outstream adUnit { code: 'video-outstream', - sizes: [[300, 250]], + sizes: [ + [640, 360] + ], mediaTypes: { video: { context: 'outstream' @@ -40,7 +42,7 @@ var adUnits = [ bids: [{ bidder: 'open8', params: { - slotId: 2 + slotKey: '2ae5a533' } }] }]; diff --git a/test/spec/modules/open8BidAdapter_spec.js b/test/spec/modules/open8BidAdapter_spec.js index 81fee823354..06b55850ca3 100644 --- a/test/spec/modules/open8BidAdapter_spec.js +++ b/test/spec/modules/open8BidAdapter_spec.js @@ -4,192 +4,223 @@ import { newBidder } from 'src/adapters/bidderFactory'; const ENDPOINT = '//as.vt.open8.com/v1/control/prebid'; describe('Open8Adapter', function() { - const adapter = newBidder(spec); - - describe('isBidRequestValid', function() { - let bid = { - 'bidder': 'open8', - 'params': { - 'slotId': '123456' - }, - 'adUnitCode': 'adunit', - 'sizes': [[300, 250]], - 'bidId': 'bidid1234', - 'bidderRequestId': 'requestid1234', - 'auctionId': 'auctionid1234', - }; - - it('should return true when required params found', function() { - expect(spec.isBidRequestValid(bid)).to.equal(true); - }); - - it('should return false when required params are not passed', function() { - let bid = Object.assign({}, bid); - delete bid.params; - bid.params = { - ' slotId': 0 - }; - expect(spec.isBidRequestValid(bid)).to.equal(false); - }); - }); - - describe('buildRequests', function() { - let bidRequests = [ - { - 'bidder': 'open8', - 'params': { - 'slotId': '123456' - }, - 'adUnitCode': 'adunit', - 'sizes': [[300, 250]], - 'bidId': 'bidid1234', - 'bidderRequestId': 'requestid1234', - 'auctionId': 'auctionid1234', - } - ]; - - it('sends bid request to ENDPOINT via GET', function() { - const requests = spec.buildRequests(bidRequests); - expect(requests[0].url).to.equal(ENDPOINT); - expect(requests[0].method).to.equal('GET'); - }); - }); - describe('interpretResponse', function() { - let response = { - slotId: 2, - userId: 'userid1234', - impId: 0.9876543, - media: 'TEST_MEDIA', - isAdReturn: true, - syncPixels: ['https://open8test.blob.core.windows.net/public/dbm/dotimage.gif'], // ['https://cm.g.doubleclick.net/pixel?google_nid=open8_dbm&google_cm&google_sc'], - syncIFs: [], - ad: { - bidId: 'TEST_BID_ID', - price: 1234.56, - creativeId: 'creativeid1234', - dealId: 'TEST_DEAL_ID', - currency: 'JPY', - adType: 2, - banner: { - w: 300, - h: 250, - adm: '
', - imps: [ - '//example.com/imp' - ] - } - } - }; - - it('should get correct banner bid response', function() { - let expectedResponse = [ - { - 'slotId': 2, - 'userId': 'userid1234', - 'impId': 0.9876543, - 'media': 'TEST_MEDIA', - 'requestId': 'requestid1234', - 'cpm': 1234.56, - 'creativeId': 'creativeid1234', - 'dealId': 'TEST_DEAL_ID', - 'width': 300, - 'height': 250, - 'ad': "
", - 'mediaType': 'banner', - 'currency': 'JPY', - 'ttl': 360, - 'netRevenue': true - } - ]; - - let bidderRequest; - let result = spec.interpretResponse({ body: response }, { bidderRequest }); - expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); - }); - - it('handles video responses', function() { - let response = { - slotId: 2, - userId: 'userid1234', - impId: Math.random(), - media: 'TEST_MEDIA', - isAdReturn: true, - syncPixels: ['https://open8test.blob.core.windows.net/public/dbm/dotimage.gif'], // ['https://cm.g.doubleclick.net/pixel?google_nid=open8_dbm&google_cm&google_sc'], - syncIFs: [], - ad: { - bidId: 'TEST_BID_ID', - price: 1234.56, - creativeId: 'creativeid1234', - dealId: 'TEST_DEAL_ID', - currency: 'JPY', - adType: 1, - video: { - purl: 'https://open8test.blob.core.windows.net/public/dbm/prebid-bigoverlay.js', - vastXml: '', - w: 320, - h: 180 - }, - } - }; - - let bidderRequest; - let result = spec.interpretResponse({ body: response }, { bidderRequest }); - expect(result[0]).to.have.property('vastXml'); - expect(result[0]).to.have.property('renderer'); - expect(result[0]).to.have.property('mediaType', 'video'); - }); - - it('handles nobid responses', function() { - let response = { - isAdReturn: false, - 'ad': {} - }; - - let bidderRequest; - let result = spec.interpretResponse({ body: response }, { bidderRequest }); - expect(result.length).to.equal(0); - }); - }); - - describe('getUserSyncs', function() { - const bidResponse1 = { - body: { - 'isAdReturn': true, - 'ad': { /* ad body */ }, - 'syncPixels': [ - 'https://example.test/1' - ] - } - }; - - const bidResponse2 = { - body: { - 'isAdReturn': true, - 'ad': { /* ad body */ }, - 'syncPixels': [ - 'https://example.test/2' - ] - } - }; - - it('should use a sync url from first response', function() { - const syncs = spec.getUserSyncs({ pixelEnabled: true }, [bidResponse1, bidResponse2]); - expect(syncs).to.deep.equal([ - { - type: 'image', - url: 'https://example.test/1' - } - ]); - }); - - it('handle empty response (e.g. timeout)', function() { - const syncs = spec.getUserSyncs({ pixelEnabled: true }, []); - expect(syncs).to.deep.equal([]); - }); - - it('returns empty syncs when not enabled', function() { - const syncs = spec.getUserSyncs({ pixelEnabled: false }, [bidResponse1]); - expect(syncs).to.deep.equal([]); - }); - }); + const adapter = newBidder(spec); + + describe('isBidRequestValid', function() { + let bid = { + 'bidder': 'open8', + 'params': { + 'slotKey': 'slotkey1234' + }, + 'adUnitCode': 'adunit', + 'sizes': [[300, 250]], + 'bidId': 'bidid1234', + 'bidderRequestId': 'requestid1234', + 'auctionId': 'auctionid1234', + }; + + it('should return true when required params found', function() { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when required params are not passed', function() { + bid.params = { + ' slotKey': 0 + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', function() { + let bidRequests = [ + { + 'bidder': 'open8', + 'params': { + 'slotKey': 'slotkey1234' + }, + 'adUnitCode': 'adunit', + 'sizes': [[300, 250]], + 'bidId': 'bidid1234', + 'bidderRequestId': 'requestid1234', + 'auctionId': 'auctionid1234', + } + ]; + + it('sends bid request to ENDPOINT via GET', function() { + const requests = spec.buildRequests(bidRequests); + expect(requests[0].url).to.equal(ENDPOINT); + expect(requests[0].method).to.equal('GET'); + }); + }); + describe('interpretResponse', function() { + const bannerResponse = { + slotKey: 'slotkey1234', + userId: 'userid1234', + impId: 'impid1234', + media: 'TEST_MEDIA', + isAdReturn: true, + syncPixels: ['//example/sync/pixel.gif'], + syncIFs: [], + ad: { + bidId: 'TEST_BID_ID', + price: 1234.56, + creativeId: 'creativeid1234', + dealId: 'TEST_DEAL_ID', + currency: 'JPY', + adType: 2, + banner: { + w: 300, + h: 250, + adm: '
', + imps: ['//example.com/imp'] + } + } + }; + const videoResponse = { + slotKey: 'slotkey1234', + userId: 'userid1234', + impId: 'impid1234', + media: 'TEST_MEDIA', + isAdReturn: true, + syncPixels: ['//example/sync/pixel.gif'], + syncIFs: [], + ad: { + bidId: 'TEST_BID_ID', + price: 1234.56, + creativeId: 'creativeid1234', + dealId: 'TEST_DEAL_ID', + currency: 'JPY', + adType: 1, + video: { + purl: '//playerexample.js', + vastXml: '', + w: 320, + h: 180 + }, + } + }; + + it('should get correct banner bid response', function() { + let expectedResponse = [{ + 'slotKey': 'slotkey1234', + 'userId': 'userid1234', + 'impId': 'impid1234', + 'media': 'TEST_MEDIA', + 'requestId': 'requestid1234', + 'cpm': 1234.56, + 'creativeId': 'creativeid1234', + 'dealId': 'TEST_DEAL_ID', + 'width': 300, + 'height': 250, + 'ad': "
", + 'mediaType': 'banner', + 'currency': 'JPY', + 'ttl': 360, + 'netRevenue': true + }]; + + let bidderRequest; + let result = spec.interpretResponse({ body: bannerResponse }, { bidderRequest }); + expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); + }); + + it('handles video responses', function() { + let expectedResponse = [{ + 'slotKey': 'slotkey1234', + 'userId': 'userid1234', + 'impId': 'impid1234', + 'media': 'TEST_MEDIA', + 'requestId': 'requestid1234', + 'cpm': 1234.56, + 'creativeId': 'creativeid1234', + 'dealId': 'TEST_DEAL_ID', + 'width': 320, + 'height': 180, + 'vastXml': '', + 'mediaType': 'video', + 'renderer': {}, + 'adResponse': {}, + 'currency': 'JPY', + 'ttl': 360, + 'netRevenue': true + }]; + + let bidderRequest; + let result = spec.interpretResponse({ body: videoResponse }, { bidderRequest }); + expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); + }); + + it('handles nobid responses', function() { + let response = { + isAdReturn: false, + 'ad': {} + }; + + let bidderRequest; + let result = spec.interpretResponse({ body: response }, { bidderRequest }); + expect(result.length).to.equal(0); + }); + }); + + describe('getUserSyncs', function() { + const imgResponse1 = { + body: { + 'isAdReturn': true, + 'ad': { /* ad body */ }, + 'syncPixels': [ + 'https://example.test/1' + ] + } + }; + + const imgResponse2 = { + body: { + 'isAdReturn': true, + 'ad': { /* ad body */ }, + 'syncPixels': [ + 'https://example.test/2' + ] + } + }; + + const ifResponse = { + body: { + 'isAdReturn': true, + 'ad': { /* ad body */ }, + 'syncIFs': [ + 'https://example.test/3' + ] + } + }; + + it('should use a sync img url from first response', function() { + const syncs = spec.getUserSyncs({ pixelEnabled: true }, [imgResponse1, imgResponse2, ifResponse]); + expect(syncs).to.deep.equal([ + { + type: 'image', + url: 'https://example.test/1' + } + ]); + }); + + it('handle ifs response', function() { + const syncs = spec.getUserSyncs({ iframeEnabled: true }, [ifResponse]); + expect(syncs).to.deep.equal([ + { + type: 'iframe', + url: 'https://example.test/3' + } + ]); + }); + + it('handle empty response (e.g. timeout)', function() { + const syncs = spec.getUserSyncs({ pixelEnabled: true }, []); + expect(syncs).to.deep.equal([]); + }); + + it('returns empty syncs when not enabled', function() { + const syncs = spec.getUserSyncs({ pixelEnabled: false }, [imgResponse1]); + expect(syncs).to.deep.equal([]); + }); + }); }); From 473adc64c47b00cfe1fd8c884fefcb82bc27f0fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=A8=E7=94=B0=20=E6=84=9B=E4=B8=80=E9=83=8E?= Date: Mon, 21 Jan 2019 12:05:26 +0900 Subject: [PATCH 3/5] add maintainer address --- modules/open8BidAdapter.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/open8BidAdapter.md b/modules/open8BidAdapter.md index b7d7204bfb7..2c69e174ee6 100644 --- a/modules/open8BidAdapter.md +++ b/modules/open8BidAdapter.md @@ -1,8 +1,8 @@ # Overview -**Module Name**: Innity Bidder Adapter +**Module Name**: Open8 Bidder Adapter **Module Type**: Bidder Adapter -**Maintainer**: engtat@innity.com +**Maintainer**: tdd-adtech@open8.com # Description From 1438626138fa146ddefe186d8cb950f8f772704a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=A8=E7=94=B0=20=E6=84=9B=E4=B8=80=E9=83=8E?= Date: Wed, 6 Feb 2019 21:42:20 +0900 Subject: [PATCH 4/5] add bidwon --- modules/open8BidAdapter.js | 21 ++++++++++++++++++- test/spec/modules/open8BidAdapter_spec.js | 25 +++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/modules/open8BidAdapter.js b/modules/open8BidAdapter.js index 6b4629f911e..9a3184a616b 100644 --- a/modules/open8BidAdapter.js +++ b/modules/open8BidAdapter.js @@ -1,4 +1,5 @@ import { Renderer } from 'src/Renderer'; +import {ajax} from '../src/ajax'; import * as utils from 'src/utils'; import { registerBidder } from 'src/adapters/bidderFactory'; import { VIDEO, BANNER } from 'src/mediaTypes'; @@ -51,12 +52,18 @@ export const spec = { userId: bidderResponse.userId, impId: bidderResponse.impId, media: bidderResponse.media, + ds: ad.ds, + spd: ad.spd, + fa: ad.fa, + pr: ad.pr, + mr: ad.mr, + nurl: ad.nurl, requestId: ad.bidId, cpm: ad.price, creativeId: ad.creativeId, dealId: ad.dealId, currency: ad.currency || 'JPY', - netRevenue: true, // TODO + netRevenue: true, ttl: 360, // 6 minutes } @@ -116,6 +123,13 @@ export const spec = { } return syncs; }, + onBidWon: function(bid) { + const winUrl = bid.nurl.replace( + /\$\{AUCTION_PRICE\}/, + bid.cpm + ); + ajax(winUrl, null); + } } function generateImpId() { @@ -154,6 +168,11 @@ function outstreamRender(bid) { impId: bid.impId, userId: bid.userId, media: bid.media, + ds: bid.ds, + spd: bid.spd, + fa: bid.fa, + pr: bid.pr, + mr: bid.mr, adResponse: bid.adResponse, mediaType: bid.mediaType }); diff --git a/test/spec/modules/open8BidAdapter_spec.js b/test/spec/modules/open8BidAdapter_spec.js index 06b55850ca3..e26811ed71c 100644 --- a/test/spec/modules/open8BidAdapter_spec.js +++ b/test/spec/modules/open8BidAdapter_spec.js @@ -58,6 +58,7 @@ describe('Open8Adapter', function() { userId: 'userid1234', impId: 'impid1234', media: 'TEST_MEDIA', + nurl: '//example/win', isAdReturn: true, syncPixels: ['//example/sync/pixel.gif'], syncIFs: [], @@ -67,6 +68,12 @@ describe('Open8Adapter', function() { creativeId: 'creativeid1234', dealId: 'TEST_DEAL_ID', currency: 'JPY', + ds: 876, + spd: 1234, + fa: 5678, + pr: 'pr1234', + mr: 'mr1234', + nurl: '//example/win', adType: 2, banner: { w: 300, @@ -90,6 +97,12 @@ describe('Open8Adapter', function() { creativeId: 'creativeid1234', dealId: 'TEST_DEAL_ID', currency: 'JPY', + ds: 876, + spd: 1234, + fa: 5678, + pr: 'pr1234', + mr: 'mr1234', + nurl: '//example/win', adType: 1, video: { purl: '//playerexample.js', @@ -106,6 +119,12 @@ describe('Open8Adapter', function() { 'userId': 'userid1234', 'impId': 'impid1234', 'media': 'TEST_MEDIA', + 'ds': 876, + 'spd': 1234, + 'fa': 5678, + 'pr': 'pr1234', + 'mr': 'mr1234', + 'nurl': '//example/win', 'requestId': 'requestid1234', 'cpm': 1234.56, 'creativeId': 'creativeid1234', @@ -130,6 +149,12 @@ describe('Open8Adapter', function() { 'userId': 'userid1234', 'impId': 'impid1234', 'media': 'TEST_MEDIA', + 'ds': 876, + 'spd': 1234, + 'fa': 5678, + 'pr': 'pr1234', + 'mr': 'mr1234', + 'nurl': '//example/win', 'requestId': 'requestid1234', 'cpm': 1234.56, 'creativeId': 'creativeid1234', From c25818677b1a900c1aba145b8bc20e89bd835c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=A8=E7=94=B0=20=E6=84=9B=E4=B8=80=E9=83=8E?= Date: Thu, 21 Feb 2019 20:49:50 +0900 Subject: [PATCH 5/5] check field populated --- modules/open8BidAdapter.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/modules/open8BidAdapter.js b/modules/open8BidAdapter.js index 9a3184a616b..be616d0ec30 100644 --- a/modules/open8BidAdapter.js +++ b/modules/open8BidAdapter.js @@ -27,7 +27,7 @@ export const spec = { var slotKey = utils.getBidIdParameter('slotKey', bid.params); queryString = utils.tryAppendQueryString(queryString, 'slot_key', slotKey); queryString = utils.tryAppendQueryString(queryString, 'imp_id', generateImpId()); - queryString = utils.tryAppendQueryString(queryString, 'bid_id', bid.bidId); + queryString += ('bid_id=' + bid.bidId); requests.push({ method: 'GET', @@ -85,13 +85,15 @@ export const spec = { ad: bannerAd.adm, mediaType: BANNER }); - try { - bannerAd.imps.forEach(impTrackUrl => { - const tracker = utils.createTrackPixelHtml(impTrackUrl); - bid.ad += tracker; - }); - } catch (error) { - utils.logError('Error appending imp tracking pixel', error); + if (bannerAd.imps) { + try { + bannerAd.imps.forEach(impTrackUrl => { + const tracker = utils.createTrackPixelHtml(impTrackUrl); + bid.ad += tracker; + }); + } catch (error) { + utils.logError('Error appending imp tracking pixel', error); + } } } return [bid]; @@ -124,6 +126,7 @@ export const spec = { return syncs; }, onBidWon: function(bid) { + if (!bid.nurl) { return; } const winUrl = bid.nurl.replace( /\$\{AUCTION_PRICE\}/, bid.cpm