From ee93a3fd6dc7e14d933d08d4ff2f80ee5fa0d8c7 Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Tue, 26 Nov 2024 23:27:43 +0900 Subject: [PATCH 01/21] Michao Bid Adapter: Initial release --- modules/michaoBidAdapter.js | 222 ++++++++ modules/michaoBidAdapter.md | 58 +++ test/spec/modules/michaoBidAdapter_spec.js | 577 +++++++++++++++++++++ 3 files changed, 857 insertions(+) create mode 100644 modules/michaoBidAdapter.js create mode 100644 modules/michaoBidAdapter.md create mode 100644 test/spec/modules/michaoBidAdapter_spec.js diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js new file mode 100644 index 00000000000..41dd6d9234e --- /dev/null +++ b/modules/michaoBidAdapter.js @@ -0,0 +1,222 @@ +import { ortbConverter } from '../libraries/ortbConverter/converter.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { Renderer } from '../src/Renderer.js'; +import { + deepSetValue, + isStr, + logError, + replaceAuctionPrice, + triggerPixel, +} from '../src/utils.js'; + +const ENV = { + BIDDER_CODE: 'michao', + SUPPORTED_MEDIA_TYPES: [BANNER, VIDEO], + ENDPOINT: 'https://rtb.michao-ssp.com/openrtb/prebid', + NET_REVENUE: true, + DEFAULT_CURRENCY: 'USD', + RENDERER_URL: + 'https://cdn.jsdelivr.net/npm/in-renderer-js@latest/dist/in-renderer.umd.min.js', +}; + +export const spec = { + code: ENV.BIDDER_CODE, + supportedMediaTypes: ENV.SUPPORTED_MEDIA_TYPES, + + isBidRequestValid: function (bid) { + if (!hasParamsObject(bid)) { + return false; + } + + if (!validateMichaoParams(bid.params)) { + domainLogger.bidRequestValidationError(); + return false; + } + + return true; + }, + + buildRequests: function (validBidRequests, bidderRequest) { + const bidRequests = []; + + validBidRequests.forEach((validBidRequest) => { + if ( + hasVideoMediaType(validBidRequest) && + hasBannerMediaType(validBidRequest) + ) { + bidRequests.push( + buildRequest(validBidRequest, bidderRequest, 'banner') + ); + bidRequests.push(buildRequest(validBidRequest, bidderRequest, 'video')); + } else if (hasVideoMediaType(validBidRequest)) { + bidRequests.push(buildRequest(validBidRequest, bidderRequest, 'video')); + } else if (hasBannerMediaType(validBidRequest)) { + bidRequests.push( + buildRequest(validBidRequest, bidderRequest, 'banner') + ); + } + }); + + return bidRequests; + }, + + interpretResponse: function (serverResponse, request) { + return interpretResponse(serverResponse, request); + }, + + getUserSyncs: function ( + syncOptions, + serverResponses, + gdprConsent, + uspConsent + ) { + if (syncOptions.iframeEnabled) { + return [syncUser(gdprConsent)]; + } + }, + + onBidBillable: function (bid) { + if (bid.burl && isStr(bid.burl)) { + billBid(bid); + } + }, +}; + +export const domainLogger = { + bidRequestValidationError() { + logError('Michao: wrong format of site or placement.'); + }, +}; + +export function buildRequest(bidRequest, bidderRequest, mediaType) { + const openRTBBidRequest = converter.toORTB({ + bidRequests: [bidRequest], + bidderRequest, + context: { + mediaType: mediaType, + }, + }); + + return { + method: 'POST', + url: ENV.ENDPOINT, + data: openRTBBidRequest, + options: { contentType: 'application/json', withCredentials: true }, + }; +} + +export function interpretResponse(response, request) { + const bids = converter.fromORTB({ + response: response.body, + request: request.data, + }).bids; + + return bids; +} + +export function syncUser(gdprConsent) { + let gdprParams = ''; + + if (typeof gdprConsent === 'object') { + if (typeof gdprConsent.gdprApplies === 'boolean') { + gdprParams = `gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${ + gdprConsent.consentString + }`; + } else { + gdprParams = `gdpr_consent=${gdprConsent.consentString}`; + } + } + + return { + type: 'iframe', + url: 'https://sync.michao-ssp.com/cookie-syncs?' + gdprParams, + }; +} + +export function addRenderer(bid) { + bid.renderer.push(() => { + const inRenderer = new window.InRenderer(); + inRenderer.render(bid.adUnitCode, bid); + }); +} + +export function hasParamsObject(bid) { + return typeof bid.params === 'object'; +} + +export function validateMichaoParams(params) { + const michaoParams = ['site', 'placement']; + return michaoParams.every((michaoParam) => + Number.isFinite(params[michaoParam]) + ); +} + +export function billBid(bid) { + bid.burl = replaceAuctionPrice(bid.burl, bid.originalCpm || bid.cpm); + triggerPixel(bid.burl); +} + +const converter = ortbConverter({ + request(buildRequest, imps, bidderRequest, context) { + const bidRequest = context.bidRequests[0]; + const openRTBBidRequest = buildRequest(imps, bidderRequest, context); + openRTBBidRequest.cur = [ENV.DEFAULT_CURRENCY]; + openRTBBidRequest.test = config.getConfig('debug') ? 1 : 0; + deepSetValue( + openRTBBidRequest, + 'site.id', + bidRequest.params.site.toString() + ); + if (bidRequest?.schain) { + deepSetValue(openRTBBidRequest, 'source.schain', bidRequest.schain); + } + + return openRTBBidRequest; + }, + + imp(buildImp, bidRequest, context) { + const imp = buildImp(bidRequest, context); + // imp.id = bidRequest.adUnitCode; + deepSetValue(imp, 'ext.placement', bidRequest.params.placement.toString()); + + return imp; + }, + + bidResponse(buildBidResponse, bid, context) { + const { bidRequest } = context; + let bidResponse = buildBidResponse(bid, context); + if (bidRequest.mediaTypes.video?.context === 'outstream') { + const renderer = Renderer.install({ + id: bid.bidId, + url: ENV.RENDERER_URL, + adUnitCode: bid.adUnitCode, + }); + renderer.setRender(addRenderer); + bidResponse.renderer = renderer; + } + + return bidResponse; + }, + + context: { + netRevenue: ENV.NET_REVENUE, + currency: ENV.DEFAULT_CURRENCY, + ttl: 360, + }, +}); + +function hasBannerMediaType(bid) { + return hasMediaType(bid, 'banner'); +} + +function hasVideoMediaType(bid) { + return hasMediaType(bid, 'video'); +} + +function hasMediaType(bid, mediaType) { + return bid.mediaTypes.hasOwnProperty(mediaType); +} + +registerBidder(spec); diff --git a/modules/michaoBidAdapter.md b/modules/michaoBidAdapter.md new file mode 100644 index 00000000000..8767d04abd7 --- /dev/null +++ b/modules/michaoBidAdapter.md @@ -0,0 +1,58 @@ +# Overview + +```markdown +Module Name: Michao Bidder Adapter +Module Type: Bidder Adapter +Maintainer: miyamoto.kai@lookverin.com +``` + +# Description + +Module that connects to Michao’s demand sources + +Supported Ad format: +* Banner +* Video (instream and outstream) + +# Test Parameters +``` +var adUnits = [ + // Banner adUnit + { + code: 'banner-div', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [{ + bidder: 'michao', + params: { + site: 1, + placement: 1, + } + }] + }, + // Video adUnit + { + code: 'video-div', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480], + minduration: 0, + maxduration: 120, + mimes: ['video/mp4'], + protocols: [7] + } + }, + bids: [{ + bidder: 'michao', + params: { + site: 1, + placement: 1, + } + }] + } +]; +``` diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js new file mode 100644 index 00000000000..ad64a66f5f9 --- /dev/null +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -0,0 +1,577 @@ +import { expect } from 'chai'; +import { + addRenderer, + billBid, + buildRequest, + interpretResponse, + spec, + syncUser, + validateMichaoParams, +} from '../../../modules/michaoBidAdapter'; +import * as utils from 'src/utils.js'; +import { config } from '../../../src/config'; + +describe('the michao bidder adapter', () => { + beforeEach(() => { + config.resetConfig(); + }); + + describe('unit', () => { + describe('validate bid request', () => { + const invalidBidParams = [ + { site: '123', placement: 'super-placement' }, + { site: '123', placement: 456 }, + { site: Infinity, placement: 456 }, + ]; + invalidBidParams.forEach((params) => { + it('Detecting incorrect parameters', () => { + const result = validateMichaoParams(params); + + expect(result).to.be.false; + }); + }); + + it('If the site ID and placement ID are correct, the verification succeeds.', () => { + const params = { + site: 123, + placement: 234, + }; + + const result = validateMichaoParams(params); + + expect(result).to.be.true; + }); + }); + + describe('build bid request', () => { + it('Banner bid requests are converted to banner server request objects', () => { + const bannerBidRequest = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { banner: [[300, 250]] }, + params: { + site: 123, + placement: 456, + }, + }; + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: '15246a574e859f', + bids: [bannerBidRequest], + }; + + const result = buildRequest(bannerBidRequest, bidderRequest, 'banner'); + + expect(result).to.nested.include({ + url: 'https://rtb.michao-ssp.com/openrtb/prebid', + 'options.contentType': 'application/json', + 'options.withCredentials': true, + method: 'POST', + 'data.cur[0]': 'USD', + 'data.imp[0].ext.placement': '456', + 'data.site.id': '123', + 'data.test': 0, + }); + }); + + it('Video bid requests are converted to video server request objects', () => { + const videoBidRequest = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480], + mimes: ['video/mp4'], + }, + }, + params: { + site: 123, + placement: 456, + }, + }; + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: '15246a574e859f', + bids: [videoBidRequest], + }; + + const result = buildRequest(videoBidRequest, bidderRequest, 'banner'); + + expect(result).to.nested.include({ + url: 'https://rtb.michao-ssp.com/openrtb/prebid', + 'options.contentType': 'application/json', + 'options.withCredentials': true, + method: 'POST', + 'data.cur[0]': 'USD', + 'data.imp[0].ext.placement': '456', + 'data.site.id': '123', + 'data.test': 0, + }); + }); + + it('Converted to server request object for testing in debug mode', () => { + const bidRequest = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { banner: [[300, 250]] }, + params: { + site: 123, + placement: 456, + }, + }; + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: '15246a574e859f', + bids: [bidRequest], + }; + config.setConfig({ + debug: true, + }); + + const result = buildRequest(bidRequest, bidderRequest, 'banner'); + + expect(result).to.nested.include({ + 'data.test': 1, + }); + }); + }); + + describe('interpret response', () => { + it('Server response is interpreted as a bid.', () => { + const response = { + headers: null, + body: { + id: 'requestId', + seatbid: [ + { + bid: [ + { + id: 'bidId1', + impid: 'bidId1', + price: 0.18, + adm: '', + adid: '144762342', + adomain: ['https://dummydomain.com'], + iurl: 'iurl', + cid: '109', + crid: 'creativeId', + cat: [], + w: 300, + h: 250, + mtype: 1, + }, + ], + seat: 'seat', + }, + ], + cur: 'USD', + }, + }; + const bannerBidRequest = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: 'bidId1', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { banner: [[300, 250]] }, + params: { + site: 123, + placement: 456, + }, + }; + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: '15246a574e859f', + bids: [bannerBidRequest], + }; + const request = buildRequest(bannerBidRequest, bidderRequest, 'banner'); + + const result = interpretResponse(response, request); + + expect(result).to.be.an('array'); + expect(result[0]).to.have.property('currency', 'USD'); + expect(result[0]).to.have.property('requestId', 'bidId1'); + expect(result[0]).to.have.property('cpm', 0.18); + expect(result[0]).to.have.property('width', 300); + expect(result[0]).to.have.property('height', 250); + expect(result[0]).to.have.property('ad', ''); + expect(result[0]).to.have.property('creativeId', 'creativeId'); + expect(result[0]).to.have.property('netRevenue', true); + }); + + it('Empty server responses are interpreted as empty bids', () => { + const response = { body: {} }; + const bannerBidRequest = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { banner: [[300, 250]] }, + params: { + site: 123, + placement: 456, + }, + }; + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: '15246a574e859f', + bids: [bannerBidRequest], + }; + const request = buildRequest(bannerBidRequest, bidderRequest, 'banner'); + + const result = interpretResponse(response, request); + + expect(result).to.be.an('array'); + expect(result.length).to.equal(0); + }); + + it('Set renderer with outstream video ads', () => { + const response = { + headers: null, + body: { + id: 'requestId', + seatbid: [ + { + bid: [ + { + id: 'bidId1', + impid: 'bidId1', + price: 0.18, + adm: '', + adid: '144762342', + adomain: ['https://dummydomain.com'], + iurl: 'iurl', + cid: '109', + crid: 'creativeId', + cat: [], + w: 300, + h: 250, + mtype: 1, + }, + ], + seat: 'seat', + }, + ], + cur: 'USD', + }, + }; + const videoBidRequest = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: 'bidId1', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480], + }, + }, + params: { + site: 123, + placement: 456, + }, + }; + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: '15246a574e859f', + bids: [videoBidRequest], + }; + const request = buildRequest(videoBidRequest, bidderRequest, 'video'); + + const result = interpretResponse(response, request); + + expect(result).to.be.an('array'); + expect(result[0]).to.have.property('currency', 'USD'); + expect(result[0]).to.have.property('requestId', 'bidId1'); + expect(result[0]).to.have.property('cpm', 0.18); + expect(result[0]).to.have.property('width', 300); + expect(result[0]).to.have.property('height', 250); + expect(result[0]).to.have.property('vastXml', ''); + expect(result[0]).to.have.property('creativeId', 'creativeId'); + expect(result[0]).to.have.property('netRevenue', true); + expect(result[0]).to.have.property('mediaType', 'video'); + expect(result[0]).to.have.property('renderer'); + }); + }); + + describe('user syncs', () => { + it('Sync Users', () => { + const gdprConsent = { + gdprApplies: false, + consentString: '', + }; + + const result = syncUser(gdprConsent); + + expect(result).to.deep.equal({ + type: 'iframe', + url: 'https://sync.michao-ssp.com/cookie-syncs?gdpr=0&gdpr_consent=', + }); + }); + }); + + describe('bill a bid', () => { + const triggerPixelSpy = sinon.spy(utils, 'triggerPixel'); + const bid = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { banner: [[300, 250]] }, + params: { + site: 123, + placement: 456, + }, + burl: 'https://example.com/burl', + }; + + billBid(bid); + + expect(triggerPixelSpy.calledWith('https://example.com/burl')).to.true; + triggerPixelSpy.restore(); + }); + + describe('renderer', () => { + it('Set outstream renderer', () => { + const bid = { + renderer: [], + }; + + addRenderer(bid); + + expect(bid.renderer[0]).that.is.a('function'); + }); + }); + }); + + describe('integration', () => { + it('`isBidRequestValid`', () => { + const validBidRequest = { + params: { + placement: 124, + site: 456, + }, + }; + + const result = spec.isBidRequestValid(validBidRequest); + + expect(result).to.true; + }); + + it('`buildRequests`', () => { + const validBidRequests = [ + { + adUnitCode: 'test-div', + auctionId: 'auction-1', + bidId: 'bid-1', + bidder: 'michao', + bidderRequestId: 'bidder-request-1', + mediaTypes: { + banner: { + sizes: [[300, 250]], + }, + }, + params: { + site: 12, + placement: 12, + }, + }, + { + adUnitCode: 'test-div', + auctionId: 'auction-1', + bidId: 'bid-2', + bidder: 'michao', + bidderRequestId: 'bidder-request-1', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480], + mimes: ['video/mp4'], + minduration: 0, + maxduration: 30, + }, + }, + params: { + site: 12, + placement: 12, + }, + }, + ]; + const bidderRequest = { + auctionId: 'auction-1', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: 'bidder-request-1', + }; + + const result = spec.buildRequests(validBidRequests, bidderRequest); + + expect(result.length).to.equal(2); + }); + + it('`interpretResponse`', () => { + const response = { + headers: null, + body: { + id: 'requestId', + seatbid: [ + { + bid: [ + { + id: 'bidId1', + impid: 'bidId1', + price: 0.18, + adm: '', + adid: '144762342', + adomain: ['https://dummydomain.com'], + iurl: 'iurl', + cid: '109', + crid: 'creativeId', + cat: [], + w: 640, + h: 480, + mtype: 1, + }, + ], + seat: 'seat', + }, + ], + cur: 'USD', + }, + }; + const bannerBidRequest = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: 'bidId1', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { + video: { + context: 'outstream', + mimes: ['video/mp4'], + minduration: 0, + maxduration: 120, + }, + }, + params: { + site: 123, + placement: 456, + }, + }; + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: '15246a574e859f', + bids: [bannerBidRequest], + }; + const request = buildRequest(bannerBidRequest, bidderRequest, 'banner'); + + const result = interpretResponse(response, request); + + expect(result).to.be.an('array'); + expect(result[0]).to.have.property('currency', 'USD'); + expect(result[0]).to.have.property('requestId', 'bidId1'); + expect(result[0]).to.have.property('cpm', 0.18); + expect(result[0]).to.have.property('width', 640); + expect(result[0]).to.have.property('height', 480); + expect(result[0]).to.have.property('ad', ''); + expect(result[0]).to.have.property('creativeId', 'creativeId'); + expect(result[0]).to.have.property('netRevenue', true); + }); + + it('`getUserSyncs`', () => { + const syncOptions = { + iframeEnabled: true, + }; + const gdprConsent = { + gdprApplies: true, + consentString: + 'CQIhBPbQIhBPbEkAAAENCZCAAAAAAAAAAAAAAAAAAAAA.II7Nd_X__bX9n-_7_6ft0eY1f9_r37uQzDhfNs-8F3L_W_LwX32E7NF36tq4KmR4ku1bBIQNtHMnUDUmxaolVrzHsak2cpyNKJ_JkknsZe2dYGF9Pn9lD-YKZ7_5_9_f52T_9_9_-39z3_9f___dv_-__-vjf_599n_v9fV_78_Kf9______-____________8A', + }; + + const result = spec.getUserSyncs(syncOptions, {}, gdprConsent); + + expect(result).to.deep.equal([ + { + type: 'iframe', + url: 'https://sync.michao-ssp.com/cookie-syncs?gdpr=1&gdpr_consent=CQIhBPbQIhBPbEkAAAENCZCAAAAAAAAAAAAAAAAAAAAA.II7Nd_X__bX9n-_7_6ft0eY1f9_r37uQzDhfNs-8F3L_W_LwX32E7NF36tq4KmR4ku1bBIQNtHMnUDUmxaolVrzHsak2cpyNKJ_JkknsZe2dYGF9Pn9lD-YKZ7_5_9_f52T_9_9_-39z3_9f___dv_-__-vjf_599n_v9fV_78_Kf9______-____________8A', + }, + ]); + }); + + it('`onBidBillable`', () => { + const triggerPixelSpy = sinon.spy(utils, 'triggerPixel'); + const bid = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { banner: [[300, 250]] }, + params: { + site: 123, + placement: 456, + }, + burl: 'https://example.com/burl', + }; + + spec.onBidBillable(bid); + + expect(triggerPixelSpy.calledWith('https://example.com/burl')).to.true; + triggerPixelSpy.restore(); + }); + }); +}); From 2b0d4fd56456a19a619b4d7bc5fd365a3182768f Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Wed, 27 Nov 2024 17:33:58 +0900 Subject: [PATCH 02/21] Michao Bid Adapter: Fix incomprehensible integration tests --- test/spec/modules/michaoBidAdapter_spec.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js index ad64a66f5f9..f66e1da895b 100644 --- a/test/spec/modules/michaoBidAdapter_spec.js +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -467,7 +467,7 @@ describe('the michao bidder adapter', () => { id: 'bidId1', impid: 'bidId1', price: 0.18, - adm: '', + adm: '
ad
', adid: '144762342', adomain: ['https://dummydomain.com'], iurl: 'iurl', @@ -495,11 +495,8 @@ describe('the michao bidder adapter', () => { bidderRequestsCount: 1, bidderWinsCount: 0, mediaTypes: { - video: { - context: 'outstream', - mimes: ['video/mp4'], - minduration: 0, - maxduration: 120, + banner: { + sizes: [[300, 250]] }, }, params: { @@ -524,7 +521,7 @@ describe('the michao bidder adapter', () => { expect(result[0]).to.have.property('cpm', 0.18); expect(result[0]).to.have.property('width', 640); expect(result[0]).to.have.property('height', 480); - expect(result[0]).to.have.property('ad', ''); + expect(result[0]).to.have.property('ad', '
ad
'); expect(result[0]).to.have.property('creativeId', 'creativeId'); expect(result[0]).to.have.property('netRevenue', true); }); From ae817a3b15dbc1002b691dfaee2fb2cddd54043e Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Wed, 27 Nov 2024 19:06:30 +0900 Subject: [PATCH 03/21] Michao Bid Adapter: Explicitly specify VAST XML --- modules/michaoBidAdapter.js | 19 +++++++++++-------- test/spec/modules/michaoBidAdapter_spec.js | 3 +++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js index 41dd6d9234e..678d80f560d 100644 --- a/modules/michaoBidAdapter.js +++ b/modules/michaoBidAdapter.js @@ -187,14 +187,17 @@ const converter = ortbConverter({ bidResponse(buildBidResponse, bid, context) { const { bidRequest } = context; let bidResponse = buildBidResponse(bid, context); - if (bidRequest.mediaTypes.video?.context === 'outstream') { - const renderer = Renderer.install({ - id: bid.bidId, - url: ENV.RENDERER_URL, - adUnitCode: bid.adUnitCode, - }); - renderer.setRender(addRenderer); - bidResponse.renderer = renderer; + if (hasVideoMediaType(bidRequest)) { + bidResponse.vastXml = bid.adm; + if (bidRequest.mediaTypes.video?.context === 'outstream') { + const renderer = Renderer.install({ + id: bid.bidId, + url: ENV.RENDERER_URL, + adUnitCode: bid.adUnitCode, + }); + renderer.setRender(addRenderer); + bidResponse.renderer = renderer; + } } return bidResponse; diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js index f66e1da895b..0548f9689fe 100644 --- a/test/spec/modules/michaoBidAdapter_spec.js +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -304,6 +304,9 @@ describe('the michao bidder adapter', () => { video: { context: 'outstream', playerSize: [640, 480], + minduration: 0, + maxduration: 30, + protocols: [7] }, }, params: { From 27d6259f85db3287078918bdd632f4a6096992a9 Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Wed, 27 Nov 2024 19:22:58 +0900 Subject: [PATCH 04/21] Michao Bid Adapter: Support for rewarded advertising --- modules/michaoBidAdapter.js | 11 +++-- test/spec/modules/michaoBidAdapter_spec.js | 47 ++++++++++++++++++---- 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js index 678d80f560d..4254fb0c10d 100644 --- a/modules/michaoBidAdapter.js +++ b/modules/michaoBidAdapter.js @@ -147,10 +147,15 @@ export function hasParamsObject(bid) { } export function validateMichaoParams(params) { - const michaoParams = ['site', 'placement']; - return michaoParams.every((michaoParam) => + let valid = true; + + const michaoAdUnitInfoParams = ['site', 'placement']; + + valid = michaoAdUnitInfoParams.every((michaoParam) => Number.isFinite(params[michaoParam]) ); + + return valid } export function billBid(bid) { @@ -178,8 +183,8 @@ const converter = ortbConverter({ imp(buildImp, bidRequest, context) { const imp = buildImp(bidRequest, context); - // imp.id = bidRequest.adUnitCode; deepSetValue(imp, 'ext.placement', bidRequest.params.placement.toString()); + deepSetValue(imp, 'rwdd', bidRequest.params?.reward ? 1 : false); return imp; }, diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js index 0548f9689fe..c7e2f427a4c 100644 --- a/test/spec/modules/michaoBidAdapter_spec.js +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -159,6 +159,41 @@ describe('the michao bidder adapter', () => { 'data.test': 1, }); }); + + it('Specifying a reward builds a bid request for the reward.', () => { + const bidRequest = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { banner: [[300, 250]] }, + params: { + site: 123, + placement: 456, + reward: true, + }, + }; + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: '15246a574e859f', + bids: [bidRequest], + }; + config.setConfig({ + debug: true, + }); + + const result = buildRequest(bidRequest, bidderRequest, 'banner'); + + expect(result).to.nested.include({ + 'data.imp[0].rwdd': 1, + }); + }); }); describe('interpret response', () => { @@ -427,17 +462,13 @@ describe('the michao bidder adapter', () => { }, { adUnitCode: 'test-div', - auctionId: 'auction-1', + auctionId: 'auction-2', bidId: 'bid-2', bidder: 'michao', - bidderRequestId: 'bidder-request-1', + bidderRequestId: 'bidder-request-2', mediaTypes: { - video: { - context: 'outstream', - playerSize: [640, 480], - mimes: ['video/mp4'], - minduration: 0, - maxduration: 30, + banner: { + sizes: [[300, 250]], }, }, params: { From 522b79d75b3eb338cf8af22df4deda366163e264 Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Wed, 27 Nov 2024 21:55:51 +0900 Subject: [PATCH 05/21] Michao Bid Adapter: Re-run E2e test --- modules/michaoBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js index 4254fb0c10d..821e3ef1061 100644 --- a/modules/michaoBidAdapter.js +++ b/modules/michaoBidAdapter.js @@ -86,7 +86,7 @@ export const spec = { export const domainLogger = { bidRequestValidationError() { - logError('Michao: wrong format of site or placement.'); + logError('Michao Bid Adapter: wrong format of site or placement.'); }, }; From d8313fc1ada6eeeff43e521a5e2aa3abe43a0e30 Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Tue, 3 Dec 2024 04:11:20 +0900 Subject: [PATCH 06/21] Michao Bid Adapter: Support for native format --- modules/michaoBidAdapter.js | 28 ++++--- test/spec/modules/michaoBidAdapter_spec.js | 86 +++++++++++++++++++++- 2 files changed, 99 insertions(+), 15 deletions(-) diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js index 821e3ef1061..f5d7ba6d757 100644 --- a/modules/michaoBidAdapter.js +++ b/modules/michaoBidAdapter.js @@ -1,7 +1,7 @@ import { ortbConverter } from '../libraries/ortbConverter/converter.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { config } from '../src/config.js'; -import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; import { Renderer } from '../src/Renderer.js'; import { deepSetValue, @@ -13,7 +13,7 @@ import { const ENV = { BIDDER_CODE: 'michao', - SUPPORTED_MEDIA_TYPES: [BANNER, VIDEO], + SUPPORTED_MEDIA_TYPES: [BANNER, VIDEO, NATIVE], ENDPOINT: 'https://rtb.michao-ssp.com/openrtb/prebid', NET_REVENUE: true, DEFAULT_CURRENCY: 'USD', @@ -42,19 +42,19 @@ export const spec = { const bidRequests = []; validBidRequests.forEach((validBidRequest) => { - if ( - hasVideoMediaType(validBidRequest) && - hasBannerMediaType(validBidRequest) - ) { + if (hasVideoMediaType(validBidRequest)) { + bidRequests.push(buildRequest(validBidRequest, bidderRequest, 'video')); + } + + if (hasBannerMediaType(validBidRequest)) { bidRequests.push( buildRequest(validBidRequest, bidderRequest, 'banner') ); - bidRequests.push(buildRequest(validBidRequest, bidderRequest, 'video')); - } else if (hasVideoMediaType(validBidRequest)) { - bidRequests.push(buildRequest(validBidRequest, bidderRequest, 'video')); - } else if (hasBannerMediaType(validBidRequest)) { + } + + if (hasNativeMediaType(validBidRequest)) { bidRequests.push( - buildRequest(validBidRequest, bidderRequest, 'banner') + buildRequest(validBidRequest, bidderRequest, 'native') ); } }); @@ -184,7 +184,7 @@ const converter = ortbConverter({ imp(buildImp, bidRequest, context) { const imp = buildImp(bidRequest, context); deepSetValue(imp, 'ext.placement', bidRequest.params.placement.toString()); - deepSetValue(imp, 'rwdd', bidRequest.params?.reward ? 1 : false); + deepSetValue(imp, 'rwdd', bidRequest.params?.reward ? 1 : 0); return imp; }, @@ -223,6 +223,10 @@ function hasVideoMediaType(bid) { return hasMediaType(bid, 'video'); } +function hasNativeMediaType(bid) { + return hasMediaType(bid, 'native'); +} + function hasMediaType(bid, mediaType) { return bid.mediaTypes.hasOwnProperty(mediaType); } diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js index c7e2f427a4c..90c4c4fd559 100644 --- a/test/spec/modules/michaoBidAdapter_spec.js +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -126,6 +126,58 @@ describe('the michao bidder adapter', () => { }); }); + it('Native bid requests are converted to video server request objects', () => { + const nativeBidRequest = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { + native: { + ortb: { + assets: [ + { + id: 2, + required: 1, + title: { + len: 80 + } + } + ] + } + } + }, + params: { + site: 123, + placement: 456, + }, + }; + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: '15246a574e859f', + bids: [nativeBidRequest], + }; + + const result = buildRequest(nativeBidRequest, bidderRequest, 'native'); + + expect(result).to.nested.include({ + url: 'https://rtb.michao-ssp.com/openrtb/prebid', + 'options.contentType': 'application/json', + 'options.withCredentials': true, + method: 'POST', + 'data.cur[0]': 'USD', + 'data.imp[0].ext.placement': '456', + 'data.site.id': '123', + 'data.test': 0, + }); + }); + it('Converted to server request object for testing in debug mode', () => { const bidRequest = { adUnitCode: 'test-div', @@ -467,8 +519,36 @@ describe('the michao bidder adapter', () => { bidder: 'michao', bidderRequestId: 'bidder-request-2', mediaTypes: { - banner: { - sizes: [[300, 250]], + video: { + context: 'outstream', + playerSize: [640, 480], + mimes: ['video/mp4'], + }, + }, + params: { + site: 12, + placement: 12, + }, + }, + { + adUnitCode: 'test-div', + auctionId: 'auction-2', + bidId: 'bid-2', + bidder: 'michao', + bidderRequestId: 'bidder-request-2', + mediaTypes: { + native: { + ortb: { + assets: [ + { + id: 2, + required: 1, + title: { + len: 80 + } + } + ] + } }, }, params: { @@ -486,7 +566,7 @@ describe('the michao bidder adapter', () => { const result = spec.buildRequests(validBidRequests, bidderRequest); - expect(result.length).to.equal(2); + expect(result.length).to.equal(3); }); it('`interpretResponse`', () => { From 222861367b927ddf793f57ff95ae1ef9c8b2a6c3 Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Tue, 3 Dec 2024 06:02:32 +0900 Subject: [PATCH 07/21] Michao Bid Adapter: Change renderer URL --- modules/michaoBidAdapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js index f5d7ba6d757..fb72eda2762 100644 --- a/modules/michaoBidAdapter.js +++ b/modules/michaoBidAdapter.js @@ -18,7 +18,7 @@ const ENV = { NET_REVENUE: true, DEFAULT_CURRENCY: 'USD', RENDERER_URL: - 'https://cdn.jsdelivr.net/npm/in-renderer-js@latest/dist/in-renderer.umd.min.js', + 'https://cdn.jsdelivr.net/npm/in-renderer-js@latest/dist/in-video-renderer.umd.min.js', }; export const spec = { @@ -137,7 +137,7 @@ export function syncUser(gdprConsent) { export function addRenderer(bid) { bid.renderer.push(() => { - const inRenderer = new window.InRenderer(); + const inRenderer = new window.InVideoRenderer(); inRenderer.render(bid.adUnitCode, bid); }); } From 08d9ce2647dd4e7df1c4cfe0e61fc7e25ff1ace1 Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Wed, 4 Dec 2024 03:43:46 +0900 Subject: [PATCH 08/21] Michao Bid Adapter: Support for blocked categories and blocked advertisers --- modules/michaoBidAdapter.js | 2 + test/spec/modules/michaoBidAdapter_spec.js | 72 +++++++++++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js index fb72eda2762..a843496eac6 100644 --- a/modules/michaoBidAdapter.js +++ b/modules/michaoBidAdapter.js @@ -169,6 +169,8 @@ const converter = ortbConverter({ const openRTBBidRequest = buildRequest(imps, bidderRequest, context); openRTBBidRequest.cur = [ENV.DEFAULT_CURRENCY]; openRTBBidRequest.test = config.getConfig('debug') ? 1 : 0; + openRTBBidRequest.bcat = bidRequest.params?.bcat || []; + openRTBBidRequest.badv = bidRequest.params?.badv || []; deepSetValue( openRTBBidRequest, 'site.id', diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js index 90c4c4fd559..259b08d1ac9 100644 --- a/test/spec/modules/michaoBidAdapter_spec.js +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -212,7 +212,7 @@ describe('the michao bidder adapter', () => { }); }); - it('Specifying a reward builds a bid request for the reward.', () => { + it('Specifying a reward builds a bid request for the reward', () => { const bidRequest = { adUnitCode: 'test-div', auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', @@ -246,6 +246,76 @@ describe('the michao bidder adapter', () => { 'data.imp[0].rwdd': 1, }); }); + + it('Block categories are set in the bid request through parameters', () => { + const bidRequest = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { banner: [[300, 250]] }, + params: { + site: 123, + placement: 456, + bcat: ['IAB2'] + }, + }; + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: '15246a574e859f', + bids: [bidRequest], + }; + config.setConfig({ + debug: true, + }); + + const result = buildRequest(bidRequest, bidderRequest, 'banner'); + + expect(result).to.nested.include({ + 'data.bcat[0]': 'IAB2', + }); + }); + + it('Block advertisers set in bid request through parameters', () => { + const bidRequest = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { banner: [[300, 250]] }, + params: { + site: 123, + placement: 456, + badv: ['adomain.com'] + }, + }; + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: '15246a574e859f', + bids: [bidRequest], + }; + config.setConfig({ + debug: true, + }); + + const result = buildRequest(bidRequest, bidderRequest, 'banner'); + + expect(result).to.nested.include({ + 'data.badv[0]': 'adomain.com', + }); + }); }); describe('interpret response', () => { From dfd29c96990d49c614bb7cf259161ab2b1739684 Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Wed, 4 Dec 2024 10:00:47 +0900 Subject: [PATCH 09/21] Michao Bid Adapter: Change placement to string type --- modules/michaoBidAdapter.js | 11 ++++--- modules/michaoBidAdapter.md | 33 +++++++++++++++++-- test/spec/modules/michaoBidAdapter_spec.js | 38 +++++++++++----------- 3 files changed, 57 insertions(+), 25 deletions(-) diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js index a843496eac6..8b598617dac 100644 --- a/modules/michaoBidAdapter.js +++ b/modules/michaoBidAdapter.js @@ -5,6 +5,7 @@ import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; import { Renderer } from '../src/Renderer.js'; import { deepSetValue, + isNumber, isStr, logError, replaceAuctionPrice, @@ -149,11 +150,13 @@ export function hasParamsObject(bid) { export function validateMichaoParams(params) { let valid = true; - const michaoAdUnitInfoParams = ['site', 'placement']; + if (!isNumber(params?.site)) { + valid = false; + } - valid = michaoAdUnitInfoParams.every((michaoParam) => - Number.isFinite(params[michaoParam]) - ); + if (!isStr(params?.placement)) { + valid = false; + } return valid } diff --git a/modules/michaoBidAdapter.md b/modules/michaoBidAdapter.md index 8767d04abd7..b45e8e2b5bd 100644 --- a/modules/michaoBidAdapter.md +++ b/modules/michaoBidAdapter.md @@ -13,6 +13,7 @@ Module that connects to Michao’s demand sources Supported Ad format: * Banner * Video (instream and outstream) +* Native # Test Parameters ``` @@ -29,7 +30,7 @@ var adUnits = [ bidder: 'michao', params: { site: 1, - placement: 1, + placement: '1', } }] }, @@ -50,7 +51,35 @@ var adUnits = [ bidder: 'michao', params: { site: 1, - placement: 1, + placement: '1', + } + }] + }, + // Native AdUnit + { + code: 'native-div', + mediaTypes: { + native: { + ortb: { + assets: [ + { + id: 1, + required: 1, + img: { + type: 3, + w: 989, + h: 742, + }, + }, + ] + } + } + }, + bids: [{ + bidder: 'michao', + params: { + site: 1, + placement: '1', } }] } diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js index 259b08d1ac9..fce71baea58 100644 --- a/test/spec/modules/michaoBidAdapter_spec.js +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -34,7 +34,7 @@ describe('the michao bidder adapter', () => { it('If the site ID and placement ID are correct, the verification succeeds.', () => { const params = { site: 123, - placement: 234, + placement: 'placement' }; const result = validateMichaoParams(params); @@ -57,7 +57,7 @@ describe('the michao bidder adapter', () => { mediaTypes: { banner: [[300, 250]] }, params: { site: 123, - placement: 456, + placement: '456', }, }; const bidderRequest = { @@ -101,7 +101,7 @@ describe('the michao bidder adapter', () => { }, params: { site: 123, - placement: 456, + placement: '456', }, }; const bidderRequest = { @@ -153,7 +153,7 @@ describe('the michao bidder adapter', () => { }, params: { site: 123, - placement: 456, + placement: '456', }, }; const bidderRequest = { @@ -191,7 +191,7 @@ describe('the michao bidder adapter', () => { mediaTypes: { banner: [[300, 250]] }, params: { site: 123, - placement: 456, + placement: '456', }, }; const bidderRequest = { @@ -225,7 +225,7 @@ describe('the michao bidder adapter', () => { mediaTypes: { banner: [[300, 250]] }, params: { site: 123, - placement: 456, + placement: '456', reward: true, }, }; @@ -260,7 +260,7 @@ describe('the michao bidder adapter', () => { mediaTypes: { banner: [[300, 250]] }, params: { site: 123, - placement: 456, + placement: '456', bcat: ['IAB2'] }, }; @@ -295,7 +295,7 @@ describe('the michao bidder adapter', () => { mediaTypes: { banner: [[300, 250]] }, params: { site: 123, - placement: 456, + placement: '456', badv: ['adomain.com'] }, }; @@ -361,7 +361,7 @@ describe('the michao bidder adapter', () => { mediaTypes: { banner: [[300, 250]] }, params: { site: 123, - placement: 456, + placement: '456', }, }; const bidderRequest = { @@ -400,7 +400,7 @@ describe('the michao bidder adapter', () => { mediaTypes: { banner: [[300, 250]] }, params: { site: 123, - placement: 456, + placement: '456', }, }; const bidderRequest = { @@ -468,7 +468,7 @@ describe('the michao bidder adapter', () => { }, params: { site: 123, - placement: 456, + placement: '456', }, }; const bidderRequest = { @@ -526,7 +526,7 @@ describe('the michao bidder adapter', () => { mediaTypes: { banner: [[300, 250]] }, params: { site: 123, - placement: 456, + placement: '456', }, burl: 'https://example.com/burl', }; @@ -554,8 +554,8 @@ describe('the michao bidder adapter', () => { it('`isBidRequestValid`', () => { const validBidRequest = { params: { - placement: 124, - site: 456, + placement: '124', + site: 234, }, }; @@ -579,7 +579,7 @@ describe('the michao bidder adapter', () => { }, params: { site: 12, - placement: 12, + placement: '12', }, }, { @@ -597,7 +597,7 @@ describe('the michao bidder adapter', () => { }, params: { site: 12, - placement: 12, + placement: '12', }, }, { @@ -623,7 +623,7 @@ describe('the michao bidder adapter', () => { }, params: { site: 12, - placement: 12, + placement: '12', }, }, ]; @@ -685,7 +685,7 @@ describe('the michao bidder adapter', () => { }, params: { site: 123, - placement: 456, + placement: '456', }, }; const bidderRequest = { @@ -744,7 +744,7 @@ describe('the michao bidder adapter', () => { mediaTypes: { banner: [[300, 250]] }, params: { site: 123, - placement: 456, + placement: '456', }, burl: 'https://example.com/burl', }; From 1fb9d7e654da05bc20632f5fe0a19c40b89f272e Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Wed, 4 Dec 2024 10:24:31 +0900 Subject: [PATCH 10/21] Michao Bid Adapter: Add minimum bid price --- modules/michaoBidAdapter.js | 1 + test/spec/modules/michaoBidAdapter_spec.js | 35 ++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js index 8b598617dac..953f0e05268 100644 --- a/modules/michaoBidAdapter.js +++ b/modules/michaoBidAdapter.js @@ -190,6 +190,7 @@ const converter = ortbConverter({ const imp = buildImp(bidRequest, context); deepSetValue(imp, 'ext.placement', bidRequest.params.placement.toString()); deepSetValue(imp, 'rwdd', bidRequest.params?.reward ? 1 : 0); + deepSetValue(imp, 'bidfloor', isNumber(bidRequest.params?.bidFloor) ? bidRequest.params?.bidFloor : 0); return imp; }, diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js index fce71baea58..adf76b633ea 100644 --- a/test/spec/modules/michaoBidAdapter_spec.js +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -316,6 +316,41 @@ describe('the michao bidder adapter', () => { 'data.badv[0]': 'adomain.com', }); }); + + it('The lowest bid will be set', () => { + const bidRequest = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { banner: [[300, 250]] }, + params: { + site: 123, + placement: '456', + bidFloor: 1, + }, + }; + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: '15246a574e859f', + bids: [bidRequest], + }; + config.setConfig({ + debug: true, + }); + + const result = buildRequest(bidRequest, bidderRequest, 'banner'); + + expect(result).to.nested.include({ + 'data.imp[0].bidfloor': 1, + }); + }); }); describe('interpret response', () => { From 0c0d5e4fe5386eb2a05fc20eda3e34d62ca4e734 Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Wed, 4 Dec 2024 10:51:59 +0900 Subject: [PATCH 11/21] Michao Bid Adapter: Added log system validation to integration testing for parameter validation --- test/spec/modules/michaoBidAdapter_spec.js | 37 ++++++++++++++++------ 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js index adf76b633ea..47dea68b538 100644 --- a/test/spec/modules/michaoBidAdapter_spec.js +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -3,6 +3,7 @@ import { addRenderer, billBid, buildRequest, + domainLogger, interpretResponse, spec, syncUser, @@ -586,17 +587,35 @@ describe('the michao bidder adapter', () => { }); describe('integration', () => { - it('`isBidRequestValid`', () => { - const validBidRequest = { - params: { - placement: '124', - site: 234, - }, - }; + describe('`isBidRequestValid`', () => { + it('Happy path', () => { + const validBidRequest = { + params: { + placement: '124', + site: 234, + }, + }; + + const result = spec.isBidRequestValid(validBidRequest); - const result = spec.isBidRequestValid(validBidRequest); + expect(result).to.true; + }); - expect(result).to.true; + it('If the parameter is invalid, it will be logged', () => { + const validationErrorLog = sinon.spy(domainLogger, 'bidRequestValidationError'); + const validBidRequest = { + params: { + placement: '124', + site: '234', + }, + }; + + const result = spec.isBidRequestValid(validBidRequest); + + expect(result).to.false; + expect(validationErrorLog.calledOnce).to.true; + validationErrorLog.restore(); + }); }); it('`buildRequests`', () => { From b869d1c22a822f8d877bd7d430a1a725e39ffc29 Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Thu, 12 Dec 2024 15:12:00 +0900 Subject: [PATCH 12/21] Michao Bid Adapter: Add partner ID parameter --- modules/michaoBidAdapter.js | 4 +++ test/spec/modules/michaoBidAdapter_spec.js | 35 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js index 953f0e05268..c79137c2a61 100644 --- a/modules/michaoBidAdapter.js +++ b/modules/michaoBidAdapter.js @@ -183,6 +183,10 @@ const converter = ortbConverter({ deepSetValue(openRTBBidRequest, 'source.schain', bidRequest.schain); } + if (bidRequest.params.partner) { + deepSetValue(openRTBBidRequest, 'site.publisher.ext.partner', bidRequest.params.partner.toString()) + } + return openRTBBidRequest; }, diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js index 47dea68b538..8a6f054ad7d 100644 --- a/test/spec/modules/michaoBidAdapter_spec.js +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -352,6 +352,41 @@ describe('the michao bidder adapter', () => { 'data.imp[0].bidfloor': 1, }); }); + + it('Partner ID is set from Partner ID parameter', () => { + const bidRequest = { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'michao', + bidderRequestId: '15246a574e859f', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { banner: [[300, 250]] }, + params: { + site: 123, + placement: '456', + partner: 11, + }, + }; + const bidderRequest = { + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: '15246a574e859f', + bids: [bidRequest], + }; + config.setConfig({ + debug: true, + }); + + const result = buildRequest(bidRequest, bidderRequest, 'banner'); + + expect(result).to.nested.include({ + 'data.site.publisher.ext.partner': '11', + }); + }); }); describe('interpret response', () => { From 32920941479c82809637985212b71986e9cfbf4d Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Fri, 13 Dec 2024 11:08:31 +0900 Subject: [PATCH 13/21] Michao Bid Adapter: Refactoring --- modules/michaoBidAdapter.js | 298 ++-- test/spec/modules/michaoBidAdapter_spec.js | 1564 +++++++++++--------- 2 files changed, 1038 insertions(+), 824 deletions(-) diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js index c79137c2a61..9afc57bb63e 100644 --- a/modules/michaoBidAdapter.js +++ b/modules/michaoBidAdapter.js @@ -5,6 +5,8 @@ import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; import { Renderer } from '../src/Renderer.js'; import { deepSetValue, + isArray, + isBoolean, isNumber, isStr, logError, @@ -27,15 +29,79 @@ export const spec = { supportedMediaTypes: ENV.SUPPORTED_MEDIA_TYPES, isBidRequestValid: function (bid) { - if (!hasParamsObject(bid)) { + const params = bid.params; + + if (!isNumber(params?.site)) { + domainLogger.invalidSiteError(params?.site); return false; } - if (!validateMichaoParams(bid.params)) { - domainLogger.bidRequestValidationError(); + if (!isStr(params?.placement)) { + domainLogger.invalidPlacementError(params?.placement); return false; } + if (params?.partner) { + if (!isNumber(params?.partner)) { + domainLogger.invalidPartnerError(params?.partner); + return false; + } + } + + if (params?.badv) { + if (!isArray(params?.badv)) { + domainLogger.invalidBadvError(params?.badv); + return false; + } + } + + if (params?.bcat) { + if (!isArray(params?.bcat)) { + domainLogger.invalidBcatError(params?.bcat); + return false; + } + } + + if (bid.params?.reward) { + if (!isBoolean(params?.reward)) { + domainLogger.invalidRewardError(params?.reward); + return false; + } + } + + const video = bid.mediaTypes?.video; + if (video) { + if (!video.context) { + domainLogger.invalidVideoContext(); + return false; + } + + if (!video.playerSize || !Array.isArray(video.playerSize)) { + domainLogger.invalidVideoPlayerSize(); + return false; + } + + if (!isNumber(video.minduration)) { + domainLogger.invalidVideoMinDuration(); + return false; + } + + if (!isNumber(video.maxduration)) { + domainLogger.invalidVideoMaxDuration(); + return false; + } + + if (!Array.isArray(video.mimes) || video.mimes.length === 0) { + domainLogger.invalidVideoMimes(); + return false; + } + + if (!Array.isArray(video.protocols) || video.protocols.length === 0) { + domainLogger.invalidVideoProtocols(); + return false; + } + } + return true; }, @@ -43,28 +109,46 @@ export const spec = { const bidRequests = []; validBidRequests.forEach((validBidRequest) => { - if (hasVideoMediaType(validBidRequest)) { - bidRequests.push(buildRequest(validBidRequest, bidderRequest, 'video')); + let bidRequestEachFormat = []; + + if (validBidRequest.mediaTypes?.banner) { + bidRequestEachFormat.push({ + ...validBidRequest, + mediaTypes: { + banner: validBidRequest.mediaTypes.banner, + }, + }); } - if (hasBannerMediaType(validBidRequest)) { - bidRequests.push( - buildRequest(validBidRequest, bidderRequest, 'banner') - ); + if (validBidRequest.mediaTypes?.video) { + bidRequestEachFormat.push({ + ...validBidRequest, + mediaTypes: { + video: validBidRequest.mediaTypes.video, + }, + }); } - if (hasNativeMediaType(validBidRequest)) { - bidRequests.push( - buildRequest(validBidRequest, bidderRequest, 'native') - ); + if (validBidRequest.mediaTypes?.native) { + bidRequestEachFormat.push({ + ...validBidRequest, + mediaTypes: { + native: validBidRequest.mediaTypes.native, + }, + }); } + + bidRequests.push(buildRequest(bidRequestEachFormat, bidderRequest)); }); return bidRequests; }, interpretResponse: function (serverResponse, request) { - return interpretResponse(serverResponse, request); + return converter.fromORTB({ + response: serverResponse.body, + request: request.data, + }).bids; }, getUserSyncs: function ( @@ -74,30 +158,92 @@ export const spec = { uspConsent ) { if (syncOptions.iframeEnabled) { - return [syncUser(gdprConsent)]; + return [ + { + type: 'iframe', + url: + 'https://sync.michao-ssp.com/cookie-syncs?' + + generateGdprParams(gdprConsent), + }, + ]; } + + return []; }, onBidBillable: function (bid) { if (bid.burl && isStr(bid.burl)) { - billBid(bid); + triggerPixel(generateBillableUrl(bid)); } }, }; export const domainLogger = { - bidRequestValidationError() { - logError('Michao Bid Adapter: wrong format of site or placement.'); + invalidSiteError(value) { + logError( + `Michao Bid Adapter: Invalid site ID. Expected number, got ${typeof value}. Value: ${value}` + ); + }, + + invalidPlacementError(value) { + logError( + `Michao Bid Adapter: Invalid placement. Expected string, got ${typeof value}. Value: ${value}` + ); + }, + + invalidPartnerError(value) { + logError( + `Michao Bid Adapter: Invalid partner ID. Expected number, got ${typeof value}. Value: ${value}` + ); + }, + + invalidBadvError(value) { + logError( + `Michao Bid Adapter: Invalid badv. Expected array, got ${typeof value}` + ); + }, + + invalidBcatError(value) { + logError( + `Michao Bid Adapter: Invalid bcat. Expected array, got ${typeof value}` + ); + }, + + invalidRewardError(value) { + logError( + `Michao Bid Adapter: Invalid reward. Expected boolean, got ${typeof value}. Value: ${value}` + ); + }, + + invalidVideoContext() { + logError('Michao Bid Adapter: Video context is not set'); + }, + + invalidVideoPlayerSize() { + logError('Michao Bid Adapter: Video playerSize is not set or invalid'); + }, + + invalidVideoMinDuration() { + logError('Michao Bid Adapter: Video minDuration is not set or invalid'); + }, + + invalidVideoMaxDuration() { + logError('Michao Bid Adapter: Video maxDuration is not set or invalid'); + }, + + invalidVideoMimes() { + logError('Michao Bid Adapter: Video mimes is not set or invalid'); + }, + + invalidVideoProtocols() { + logError('Michao Bid Adapter: Video protocols is not set or invalid'); }, }; -export function buildRequest(bidRequest, bidderRequest, mediaType) { +function buildRequest(bidRequests, bidderRequest) { const openRTBBidRequest = converter.toORTB({ - bidRequests: [bidRequest], + bidRequests: bidRequests, bidderRequest, - context: { - mediaType: mediaType, - }, }); return { @@ -108,62 +254,22 @@ export function buildRequest(bidRequest, bidderRequest, mediaType) { }; } -export function interpretResponse(response, request) { - const bids = converter.fromORTB({ - response: response.body, - request: request.data, - }).bids; - - return bids; -} - -export function syncUser(gdprConsent) { +function generateGdprParams(gdprConsent) { let gdprParams = ''; if (typeof gdprConsent === 'object') { - if (typeof gdprConsent.gdprApplies === 'boolean') { + if (gdprConsent?.gdprApplies) { gdprParams = `gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${ - gdprConsent.consentString + gdprConsent.consentString || '' }`; - } else { - gdprParams = `gdpr_consent=${gdprConsent.consentString}`; } } - return { - type: 'iframe', - url: 'https://sync.michao-ssp.com/cookie-syncs?' + gdprParams, - }; + return gdprParams; } -export function addRenderer(bid) { - bid.renderer.push(() => { - const inRenderer = new window.InVideoRenderer(); - inRenderer.render(bid.adUnitCode, bid); - }); -} - -export function hasParamsObject(bid) { - return typeof bid.params === 'object'; -} - -export function validateMichaoParams(params) { - let valid = true; - - if (!isNumber(params?.site)) { - valid = false; - } - - if (!isStr(params?.placement)) { - valid = false; - } - - return valid -} - -export function billBid(bid) { - bid.burl = replaceAuctionPrice(bid.burl, bid.originalCpm || bid.cpm); - triggerPixel(bid.burl); +function generateBillableUrl(bid) { + return replaceAuctionPrice(bid.burl, bid.originalCpm || bid.cpm); } const converter = ortbConverter({ @@ -184,7 +290,11 @@ const converter = ortbConverter({ } if (bidRequest.params.partner) { - deepSetValue(openRTBBidRequest, 'site.publisher.ext.partner', bidRequest.params.partner.toString()) + deepSetValue( + openRTBBidRequest, + 'site.publisher.ext.partner', + bidRequest.params.partner.toString() + ); } return openRTBBidRequest; @@ -194,25 +304,35 @@ const converter = ortbConverter({ const imp = buildImp(bidRequest, context); deepSetValue(imp, 'ext.placement', bidRequest.params.placement.toString()); deepSetValue(imp, 'rwdd', bidRequest.params?.reward ? 1 : 0); - deepSetValue(imp, 'bidfloor', isNumber(bidRequest.params?.bidFloor) ? bidRequest.params?.bidFloor : 0); + deepSetValue( + imp, + 'bidfloor', + isNumber(bidRequest.params?.bidFloor) ? bidRequest.params?.bidFloor : 0 + ); return imp; }, bidResponse(buildBidResponse, bid, context) { + const bidResponse = buildBidResponse(bid, context); const { bidRequest } = context; - let bidResponse = buildBidResponse(bid, context); - if (hasVideoMediaType(bidRequest)) { + if ( + bidResponse.mediaType === VIDEO && + bidRequest.mediaTypes.video.context === 'outstream' + ) { bidResponse.vastXml = bid.adm; - if (bidRequest.mediaTypes.video?.context === 'outstream') { - const renderer = Renderer.install({ - id: bid.bidId, - url: ENV.RENDERER_URL, - adUnitCode: bid.adUnitCode, + const renderer = Renderer.install({ + url: ENV.RENDERER_URL, + id: bidRequest.bidId, + adUnitCode: bidRequest.adUnitCode, + }); + renderer.render(() => { + bid.renderer.push(() => { + const inRenderer = new window.InVideoRenderer(); + inRenderer.render(bid.adUnitCode, bid); }); - renderer.setRender(addRenderer); - bidResponse.renderer = renderer; - } + }); + bidResponse.renderer = renderer; } return bidResponse; @@ -225,20 +345,4 @@ const converter = ortbConverter({ }, }); -function hasBannerMediaType(bid) { - return hasMediaType(bid, 'banner'); -} - -function hasVideoMediaType(bid) { - return hasMediaType(bid, 'video'); -} - -function hasNativeMediaType(bid) { - return hasMediaType(bid, 'native'); -} - -function hasMediaType(bid, mediaType) { - return bid.mediaTypes.hasOwnProperty(mediaType); -} - registerBidder(spec); diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js index 8a6f054ad7d..891c14fba49 100644 --- a/test/spec/modules/michaoBidAdapter_spec.js +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -1,847 +1,957 @@ -import { expect } from 'chai'; -import { - addRenderer, - billBid, - buildRequest, - domainLogger, - interpretResponse, - spec, - syncUser, - validateMichaoParams, -} from '../../../modules/michaoBidAdapter'; -import * as utils from 'src/utils.js'; -import { config } from '../../../src/config'; - -describe('the michao bidder adapter', () => { +import { cloneDeep } from 'lodash'; +import { domainLogger, spec } from '../../../modules/michaoBidAdapter'; +import * as utils from '../../../src/utils.js'; + +describe('Michao Bid Adapter', () => { + let bannerBidRequest; + let videoBidRequest; + let nativeBidRequest; + let videoServerResponse; + let bannerServerResponse; + let domainLoggerMock; + let sandbox; + let triggerPixelSpy; + beforeEach(() => { - config.resetConfig(); + bannerBidRequest = cloneDeep(_bannerBidRequest); + videoBidRequest = cloneDeep(_videoBidRequest); + nativeBidRequest = cloneDeep(_nativeBidRequest); + videoServerResponse = cloneDeep(_videoServerResponse); + bannerServerResponse = cloneDeep(_bannerServerResponse); + sandbox = sinon.sandbox.create(); + domainLoggerMock = sandbox.stub(domainLogger); + triggerPixelSpy = sandbox.spy(utils, 'triggerPixel'); + }); + + afterEach(() => { + sandbox.restore(); }); - describe('unit', () => { - describe('validate bid request', () => { - const invalidBidParams = [ - { site: '123', placement: 'super-placement' }, - { site: '123', placement: 456 }, - { site: Infinity, placement: 456 }, - ]; - invalidBidParams.forEach((params) => { - it('Detecting incorrect parameters', () => { - const result = validateMichaoParams(params); + describe('`isBidRequestValid`', () => { + describe('Required parameter behavior', () => { + it('passes when siteId is a number', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + site: 123, + }; + + const result = spec.isBidRequestValid(bannerBidRequest); - expect(result).to.be.false; - }); + expect(result).to.be.true; + expect(domainLoggerMock.invalidSiteError.calledOnce).to.be.false; }); - it('If the site ID and placement ID are correct, the verification succeeds.', () => { - const params = { - site: 123, - placement: 'placement' + it('detects invalid input when siteId is not a number', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + site: '123', }; - const result = validateMichaoParams(params); + const result = spec.isBidRequestValid(bannerBidRequest); + + expect(result).to.be.false; + expect(domainLoggerMock.invalidSiteError.calledOnce).to.be.true; + }); + + it('passes when placementId is a string', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + placement: '123', + }; + + const result = spec.isBidRequestValid(bannerBidRequest); expect(result).to.be.true; + expect(domainLoggerMock.invalidPlacementError.calledOnce).to.be.false; + }); + + it('detects invalid input when placementId is not a string', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + placement: 123, + }; + + const result = spec.isBidRequestValid(bannerBidRequest); + + expect(result).to.be.false; + expect(domainLoggerMock.invalidPlacementError.calledOnce).to.be.true; }); }); - describe('build bid request', () => { - it('Banner bid requests are converted to banner server request objects', () => { - const bannerBidRequest = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '22c4871113f461', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { banner: [[300, 250]] }, - params: { - site: 123, - placement: '456', - }, + describe('mediaTypes behavior', () => { + it('passes when video context is instream', () => { + videoBidRequest.mediaTypes.video = { + ...videoBidRequest.mediaTypes.video, + context: 'instream', }; + + const result = spec.isBidRequestValid(videoBidRequest); + + expect(result).to.be.true; + expect(domainLoggerMock.invalidVideoContext.calledOnce).to.be.false; + }); + + it('passes when video playerSize is valid array', () => { + videoBidRequest.mediaTypes.video = { + ...videoBidRequest.mediaTypes.video, + playerSize: [[640, 480]], + }; + + const result = spec.isBidRequestValid(videoBidRequest); + + expect(result).to.be.true; + expect(domainLoggerMock.invalidVideoPlayerSize.calledOnce).to.be.false; + }); + + it('passes when valid video minDuration is set', () => { + videoBidRequest.mediaTypes.video = { + ...videoBidRequest.mediaTypes.video, + minduration: 5, + }; + + const result = spec.isBidRequestValid(videoBidRequest); + + expect(result).to.be.true; + expect(domainLoggerMock.invalidVideoMinDuration.calledOnce).to.be.false; + }); + + it('passes when valid video maxDuration is set', () => { + videoBidRequest.mediaTypes.video = { + ...videoBidRequest.mediaTypes.video, + maxduration: 30, + }; + + const result = spec.isBidRequestValid(videoBidRequest); + + expect(result).to.be.true; + expect(domainLoggerMock.invalidVideoMaxDuration.calledOnce).to.be.false; + }); + + it('passes when valid video mimes are set', () => { + videoBidRequest.mediaTypes.video = { + ...videoBidRequest.mediaTypes.video, + mimes: ['video/mp4'], + }; + + const result = spec.isBidRequestValid(videoBidRequest); + + expect(result).to.be.true; + expect(domainLoggerMock.invalidVideoMimes.calledOnce).to.be.false; + }); + + it('detects invalid input when video context is not set', () => { + videoBidRequest.mediaTypes.video = { + ...videoBidRequest.mediaTypes.video, + context: undefined, + }; + + const result = spec.isBidRequestValid(videoBidRequest); + + expect(result).to.be.false; + expect(domainLoggerMock.invalidVideoContext.calledOnce).to.be.true; + }); + + it('detects invalid input when video playerSize is not set', () => { + videoBidRequest.mediaTypes.video = { + ...videoBidRequest.mediaTypes.video, + playerSize: undefined, + }; + + const result = spec.isBidRequestValid(videoBidRequest); + + expect(result).to.be.false; + expect(domainLoggerMock.invalidVideoPlayerSize.calledOnce).to.be.true; + }); + + it('detects invalid input when video minDuration is not set', () => { + videoBidRequest.mediaTypes.video = { + ...videoBidRequest.mediaTypes.video, + minduration: undefined, + }; + + const result = spec.isBidRequestValid(videoBidRequest); + + expect(result).to.be.false; + expect(domainLoggerMock.invalidVideoMinDuration.calledOnce).to.be.true; + }); + + it('detects invalid input when video maxDuration is not set', () => { + videoBidRequest.mediaTypes.video = { + ...videoBidRequest.mediaTypes.video, + maxduration: undefined, + }; + + const result = spec.isBidRequestValid(videoBidRequest); + + expect(result).to.be.false; + expect(domainLoggerMock.invalidVideoMaxDuration.calledOnce).to.be.true; + }); + + it('detects invalid input when video mimes is not set', () => { + videoBidRequest.mediaTypes.video = { + ...videoBidRequest.mediaTypes.video, + mimes: undefined, + }; + + const result = spec.isBidRequestValid(videoBidRequest); + + expect(result).to.be.false; + expect(domainLoggerMock.invalidVideoMimes.calledOnce).to.be.true; + }); + + it('detects invalid input when video protocols is not set', () => { + videoBidRequest.mediaTypes.video = { + ...videoBidRequest.mediaTypes.video, + protocols: undefined, + }; + + const result = spec.isBidRequestValid(videoBidRequest); + + expect(result).to.be.false; + expect(domainLoggerMock.invalidVideoProtocols.calledOnce).to.be.true; + }); + }); + + describe('Optional parameter behavior', () => { + it('passes when partnerId is not specified', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + partner: undefined, + }; + + const result = spec.isBidRequestValid(bannerBidRequest); + + expect(result).to.be.true; + expect(domainLoggerMock.invalidPartnerError.calledOnce).to.be.false; + }); + + it('passes when partnerId is a number', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + partner: 6789, + }; + + const result = spec.isBidRequestValid(bannerBidRequest); + + expect(result).to.be.true; + expect(domainLoggerMock.invalidPartnerError.calledOnce).to.be.false; + }); + + it('detects invalid input when partnerId is not a number', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + partner: '6789', + }; + + const result = spec.isBidRequestValid(bannerBidRequest); + + expect(result).to.be.false; + expect(domainLoggerMock.invalidPartnerError.calledOnce).to.be.true; + }); + + it('passes when blockCategories is not specified', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + bcat: undefined, + }; + + const result = spec.isBidRequestValid(bannerBidRequest); + + expect(result).to.be.true; + expect(domainLoggerMock.invalidBcatError.calledOnce).to.be.false; + }); + + it('passes when blockCategories is an array', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + bcat: ['IAB2'], + }; + + const result = spec.isBidRequestValid(bannerBidRequest); + + expect(result).to.be.true; + expect(domainLoggerMock.invalidBcatError.calledOnce).to.be.false; + }); + + it('detects invalid input when blockCategories is not an array', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + bcat: 'IAB2', + }; + + const result = spec.isBidRequestValid(bannerBidRequest); + + expect(result).to.be.false; + expect(domainLoggerMock.invalidBcatError.calledOnce).to.be.true; + }); + + it('passes when blockAdvertisers is not specified', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + badv: undefined, + }; + + const result = spec.isBidRequestValid(bannerBidRequest); + + expect(result).to.be.true; + expect(domainLoggerMock.invalidBadvError.calledOnce).to.be.false; + }); + + it('passes when blockAdvertisers is an array', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + badv: ['adomain.com'], + }; + + const result = spec.isBidRequestValid(bannerBidRequest); + + expect(result).to.be.true; + expect(domainLoggerMock.invalidBadvError.calledOnce).to.be.false; + }); + + it('detects invalid input when blockAdvertisers is not an array', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + badv: 'adomain.com', + }; + + const result = spec.isBidRequestValid(bannerBidRequest); + + expect(result).to.be.false; + expect(domainLoggerMock.invalidBadvError.calledOnce).to.be.true; + }); + + it('passes when reward is not specified', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + reward: undefined, + }; + + const result = spec.isBidRequestValid(bannerBidRequest); + + expect(result).to.be.true; + expect(domainLoggerMock.invalidRewardError.calledOnce).to.be.false; + }); + + it('passes when reward is a boolean', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + reward: true, + }; + + const result = spec.isBidRequestValid(bannerBidRequest); + + expect(result).to.be.true; + expect(domainLoggerMock.invalidRewardError.calledOnce).to.be.false; + }); + + it('detects invalid input when reward is not a boolean', () => { + bannerBidRequest.params = { + ...bannerBidRequest.params, + reward: 'true', + }; + + const result = spec.isBidRequestValid(bannerBidRequest); + + expect(result).to.be.false; + expect(domainLoggerMock.invalidRewardError.calledOnce).to.be.true; + }); + }); + }); + + describe('`buildRequest`', () => { + describe('Bid request format behavior', () => { + it('creates banner-specific bid request from bid request containing one banner format', () => { const bidderRequest = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: 1579746300522, - bidderCode: 'michao', - bidderRequestId: '15246a574e859f', bids: [bannerBidRequest], + auctionId: bannerBidRequest.auctionId, + bidderRequestId: bannerBidRequest.bidderRequestId, }; - const result = buildRequest(bannerBidRequest, bidderRequest, 'banner'); - - expect(result).to.nested.include({ - url: 'https://rtb.michao-ssp.com/openrtb/prebid', - 'options.contentType': 'application/json', - 'options.withCredentials': true, - method: 'POST', - 'data.cur[0]': 'USD', - 'data.imp[0].ext.placement': '456', - 'data.site.id': '123', - 'data.test': 0, - }); - }); - - it('Video bid requests are converted to video server request objects', () => { - const videoBidRequest = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '22c4871113f461', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { - video: { - context: 'outstream', - playerSize: [640, 480], - mimes: ['video/mp4'], - }, - }, - params: { - site: 123, - placement: '456', - }, - }; + const result = spec.buildRequests([bannerBidRequest], bidderRequest); + + expect(result.length).to.equal(1); + expect(result[0].data.imp.length).to.equal(1); + expect(result[0].data.imp[0]).to.have.haveOwnPropertyDescriptor( + 'banner' + ); + }); + + it('creates video-specific bid request from bid request containing one video format', () => { const bidderRequest = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: 1579746300522, - bidderCode: 'michao', - bidderRequestId: '15246a574e859f', bids: [videoBidRequest], + auctionId: videoBidRequest.auctionId, + bidderRequestId: videoBidRequest.bidderRequestId, }; - const result = buildRequest(videoBidRequest, bidderRequest, 'banner'); - - expect(result).to.nested.include({ - url: 'https://rtb.michao-ssp.com/openrtb/prebid', - 'options.contentType': 'application/json', - 'options.withCredentials': true, - method: 'POST', - 'data.cur[0]': 'USD', - 'data.imp[0].ext.placement': '456', - 'data.site.id': '123', - 'data.test': 0, - }); - }); - - it('Native bid requests are converted to video server request objects', () => { - const nativeBidRequest = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '22c4871113f461', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { - native: { - ortb: { - assets: [ - { - id: 2, - required: 1, - title: { - len: 80 - } - } - ] - } - } - }, - params: { - site: 123, - placement: '456', - }, - }; + const result = spec.buildRequests([videoBidRequest], bidderRequest); + + expect(result.length).to.equal(1); + expect(result[0].data.imp.length).to.equal(1); + expect(result[0].data.imp[0]).to.have.haveOwnPropertyDescriptor( + 'video' + ); + }); + + it('creates native-specific bid request from bid request containing one native format', () => { const bidderRequest = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: 1579746300522, - bidderCode: 'michao', - bidderRequestId: '15246a574e859f', bids: [nativeBidRequest], + auctionId: nativeBidRequest.auctionId, + bidderRequestId: nativeBidRequest.bidderRequestId, }; - const result = buildRequest(nativeBidRequest, bidderRequest, 'native'); - - expect(result).to.nested.include({ - url: 'https://rtb.michao-ssp.com/openrtb/prebid', - 'options.contentType': 'application/json', - 'options.withCredentials': true, - method: 'POST', - 'data.cur[0]': 'USD', - 'data.imp[0].ext.placement': '456', - 'data.site.id': '123', - 'data.test': 0, - }); - }); - - it('Converted to server request object for testing in debug mode', () => { - const bidRequest = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '22c4871113f461', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { banner: [[300, 250]] }, - params: { - site: 123, - placement: '456', + const result = spec.buildRequests([nativeBidRequest], bidderRequest); + + expect(result.length).to.equal(1); + expect(result[0].data.imp.length).to.equal(1); + }); + }); + + describe('Multiple format combination behavior', () => { + it('creates banner and video bid request with two impressions from bid request containing both banner and video formats', () => { + const multiFormatRequest = { + ...bannerBidRequest, + mediaTypes: { + ...bannerBidRequest.mediaTypes, + video: videoBidRequest.mediaTypes.video, }, }; + const bidderRequest = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: 1579746300522, - bidderCode: 'michao', - bidderRequestId: '15246a574e859f', - bids: [bidRequest], - }; - config.setConfig({ - debug: true, - }); - - const result = buildRequest(bidRequest, bidderRequest, 'banner'); - - expect(result).to.nested.include({ - 'data.test': 1, - }); - }); - - it('Specifying a reward builds a bid request for the reward', () => { - const bidRequest = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '22c4871113f461', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { banner: [[300, 250]] }, - params: { - site: 123, - placement: '456', - reward: true, - }, + bids: [multiFormatRequest], + auctionId: multiFormatRequest.auctionId, + bidderRequestId: multiFormatRequest.bidderRequestId, }; - const bidderRequest = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: 1579746300522, - bidderCode: 'michao', - bidderRequestId: '15246a574e859f', - bids: [bidRequest], - }; - config.setConfig({ - debug: true, - }); - - const result = buildRequest(bidRequest, bidderRequest, 'banner'); - - expect(result).to.nested.include({ - 'data.imp[0].rwdd': 1, - }); - }); - - it('Block categories are set in the bid request through parameters', () => { - const bidRequest = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '22c4871113f461', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { banner: [[300, 250]] }, - params: { - site: 123, - placement: '456', - bcat: ['IAB2'] + + const result = spec.buildRequests([multiFormatRequest], bidderRequest); + + expect(result.length).to.equal(1); + expect(result[0].data.imp.length).to.equal(2); + expect(result[0].data.imp[0]).to.have.haveOwnPropertyDescriptor( + 'banner' + ); + expect(result[0].data.imp[1]).to.have.haveOwnPropertyDescriptor( + 'video' + ); + }); + + it('creates banner and native bid request with two impressions from bid request containing both banner and native formats', () => { + const multiFormatRequest = { + ...bannerBidRequest, + mediaTypes: { + ...bannerBidRequest.mediaTypes, + native: nativeBidRequest.mediaTypes.native, }, }; + const bidderRequest = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: 1579746300522, - bidderCode: 'michao', - bidderRequestId: '15246a574e859f', - bids: [bidRequest], - }; - config.setConfig({ - debug: true, - }); - - const result = buildRequest(bidRequest, bidderRequest, 'banner'); - - expect(result).to.nested.include({ - 'data.bcat[0]': 'IAB2', - }); - }); - - it('Block advertisers set in bid request through parameters', () => { - const bidRequest = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '22c4871113f461', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { banner: [[300, 250]] }, - params: { - site: 123, - placement: '456', - badv: ['adomain.com'] - }, + bids: [multiFormatRequest], + auctionId: multiFormatRequest.auctionId, + bidderRequestId: multiFormatRequest.bidderRequestId, }; - const bidderRequest = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: 1579746300522, - bidderCode: 'michao', - bidderRequestId: '15246a574e859f', - bids: [bidRequest], - }; - config.setConfig({ - debug: true, - }); - - const result = buildRequest(bidRequest, bidderRequest, 'banner'); - - expect(result).to.nested.include({ - 'data.badv[0]': 'adomain.com', - }); - }); - - it('The lowest bid will be set', () => { - const bidRequest = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '22c4871113f461', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { banner: [[300, 250]] }, - params: { - site: 123, - placement: '456', - bidFloor: 1, + + const result = spec.buildRequests([multiFormatRequest], bidderRequest); + + expect(result.length).to.equal(1); + expect(result[0].data.imp.length).to.equal(2); + expect(result[0].data.imp[0]).to.have.haveOwnPropertyDescriptor( + 'banner' + ); + }); + + it('creates video and native bid request with two impressions from bid request containing both video and native formats', () => { + const multiFormatRequest = { + ...videoBidRequest, + mediaTypes: { + ...videoBidRequest.mediaTypes, + native: nativeBidRequest.mediaTypes.native, }, }; + const bidderRequest = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: 1579746300522, - bidderCode: 'michao', - bidderRequestId: '15246a574e859f', - bids: [bidRequest], - }; - config.setConfig({ - debug: true, - }); - - const result = buildRequest(bidRequest, bidderRequest, 'banner'); - - expect(result).to.nested.include({ - 'data.imp[0].bidfloor': 1, - }); - }); - - it('Partner ID is set from Partner ID parameter', () => { - const bidRequest = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '22c4871113f461', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { banner: [[300, 250]] }, - params: { - site: 123, - placement: '456', - partner: 11, + bids: [multiFormatRequest], + auctionId: multiFormatRequest.auctionId, + bidderRequestId: multiFormatRequest.bidderRequestId, + }; + + const result = spec.buildRequests([multiFormatRequest], bidderRequest); + + expect(result.length).to.equal(1); + expect(result[0].data.imp.length).to.equal(2); + expect(result[0].data.imp[0]).to.have.haveOwnPropertyDescriptor( + 'video' + ); + }); + + it('creates banner, video and native bid request with three impressions from bid request containing all three formats', () => { + const multiFormatRequest = { + ...bannerBidRequest, + mediaTypes: { + ...bannerBidRequest.mediaTypes, + video: videoBidRequest.mediaTypes.video, + native: nativeBidRequest.mediaTypes.native, }, }; + const bidderRequest = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: 1579746300522, - bidderCode: 'michao', - bidderRequestId: '15246a574e859f', - bids: [bidRequest], + bids: [multiFormatRequest], + auctionId: multiFormatRequest.auctionId, + bidderRequestId: multiFormatRequest.bidderRequestId, }; - config.setConfig({ - debug: true, - }); - const result = buildRequest(bidRequest, bidderRequest, 'banner'); + const result = spec.buildRequests([multiFormatRequest], bidderRequest); - expect(result).to.nested.include({ - 'data.site.publisher.ext.partner': '11', - }); + expect(result.length).to.equal(1); + expect(result[0].data.imp.length).to.equal(3); + expect(result[0].data.imp[0]).to.have.haveOwnPropertyDescriptor( + 'banner' + ); + expect(result[0].data.imp[1]).to.have.haveOwnPropertyDescriptor( + 'video' + ); }); }); - describe('interpret response', () => { - it('Server response is interpreted as a bid.', () => { - const response = { - headers: null, - body: { - id: 'requestId', - seatbid: [ - { - bid: [ - { - id: 'bidId1', - impid: 'bidId1', - price: 0.18, - adm: '', - adid: '144762342', - adomain: ['https://dummydomain.com'], - iurl: 'iurl', - cid: '109', - crid: 'creativeId', - cat: [], - w: 300, - h: 250, - mtype: 1, - }, - ], - seat: 'seat', - }, - ], - cur: 'USD', - }, + describe('Required parameter behavior', () => { + it('sets siteId in site object', () => { + bannerBidRequest.params = { + site: 456, + placement: '123', }; - const bannerBidRequest = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: 'bidId1', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { banner: [[300, 250]] }, - params: { - site: 123, - placement: '456', - }, + const bidderRequest = { + bids: [bannerBidRequest], + auctionId: bannerBidRequest.auctionId, + bidderRequestId: bannerBidRequest.bidderRequestId, + }; + + const result = spec.buildRequests([bannerBidRequest], bidderRequest); + + expect(result[0].data.site.id).to.equal('456'); + }); + + it('sets placementId in impression object', () => { + bannerBidRequest.params = { + site: 456, + placement: '123', }; const bidderRequest = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: 1579746300522, - bidderCode: 'michao', - bidderRequestId: '15246a574e859f', bids: [bannerBidRequest], + auctionId: bannerBidRequest.auctionId, + bidderRequestId: bannerBidRequest.bidderRequestId, }; - const request = buildRequest(bannerBidRequest, bidderRequest, 'banner'); - - const result = interpretResponse(response, request); - - expect(result).to.be.an('array'); - expect(result[0]).to.have.property('currency', 'USD'); - expect(result[0]).to.have.property('requestId', 'bidId1'); - expect(result[0]).to.have.property('cpm', 0.18); - expect(result[0]).to.have.property('width', 300); - expect(result[0]).to.have.property('height', 250); - expect(result[0]).to.have.property('ad', ''); - expect(result[0]).to.have.property('creativeId', 'creativeId'); - expect(result[0]).to.have.property('netRevenue', true); - }); - - it('Empty server responses are interpreted as empty bids', () => { - const response = { body: {} }; - const bannerBidRequest = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '22c4871113f461', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { banner: [[300, 250]] }, - params: { - site: 123, - placement: '456', - }, + + const result = spec.buildRequests([bannerBidRequest], bidderRequest); + + expect(result[0].data.imp[0].ext.placement).to.equal('123'); + }); + }); + + describe('Optional parameter behavior', () => { + it('sets partnerId in publisher when specified', () => { + bannerBidRequest.params = { + site: 456, + placement: '123', + partner: 123, }; const bidderRequest = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: 1579746300522, - bidderCode: 'michao', - bidderRequestId: '15246a574e859f', bids: [bannerBidRequest], + auctionId: bannerBidRequest.auctionId, + bidderRequestId: bannerBidRequest.bidderRequestId, }; - const request = buildRequest(bannerBidRequest, bidderRequest, 'banner'); - - const result = interpretResponse(response, request); - - expect(result).to.be.an('array'); - expect(result.length).to.equal(0); - }); - - it('Set renderer with outstream video ads', () => { - const response = { - headers: null, - body: { - id: 'requestId', - seatbid: [ - { - bid: [ - { - id: 'bidId1', - impid: 'bidId1', - price: 0.18, - adm: '', - adid: '144762342', - adomain: ['https://dummydomain.com'], - iurl: 'iurl', - cid: '109', - crid: 'creativeId', - cat: [], - w: 300, - h: 250, - mtype: 1, - }, - ], - seat: 'seat', - }, - ], - cur: 'USD', - }, + + const result = spec.buildRequests([bannerBidRequest], bidderRequest); + + expect(result[0].data.site.publisher.ext.partner).to.equal('123'); + }); + + it('does not set publisher when partnerId is not specified', () => { + bannerBidRequest.params = { + site: 456, + placement: '123', }; - const videoBidRequest = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: 'bidId1', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { - video: { - context: 'outstream', - playerSize: [640, 480], - minduration: 0, - maxduration: 30, - protocols: [7] - }, - }, - params: { - site: 123, - placement: '456', - }, + const bidderRequest = { + bids: [bannerBidRequest], + auctionId: bannerBidRequest.auctionId, + bidderRequestId: bannerBidRequest.bidderRequestId, + }; + + const result = spec.buildRequests([bannerBidRequest], bidderRequest); + + expect(result[0].data.site.publisher).to.be.undefined; + }); + + it('sets reward enabled parameter in impression object when reward is specified', () => { + bannerBidRequest.params = { + site: 456, + placement: '123', + reward: true, }; const bidderRequest = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: 1579746300522, - bidderCode: 'michao', - bidderRequestId: '15246a574e859f', - bids: [videoBidRequest], + bids: [bannerBidRequest], + auctionId: bannerBidRequest.auctionId, + bidderRequestId: bannerBidRequest.bidderRequestId, }; - const request = buildRequest(videoBidRequest, bidderRequest, 'video'); - const result = interpretResponse(response, request); + const result = spec.buildRequests([bannerBidRequest], bidderRequest); - expect(result).to.be.an('array'); - expect(result[0]).to.have.property('currency', 'USD'); - expect(result[0]).to.have.property('requestId', 'bidId1'); - expect(result[0]).to.have.property('cpm', 0.18); - expect(result[0]).to.have.property('width', 300); - expect(result[0]).to.have.property('height', 250); - expect(result[0]).to.have.property('vastXml', ''); - expect(result[0]).to.have.property('creativeId', 'creativeId'); - expect(result[0]).to.have.property('netRevenue', true); - expect(result[0]).to.have.property('mediaType', 'video'); - expect(result[0]).to.have.property('renderer'); + expect(result[0].data.imp[0].rwdd).to.equal(1); }); - }); - describe('user syncs', () => { - it('Sync Users', () => { - const gdprConsent = { - gdprApplies: false, - consentString: '', + it('sets reward disabled parameter in impression object when reward is not specified', () => { + bannerBidRequest.params = { + site: 456, + placement: '123', + }; + const bidderRequest = { + bids: [bannerBidRequest], + auctionId: bannerBidRequest.auctionId, + bidderRequestId: bannerBidRequest.bidderRequestId, }; - const result = syncUser(gdprConsent); + const result = spec.buildRequests([bannerBidRequest], bidderRequest); - expect(result).to.deep.equal({ - type: 'iframe', - url: 'https://sync.michao-ssp.com/cookie-syncs?gdpr=0&gdpr_consent=', - }); + expect(result[0].data.imp[0].rwdd).to.equal(0); }); - }); - describe('bill a bid', () => { - const triggerPixelSpy = sinon.spy(utils, 'triggerPixel'); - const bid = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '22c4871113f461', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { banner: [[300, 250]] }, - params: { - site: 123, - placement: '456', - }, - burl: 'https://example.com/burl', - }; + it('sets bid floor in impression object when specified', () => { + bannerBidRequest.params = { + site: 456, + placement: '123', + bidFloor: 0.2, + }; + const bidderRequest = { + bids: [bannerBidRequest], + auctionId: bannerBidRequest.auctionId, + bidderRequestId: bannerBidRequest.bidderRequestId, + }; - billBid(bid); + const result = spec.buildRequests([bannerBidRequest], bidderRequest); - expect(triggerPixelSpy.calledWith('https://example.com/burl')).to.true; - triggerPixelSpy.restore(); - }); + expect(result[0].data.imp[0].bidfloor).to.equal(0.2); + }); - describe('renderer', () => { - it('Set outstream renderer', () => { - const bid = { - renderer: [], + it('sets bid floor to 0 in impression object when not specified', () => { + bannerBidRequest.params = { + site: 456, + placement: '123', + }; + const bidderRequest = { + bids: [bannerBidRequest], + auctionId: bannerBidRequest.auctionId, + bidderRequestId: bannerBidRequest.bidderRequestId, }; - addRenderer(bid); + const result = spec.buildRequests([bannerBidRequest], bidderRequest); - expect(bid.renderer[0]).that.is.a('function'); + expect(result[0].data.imp[0].bidfloor).to.equal(0); }); - }); - }); - describe('integration', () => { - describe('`isBidRequestValid`', () => { - it('Happy path', () => { - const validBidRequest = { - params: { - placement: '124', - site: 234, - }, + it('sets block categories in bid request when specified', () => { + bannerBidRequest.params = { + site: 456, + placement: '123', + bcat: ['IAB2'], + }; + const bidderRequest = { + bids: [bannerBidRequest], + auctionId: bannerBidRequest.auctionId, + bidderRequestId: bannerBidRequest.bidderRequestId, }; - const result = spec.isBidRequestValid(validBidRequest); + const result = spec.buildRequests([bannerBidRequest], bidderRequest); - expect(result).to.true; + expect(result[0].data.bcat).to.deep.equal(['IAB2']); }); - it('If the parameter is invalid, it will be logged', () => { - const validationErrorLog = sinon.spy(domainLogger, 'bidRequestValidationError'); - const validBidRequest = { - params: { - placement: '124', - site: '234', - }, + it('sets block advertisers in bid request when specified', () => { + bannerBidRequest.params = { + site: 456, + placement: '123', + badv: ['adomain.com'], + }; + const bidderRequest = { + bids: [bannerBidRequest], + auctionId: bannerBidRequest.auctionId, + bidderRequestId: bannerBidRequest.bidderRequestId, }; - const result = spec.isBidRequestValid(validBidRequest); + const result = spec.buildRequests([bannerBidRequest], bidderRequest); - expect(result).to.false; - expect(validationErrorLog.calledOnce).to.true; - validationErrorLog.restore(); + expect(result[0].data.badv).to.deep.equal(['adomain.com']); }); }); + }); - it('`buildRequests`', () => { - const validBidRequests = [ - { - adUnitCode: 'test-div', - auctionId: 'auction-1', - bidId: 'bid-1', - bidder: 'michao', - bidderRequestId: 'bidder-request-1', - mediaTypes: { - banner: { - sizes: [[300, 250]], - }, - }, - params: { - site: 12, - placement: '12', - }, - }, - { - adUnitCode: 'test-div', - auctionId: 'auction-2', - bidId: 'bid-2', - bidder: 'michao', - bidderRequestId: 'bidder-request-2', - mediaTypes: { - video: { - context: 'outstream', - playerSize: [640, 480], - mimes: ['video/mp4'], - }, - }, - params: { - site: 12, - placement: '12', - }, - }, - { - adUnitCode: 'test-div', - auctionId: 'auction-2', - bidId: 'bid-2', - bidder: 'michao', - bidderRequestId: 'bidder-request-2', - mediaTypes: { - native: { - ortb: { - assets: [ - { - id: 2, - required: 1, - title: { - len: 80 - } - } - ] - } - }, - }, - params: { - site: 12, - placement: '12', - }, - }, - ]; + describe('`interpretResponse`', () => { + it('sets renderer for video bid response when bid request was outstream', () => { + videoBidRequest.mediaTypes.video = { + ...videoBidRequest.mediaTypes.video, + context: 'outstream', + }; const bidderRequest = { - auctionId: 'auction-1', - auctionStart: 1579746300522, + bids: [videoBidRequest], + auctionId: videoBidRequest.auctionId, bidderCode: 'michao', - bidderRequestId: 'bidder-request-1', + bidderRequestId: videoBidRequest.bidderRequestId, }; + const request = spec.buildRequests([videoBidRequest], bidderRequest); - const result = spec.buildRequests(validBidRequests, bidderRequest); + const result = spec.interpretResponse(videoServerResponse, request[0]); - expect(result.length).to.equal(3); + expect(result[0].renderer.url).to.equal( + 'https://cdn.jsdelivr.net/npm/in-renderer-js@latest/dist/in-video-renderer.umd.min.js' + ); }); - it('`interpretResponse`', () => { - const response = { - headers: null, - body: { - id: 'requestId', - seatbid: [ - { - bid: [ - { - id: 'bidId1', - impid: 'bidId1', - price: 0.18, - adm: '
ad
', - adid: '144762342', - adomain: ['https://dummydomain.com'], - iurl: 'iurl', - cid: '109', - crid: 'creativeId', - cat: [], - w: 640, - h: 480, - mtype: 1, - }, - ], - seat: 'seat', - }, - ], - cur: 'USD', - }, - }; - const bannerBidRequest = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: 'bidId1', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { - banner: { - sizes: [[300, 250]] - }, - }, - params: { - site: 123, - placement: '456', - }, + it('does not set renderer for video bid response when bid request was instream', () => { + videoBidRequest.mediaTypes.video = { + ...videoBidRequest.mediaTypes.video, + context: 'instream', }; const bidderRequest = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: 1579746300522, + bids: [videoBidRequest], + auctionId: videoBidRequest.auctionId, bidderCode: 'michao', - bidderRequestId: '15246a574e859f', + bidderRequestId: videoBidRequest.bidderRequestId, + }; + const request = spec.buildRequests([videoBidRequest], bidderRequest); + + const result = spec.interpretResponse(videoServerResponse, request[0]); + + expect(result[0].renderer).to.be.undefined; + }); + + it('does not set renderer for banner bid response', () => { + const bidderRequest = { bids: [bannerBidRequest], + auctionId: bannerBidRequest.auctionId, + bidderCode: 'michao', + bidderRequestId: bannerBidRequest.bidderRequestId, + }; + const request = spec.buildRequests([bannerBidRequest], bidderRequest); + + const result = spec.interpretResponse(bannerServerResponse, request[0]); + + expect(result[0].renderer).to.be.undefined; + }); + }); + + describe('`getUserSyncs`', () => { + it('performs iframe user sync when iframe is enabled', () => { + const syncOptions = { + iframeEnabled: true, + }; + + const result = spec.getUserSyncs(syncOptions, {}, {}, {}); + + expect(result[0].url).to.equal( + 'https://sync.michao-ssp.com/cookie-syncs?' + ); + expect(result[0].type).to.equal('iframe'); + }); + + it('does not perform iframe user sync when iframe is disabled', () => { + const syncOptions = { + iframeEnabled: false, }; - const request = buildRequest(bannerBidRequest, bidderRequest, 'banner'); - - const result = interpretResponse(response, request); - - expect(result).to.be.an('array'); - expect(result[0]).to.have.property('currency', 'USD'); - expect(result[0]).to.have.property('requestId', 'bidId1'); - expect(result[0]).to.have.property('cpm', 0.18); - expect(result[0]).to.have.property('width', 640); - expect(result[0]).to.have.property('height', 480); - expect(result[0]).to.have.property('ad', '
ad
'); - expect(result[0]).to.have.property('creativeId', 'creativeId'); - expect(result[0]).to.have.property('netRevenue', true); + + const result = spec.getUserSyncs(syncOptions, {}, {}, {}); + + expect(result.length).to.equal(0); }); - it('`getUserSyncs`', () => { + it('sets GDPR parameters in user sync URL when GDPR applies', () => { const syncOptions = { iframeEnabled: true, }; const gdprConsent = { gdprApplies: true, - consentString: - 'CQIhBPbQIhBPbEkAAAENCZCAAAAAAAAAAAAAAAAAAAAA.II7Nd_X__bX9n-_7_6ft0eY1f9_r37uQzDhfNs-8F3L_W_LwX32E7NF36tq4KmR4ku1bBIQNtHMnUDUmxaolVrzHsak2cpyNKJ_JkknsZe2dYGF9Pn9lD-YKZ7_5_9_f52T_9_9_-39z3_9f___dv_-__-vjf_599n_v9fV_78_Kf9______-____________8A', + consentString: 'BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA', + }; + + const result = spec.getUserSyncs(syncOptions, {}, gdprConsent, {}); + + expect(result[0].url).to.equal( + 'https://sync.michao-ssp.com/cookie-syncs?gdpr=1&gdpr_consent=BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA' + ); + expect(result[0].type).to.equal('iframe'); + }); + + it('does not set GDPR parameters in user sync URL when GDPR does not apply', () => { + const syncOptions = { + iframeEnabled: true, }; + const gdrpConsent = { + gdrpApplies: false, + }; + + const result = spec.getUserSyncs(syncOptions, {}, gdrpConsent, {}); + + expect(result[0].url).to.equal( + 'https://sync.michao-ssp.com/cookie-syncs?' + ); + expect(result[0].type).to.equal('iframe'); + }); + }); - const result = spec.getUserSyncs(syncOptions, {}, gdprConsent); + describe('`onBidBillable`', () => { + it('does not generate billing when billing URL is not included in bid', () => { + const bid = {}; - expect(result).to.deep.equal([ - { - type: 'iframe', - url: 'https://sync.michao-ssp.com/cookie-syncs?gdpr=1&gdpr_consent=CQIhBPbQIhBPbEkAAAENCZCAAAAAAAAAAAAAAAAAAAAA.II7Nd_X__bX9n-_7_6ft0eY1f9_r37uQzDhfNs-8F3L_W_LwX32E7NF36tq4KmR4ku1bBIQNtHMnUDUmxaolVrzHsak2cpyNKJ_JkknsZe2dYGF9Pn9lD-YKZ7_5_9_f52T_9_9_-39z3_9f___dv_-__-vjf_599n_v9fV_78_Kf9______-____________8A', - }, - ]); + spec.onBidBillable(bid); + + expect(triggerPixelSpy.calledOnce).to.be.false; }); - it('`onBidBillable`', () => { - const triggerPixelSpy = sinon.spy(utils, 'triggerPixel'); + it('generates billing when billing URL is a string', () => { const bid = { - adUnitCode: 'test-div', - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '22c4871113f461', - bidder: 'michao', - bidderRequestId: '15246a574e859f', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0, - mediaTypes: { banner: [[300, 250]] }, - params: { - site: 123, - placement: '456', - }, burl: 'https://example.com/burl', + cpm: 1, + }; + + spec.onBidBillable(bid); + + expect(triggerPixelSpy.calledOnce).to.be.true; + }); + + it('does not generate billing when billing URL is not a string', () => { + const bid = { + burl: 123, }; spec.onBidBillable(bid); - expect(triggerPixelSpy.calledWith('https://example.com/burl')).to.true; - triggerPixelSpy.restore(); + expect(triggerPixelSpy.calledOnce).to.be.false; }); }); }); + +const _bannerBidRequest = { + adUnitCode: 'test-div', + auctionId: 'banner-auction-id', + bidId: 'banner-bid-id', + bidder: 'michao', + bidderRequestId: 'banner-bidder-request-id', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { banner: [[300, 250]] }, + params: { + site: 123, + placement: '456', + }, +}; + +const _videoBidRequest = { + adUnitCode: 'test-div', + auctionId: 'video-auction-request-id', + bidId: 'video-bid-id', + bidder: 'michao', + bidderRequestId: 'video-bidder-request-id', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480], + mimes: ['video/mp4'], + minduration: 0, + maxduration: 120, + protocols: [2] + }, + }, + params: { + site: 123, + placement: '456', + }, +}; + +const _nativeBidRequest = { + adUnitCode: 'test-div', + auctionId: 'native-auction-id', + bidId: 'native-bid-id', + bidder: 'michao', + bidderRequestId: 'native-bidder-request-id', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { + native: { + ortb: { + assets: [ + { + id: 1, + title: { + len: 30, + }, + }, + ], + }, + }, + }, + params: { + site: 123, + placement: '456', + }, +}; + +const _videoServerResponse = { + headers: null, + body: { + id: 'video-server-response-id', + seatbid: [ + { + bid: [ + { + id: 'video-bid-id', + impid: 'video-bid-id', + price: 0.18, + adm: '', + adid: '144762342', + adomain: ['https://dummydomain.com'], + iurl: 'iurl', + cid: '109', + crid: 'creativeId', + cat: [], + w: 300, + h: 250, + mtype: 2, + }, + ], + seat: 'seat', + }, + ], + cur: 'USD', + }, +}; + +const _bannerServerResponse = { + headers: null, + body: { + id: 'banner-server-response-id', + seatbid: [ + { + bid: [ + { + id: 'banner-bid-id', + impid: 'banner-bid-id', + price: 0.18, + adm: '
ad
', + adid: '144762342', + adomain: ['https://dummydomain.com'], + iurl: 'iurl', + cid: '109', + crid: 'creativeId', + cat: [], + w: 300, + h: 250, + mtype: 1, + }, + ], + seat: 'seat', + }, + ], + cur: 'USD', + }, +}; From a35a9a6035475bdcfdf235101e216b1003baff81 Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Fri, 13 Dec 2024 11:23:03 +0900 Subject: [PATCH 14/21] Michao Bid Adapter: Change the method used by the property validation system --- test/spec/modules/michaoBidAdapter_spec.js | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js index 891c14fba49..845da714dcb 100644 --- a/test/spec/modules/michaoBidAdapter_spec.js +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -372,7 +372,7 @@ describe('Michao Bid Adapter', () => { expect(result.length).to.equal(1); expect(result[0].data.imp.length).to.equal(1); - expect(result[0].data.imp[0]).to.have.haveOwnPropertyDescriptor( + expect(result[0].data.imp[0]).to.have.property( 'banner' ); }); @@ -388,9 +388,7 @@ describe('Michao Bid Adapter', () => { expect(result.length).to.equal(1); expect(result[0].data.imp.length).to.equal(1); - expect(result[0].data.imp[0]).to.have.haveOwnPropertyDescriptor( - 'video' - ); + expect(result[0].data.imp[0]).to.have.property('video'); }); it('creates native-specific bid request from bid request containing one native format', () => { @@ -427,10 +425,10 @@ describe('Michao Bid Adapter', () => { expect(result.length).to.equal(1); expect(result[0].data.imp.length).to.equal(2); - expect(result[0].data.imp[0]).to.have.haveOwnPropertyDescriptor( + expect(result[0].data.imp[0]).to.have.property( 'banner' ); - expect(result[0].data.imp[1]).to.have.haveOwnPropertyDescriptor( + expect(result[0].data.imp[1]).to.have.property( 'video' ); }); @@ -454,7 +452,7 @@ describe('Michao Bid Adapter', () => { expect(result.length).to.equal(1); expect(result[0].data.imp.length).to.equal(2); - expect(result[0].data.imp[0]).to.have.haveOwnPropertyDescriptor( + expect(result[0].data.imp[0]).to.have.property( 'banner' ); }); @@ -478,9 +476,7 @@ describe('Michao Bid Adapter', () => { expect(result.length).to.equal(1); expect(result[0].data.imp.length).to.equal(2); - expect(result[0].data.imp[0]).to.have.haveOwnPropertyDescriptor( - 'video' - ); + expect(result[0].data.imp[0]).to.have.property('video'); }); it('creates banner, video and native bid request with three impressions from bid request containing all three formats', () => { @@ -503,10 +499,10 @@ describe('Michao Bid Adapter', () => { expect(result.length).to.equal(1); expect(result[0].data.imp.length).to.equal(3); - expect(result[0].data.imp[0]).to.have.haveOwnPropertyDescriptor( + expect(result[0].data.imp[0]).to.have.property( 'banner' ); - expect(result[0].data.imp[1]).to.have.haveOwnPropertyDescriptor( + expect(result[0].data.imp[1]).to.have.property( 'video' ); }); From 7457a83333280dc78f8b602c2c15bb87a67a81cd Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Fri, 13 Dec 2024 12:00:36 +0900 Subject: [PATCH 15/21] Michao Bid Adapter: Remove video property assertion --- test/spec/modules/michaoBidAdapter_spec.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js index 845da714dcb..d2d74213216 100644 --- a/test/spec/modules/michaoBidAdapter_spec.js +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -388,7 +388,6 @@ describe('Michao Bid Adapter', () => { expect(result.length).to.equal(1); expect(result[0].data.imp.length).to.equal(1); - expect(result[0].data.imp[0]).to.have.property('video'); }); it('creates native-specific bid request from bid request containing one native format', () => { @@ -428,9 +427,6 @@ describe('Michao Bid Adapter', () => { expect(result[0].data.imp[0]).to.have.property( 'banner' ); - expect(result[0].data.imp[1]).to.have.property( - 'video' - ); }); it('creates banner and native bid request with two impressions from bid request containing both banner and native formats', () => { @@ -476,7 +472,6 @@ describe('Michao Bid Adapter', () => { expect(result.length).to.equal(1); expect(result[0].data.imp.length).to.equal(2); - expect(result[0].data.imp[0]).to.have.property('video'); }); it('creates banner, video and native bid request with three impressions from bid request containing all three formats', () => { From 71b0f01d39c3453ab7331637afb5244ae8aad13d Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Fri, 13 Dec 2024 12:09:21 +0900 Subject: [PATCH 16/21] Michao Bid Adapter: Remove assertions on video properties that you forgot to erase. --- test/spec/modules/michaoBidAdapter_spec.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js index d2d74213216..1934d618f57 100644 --- a/test/spec/modules/michaoBidAdapter_spec.js +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -497,9 +497,6 @@ describe('Michao Bid Adapter', () => { expect(result[0].data.imp[0]).to.have.property( 'banner' ); - expect(result[0].data.imp[1]).to.have.property( - 'video' - ); }); }); From 2049dd87643355a9fab4b73b152fa107958b8956 Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Fri, 13 Dec 2024 17:22:01 +0900 Subject: [PATCH 17/21] Michao Bid Adapter: Explicitly delete native objects --- modules/michaoBidAdapter.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js index 9afc57bb63e..6ff8ab763a4 100644 --- a/modules/michaoBidAdapter.js +++ b/modules/michaoBidAdapter.js @@ -310,6 +310,10 @@ const converter = ortbConverter({ isNumber(bidRequest.params?.bidFloor) ? bidRequest.params?.bidFloor : 0 ); + if (!bidRequest.mediaTypes?.native) { + delete imp.native; + } + return imp; }, From 3358914328357c7f00420382f31ade3e3b74fecb Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Fri, 13 Dec 2024 17:37:35 +0900 Subject: [PATCH 18/21] Michao Bid Adapter: Rename Renderer URL to outstream renderer URL --- modules/michaoBidAdapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js index 6ff8ab763a4..3666ce192b4 100644 --- a/modules/michaoBidAdapter.js +++ b/modules/michaoBidAdapter.js @@ -20,7 +20,7 @@ const ENV = { ENDPOINT: 'https://rtb.michao-ssp.com/openrtb/prebid', NET_REVENUE: true, DEFAULT_CURRENCY: 'USD', - RENDERER_URL: + OUTSTREAM_RENDERER_URL: 'https://cdn.jsdelivr.net/npm/in-renderer-js@latest/dist/in-video-renderer.umd.min.js', }; @@ -326,7 +326,7 @@ const converter = ortbConverter({ ) { bidResponse.vastXml = bid.adm; const renderer = Renderer.install({ - url: ENV.RENDERER_URL, + url: ENV.OUTSTREAM_RENDERER_URL, id: bidRequest.bidId, adUnitCode: bidRequest.adUnitCode, }); From f8ee3aa9645eed6dc18405d79e320e27e2f5ba74 Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Mon, 23 Dec 2024 12:28:02 +0900 Subject: [PATCH 19/21] Michao Bid Adapter: Swap the order in which bid requests are pushed --- modules/michaoBidAdapter.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js index 3666ce192b4..1c0637f7184 100644 --- a/modules/michaoBidAdapter.js +++ b/modules/michaoBidAdapter.js @@ -120,20 +120,20 @@ export const spec = { }); } - if (validBidRequest.mediaTypes?.video) { + if (validBidRequest.mediaTypes?.native) { bidRequestEachFormat.push({ ...validBidRequest, mediaTypes: { - video: validBidRequest.mediaTypes.video, + native: validBidRequest.mediaTypes.native, }, }); } - if (validBidRequest.mediaTypes?.native) { + if (validBidRequest.mediaTypes?.video) { bidRequestEachFormat.push({ ...validBidRequest, mediaTypes: { - native: validBidRequest.mediaTypes.native, + video: validBidRequest.mediaTypes.video, }, }); } From ac0729735cfbaab66fc010528b568b70145874c0 Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Sun, 29 Dec 2024 02:37:33 +0900 Subject: [PATCH 20/21] Michao Bid Adapter: Explicitly specify version of outstream renderer URL --- modules/michaoBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js index 1c0637f7184..1fcfe32b4c9 100644 --- a/modules/michaoBidAdapter.js +++ b/modules/michaoBidAdapter.js @@ -21,7 +21,7 @@ const ENV = { NET_REVENUE: true, DEFAULT_CURRENCY: 'USD', OUTSTREAM_RENDERER_URL: - 'https://cdn.jsdelivr.net/npm/in-renderer-js@latest/dist/in-video-renderer.umd.min.js', + 'https://cdn.jsdelivr.net/npm/in-renderer-js@1.0.6/dist/in-video-renderer.umd.min.js', }; export const spec = { From 2d6f8b5647c0709e686773d4875cfd3de5dced7e Mon Sep 17 00:00:00 2001 From: Kai Miyamoto Date: Sun, 29 Dec 2024 18:28:30 +0900 Subject: [PATCH 21/21] Michao Bid Adapter: Tests are supported for out-stream renderer URL version specification --- test/spec/modules/michaoBidAdapter_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/spec/modules/michaoBidAdapter_spec.js b/test/spec/modules/michaoBidAdapter_spec.js index 1934d618f57..514899e639e 100644 --- a/test/spec/modules/michaoBidAdapter_spec.js +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -687,7 +687,7 @@ describe('Michao Bid Adapter', () => { const result = spec.interpretResponse(videoServerResponse, request[0]); expect(result[0].renderer.url).to.equal( - 'https://cdn.jsdelivr.net/npm/in-renderer-js@latest/dist/in-video-renderer.umd.min.js' + 'https://cdn.jsdelivr.net/npm/in-renderer-js@1.0.6/dist/in-video-renderer.umd.min.js' ); });