From 2b21f548f61d7f62b3a9e3a2212f327cfa4f761a Mon Sep 17 00:00:00 2001 From: takuhou Date: Tue, 15 Nov 2022 09:54:03 +0900 Subject: [PATCH] YieldOne Bid Adapter: update documentation, test and code style (#9233) * add parameter test * change new_format to single_format * fix adomain typo * add parameter test * add jsdoc comment and update readme * change @return to @returns * change param and returns * add typeof and change param/returns * change returns value * change flux to 1x1 Co-authored-by: TakuhoSanpei --- modules/yieldoneBidAdapter.js | 68 +++++++++-- modules/yieldoneBidAdapter.md | 118 +++++++++++++++++-- test/spec/modules/yieldoneBidAdapter_spec.js | 36 +++++- 3 files changed, 199 insertions(+), 23 deletions(-) diff --git a/modules/yieldoneBidAdapter.js b/modules/yieldoneBidAdapter.js index 4c5f1687641..d408a0595f9 100644 --- a/modules/yieldoneBidAdapter.js +++ b/modules/yieldoneBidAdapter.js @@ -4,6 +4,17 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import { Renderer } from '../src/Renderer.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; +/** + * @typedef {import('../src/adapters/bidderFactory').Bid} Bid + * @typedef {import('../src/adapters/bidderFactory').BidRequest} BidRequest + * @typedef {import('../src/adapters/bidderFactory').BidderSpec} BidderSpec + * @typedef {import('../src/adapters/bidderFactory').ServerRequest} ServerRequest + * @typedef {import('../src/adapters/bidderFactory').ServerResponse} ServerResponse + * @typedef {import('../src/adapters/bidderFactory').SyncOptions} SyncOptions + * @typedef {import('../src/adapters/bidderFactory').UserSync} UserSync + * @typedef {import('../src/auction').BidderRequest} BidderRequest + */ + const BIDDER_CODE = 'yieldone'; const ENDPOINT_URL = 'https://y.one.impact-ad.jp/h_bid'; const USER_SYNC_URL = 'https://y.one.impact-ad.jp/push_sync'; @@ -13,13 +24,25 @@ const VIEWABLE_PERCENTAGE_URL = 'https://img.ak.impact-ad.jp/ic/pone/ivt/firstvi const DEFAULT_VIDEO_SIZE = {w: 640, h: 360}; +/** @type BidderSpec */ export const spec = { code: BIDDER_CODE, aliases: ['y1'], supportedMediaTypes: [BANNER, VIDEO], + /** + * Determines whether or not the given bid request is valid. + * @param {BidRequest} bid The bid params to validate. + * @returns {boolean} True if this is a valid bid, and false otherwise. + */ isBidRequestValid: function(bid) { return !!(bid.params.placementId); }, + /** + * Make a server request from the list of BidRequests. + * @param {Bid[]} validBidRequests - An array of bids. + * @param {BidderRequest} bidderRequest - bidder request object. + * @returns {ServerRequest|ServerRequest[]} ServerRequest Info describing the request to the server. + */ buildRequests: function(validBidRequests, bidderRequest) { return validBidRequests.map(bidRequest => { const params = bidRequest.params; @@ -96,6 +119,12 @@ export const spec = { }; }); }, + /** + * Unpack the response from the server into a list of bids. + * @param {ServerResponse} serverResponse - A successful response from the server. + * @param {BidRequest} bidRequests + * @returns {Bid[]} - An array of bids which were nested inside the server. + */ interpretResponse: function(serverResponse, bidRequest) { const bidResponses = []; const response = serverResponse.body; @@ -188,6 +217,11 @@ export const spec = { } return bidResponses; }, + /** + * Register the user sync pixels which should be dropped after the auction. + * @param {SyncOptions} syncOptions Which user syncs are allowed? + * @returns {UserSync[]} The user syncs which should be dropped. + */ getUserSyncs: function(syncOptions) { if (syncOptions.iframeEnabled) { return [{ @@ -202,7 +236,7 @@ export const spec = { * NOTE: server side does not yet support multiple formats. * @param {Object} bidRequest - * @param {boolean} [enabledOldFormat = true] - default: `true`. - * @return {string|null} - `"banner"` or `"video"` or `null`. + * @returns {string|null} - `"banner"` or `"video"` or `null`. */ function getMediaType(bidRequest, enabledOldFormat = true) { let hasBannerType = Boolean(deepAccess(bidRequest, 'mediaTypes.banner')); @@ -239,7 +273,7 @@ function getMediaType(bidRequest, enabledOldFormat = true) { * @param {Object} bidRequest.banner - * @param {Array} bidRequest.banner.sizes - * @param {boolean} [enabledOldFormat = true] - default: `true`. - * @return {string} - strings like `"300x250"` or `"300x250,728x90"`. + * @returns {string} - strings like `"300x250"` or `"300x250,728x90"`. */ function getBannerSizes(bidRequest, enabledOldFormat = true) { let sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes'); @@ -254,10 +288,10 @@ function getBannerSizes(bidRequest, enabledOldFormat = true) { /** * @param {Object} bidRequest - * @param {boolean} [enabledOldFormat = true] - default: `true`. - * @param {boolean} [enabledFlux = true] - default: `true`. - * @return {{w: number, h: number}} - + * @param {boolean} [enabled1x1 = true] - default: `true`. + * @returns {{w: number, h: number}} - */ -function getVideoSize(bidRequest, enabledOldFormat = true, enabledFlux = true) { +function getVideoSize(bidRequest, enabledOldFormat = true, enabled1x1 = true) { /** * @param {Array | Array>} sizes - * @return {{w: number, h: number} | null} - @@ -287,10 +321,10 @@ function getVideoSize(bidRequest, enabledOldFormat = true, enabledFlux = true) { playerSize = playerSize || _getPlayerSize(bidRequest.sizes); } - if (enabledFlux) { - // NOTE: `video.playerSize` in Flux is always [1,1]. + if (enabled1x1) { + // NOTE: `video.playerSize` in 1x1 is always [1,1]. if (playerSize && (playerSize.w === 1 && playerSize.h === 1)) { - // NOTE: `params.playerSize` is a specific object to support `FLUX`. + // NOTE: `params.playerSize` is a specific object to support `1x1`. playerSize = _getPlayerSize(deepAccess(bidRequest, 'params.playerSize')); } } @@ -298,6 +332,11 @@ function getVideoSize(bidRequest, enabledOldFormat = true, enabledFlux = true) { return playerSize || DEFAULT_VIDEO_SIZE; } +/** + * Create render for outstream video. + * @param {Object} serverResponse.body - + * @returns {Renderer} - Prebid Renderer object + */ function newRenderer(response) { const renderer = Renderer.install({ id: response.uid, @@ -314,12 +353,21 @@ function newRenderer(response) { return renderer; } +/** + * Handles an outstream response after the library is loaded + * @param {Object} bid + */ function outstreamRender(bid) { bid.renderer.push(() => { window.DACIVTPREBID.renderPrebid(bid); }); } +/** + * Create render for cmer outstream video. + * @param {Object} serverResponse.body - + * @returns {Renderer} - Prebid Renderer object + */ function newCmerRenderer(response) { const renderer = Renderer.install({ id: response.uid, @@ -336,6 +384,10 @@ function newCmerRenderer(response) { return renderer; } +/** + * Handles an outstream response after the library is loaded + * @param {Object} bid + */ function cmerRender(bid) { bid.renderer.push(() => { window.CMERYONEPREBID.renderPrebid(bid); diff --git a/modules/yieldoneBidAdapter.md b/modules/yieldoneBidAdapter.md index 1414d4e464f..d1306a08202 100644 --- a/modules/yieldoneBidAdapter.md +++ b/modules/yieldoneBidAdapter.md @@ -13,8 +13,7 @@ Connect to YIELDONE for bids. THE YIELDONE adapter requires setup and approval from the YIELDONE team. Please reach out to your account team or y1s@platform-one.co.jp for more information. -Note: THE YIELDONE adapter do not support "multi-format" scenario... if both -banner and video are specified as mediatypes, YIELDONE will treat it as a video unit. +YIELDONE adapter supports Banner, Video and Multi-Format(video, banner) currently. # Test Parameters ```javascript @@ -24,13 +23,16 @@ var adUnits = [ code: 'banner-div', mediaTypes: { banner: { - sizes: [[300, 250], [336, 280]] + sizes: [ + [300, 250], + [336, 280] + ] } }, bids: [{ bidder: 'yieldone', params: { - placementId: '36891' + placementId: '36891' // required } }] }, @@ -44,11 +46,109 @@ var adUnits = [ }, }, bids: [{ - bidder: 'yieldone', - params: { - placementId: '41993' - } - }] + bidder: "yieldone", + params: { + placementId: "36892", // required + playerParams: { // optional + wrapperWidth: "320px", // optional + wrapperHeight: "180px" // optional + }, + } + }] + }, + // Video adUnit(mediaTypes.video.playerSize: [1,1]) + { + code: 'video-1x1-div', + mediaTypes: { + video: { + playerSize: [[1, 1]], + context: 'outstream' + }, + }, + bids: [{ + bidder: 'yieldone', + params: { + placementId: "36892", // required + playerSize: [640, 360], // required + playerParams: { // optional + wrapperWidth: "320px", // optional + wrapperHeight: "180px" // optional + }, + } + }] + }, + // Multi-Format adUnit + { + code: "multi-format-div", + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [1, 1] + ] + }, + video: { + playerSize: [640, 360], + context: "outstream" + } + }, + bids: [{ + // * "video" bid object should be placed before "banner" bid object. + // This bid will request a "video" media type ad. + bidder: "yieldone", + params: { + placementId: "36892", // required + playerParams: { // required + wrapperWidth: "320px", // optional + wrapperHeight: "180px" // optional + }, + } + }, + { + // This bid will request a "banner" media type ad. + bidder: "yieldone", + params: { + placementId: "36891" // required + } + } + ] + }, + // Multi-Format adUnit(mediaTypes.video.playerSize: [1,1]) + { + code: "multi-format-1x1-div", + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [1, 1] + ] + }, + video: { + playerSize: [1, 1], + context: "outstream" + } + }, + bids: [{ + // * "video" bid object should be placed before "banner" bid object. + // This bid will request a "video" media type ad. + bidder: "yieldone", + params: { + placementId: "36892", // required + playerSize: [640, 360], // required + playerParams: { // required + wrapperWidth: "320px", // optional + wrapperHeight: "180px" // optional + }, + } + }, + { + // This bid will request a "banner" media type ad. + bidder: "yieldone", + params: { + placementId: "36891" // required + } + } + ] } ``` diff --git a/test/spec/modules/yieldoneBidAdapter_spec.js b/test/spec/modules/yieldoneBidAdapter_spec.js index 59bd4a80081..a10247411db 100644 --- a/test/spec/modules/yieldoneBidAdapter_spec.js +++ b/test/spec/modules/yieldoneBidAdapter_spec.js @@ -140,7 +140,7 @@ describe('yieldoneBidAdapter', function() { }); }); - describe('New Format', function () { + describe('Single Format', function () { const bidRequests = [ { params: {placementId: '0'}, @@ -206,8 +206,11 @@ describe('yieldoneBidAdapter', function() { it('width and height should be set as separate parameters on outstream requests', function () { expect(request[0].data).to.not.have.property('w'); + expect(request[0].data).to.not.have.property('h'); expect(request[1].data).to.not.have.property('w'); + expect(request[1].data).to.not.have.property('h'); expect(request[2].data).to.not.have.property('w'); + expect(request[2].data).to.not.have.property('h'); expect(request[3].data.w).to.equal(1280); expect(request[3].data.h).to.equal(720); expect(request[4].data.w).to.equal(1920); @@ -260,12 +263,13 @@ describe('yieldoneBidAdapter', function() { it('width and height should be set as separate parameters on outstream requests', function () { expect(request[0].data).to.not.have.property('w'); + expect(request[0].data).to.not.have.property('h'); expect(request[1].data.w).to.equal(1920); expect(request[1].data.h).to.equal(1080); }); }); - describe('FLUX Format', function () { + describe('1x1 Format', function () { const bidRequests = [ { // It will be treated as a banner. @@ -326,6 +330,7 @@ describe('yieldoneBidAdapter', function() { it('width and height should be set as separate parameters on outstream requests', function () { expect(request[0].data).to.not.have.property('w'); + expect(request[0].data).to.not.have.property('h'); expect(request[1].data.w).to.equal(1920); expect(request[1].data.h).to.equal(1080); expect(request[2].data.w).to.equal(DEFAULT_VIDEO_SIZE.w); @@ -500,9 +505,9 @@ describe('yieldoneBidAdapter', function() { 'currency': 'JPY', 'statusMessage': 'Bid available', 'dealId': 'P1-FIX-7800-DSP-MON', - 'admoain': [ + 'adomain': [ 'www.example.com' - ] + ], } }; @@ -528,7 +533,16 @@ describe('yieldoneBidAdapter', function() { }]; let result = spec.interpretResponse(serverResponseBanner, bidRequestBanner[0]); expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0])); + expect(result[0].requestId).to.equal(expectedResponse[0].requestId); + expect(result[0].cpm).to.equal(expectedResponse[0].cpm); + expect(result[0].width).to.equal(expectedResponse[0].width); + expect(result[0].height).to.equal(expectedResponse[0].height); + expect(result[0].creativeId).to.equal(expectedResponse[0].creativeId); + expect(result[0].dealId).to.equal(expectedResponse[0].dealId); + expect(result[0].currency).to.equal(expectedResponse[0].currency); expect(result[0].mediaType).to.equal(expectedResponse[0].mediaType); + expect(result[0].ad).to.equal(expectedResponse[0].ad); + expect(result[0].meta.advertiserDomains[0]).to.equal(expectedResponse[0].meta.advertiserDomains[0]); }); let serverResponseVideo = { @@ -537,7 +551,7 @@ describe('yieldoneBidAdapter', function() { 'height': 360, 'width': 640, 'cpm': 0.0536616, - 'dealId': 'P1-FIX-766-DSP-MON', + 'dealId': 'P1-FIX-7800-DSP-MON', 'crid': '2494768', 'currency': 'JPY', 'statusMessage': 'Bid available', @@ -575,7 +589,7 @@ describe('yieldoneBidAdapter', function() { 'currency': 'JPY', 'netRevenue': true, 'ttl': 3000, - 'referrer': '', + 'referrer': 'http%3A%2F%2Flocalhost%3A9876%2F%3Fid%3D74552836', 'meta': { 'advertiserDomains': [] }, @@ -588,9 +602,19 @@ describe('yieldoneBidAdapter', function() { }]; let result = spec.interpretResponse(serverResponseVideo, bidRequestVideo[0]); expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0])); + expect(result[0].requestId).to.equal(expectedResponse[0].requestId); + expect(result[0].cpm).to.equal(expectedResponse[0].cpm); + expect(result[0].width).to.equal(expectedResponse[0].width); + expect(result[0].height).to.equal(expectedResponse[0].height); + expect(result[0].creativeId).to.equal(expectedResponse[0].creativeId); + expect(result[0].dealId).to.equal(expectedResponse[0].dealId); + expect(result[0].currency).to.equal(expectedResponse[0].currency); + expect(result[0].vastXml).to.equal(expectedResponse[0].vastXml); expect(result[0].mediaType).to.equal(expectedResponse[0].mediaType); + expect(result[0].referrer).to.equal(expectedResponse[0].referrer); expect(result[0].renderer.id).to.equal(expectedResponse[0].renderer.id); expect(result[0].renderer.url).to.equal(expectedResponse[0].renderer.url); + expect(result[0].meta.advertiserDomains[0]).to.equal(expectedResponse[0].meta.advertiserDomains[0]); }); it('handles empty bid response', function () {