diff --git a/modules/michaoBidAdapter.js b/modules/michaoBidAdapter.js new file mode 100644 index 00000000000..953f0e05268 --- /dev/null +++ b/modules/michaoBidAdapter.js @@ -0,0 +1,240 @@ +import { ortbConverter } from '../libraries/ortbConverter/converter.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import { Renderer } from '../src/Renderer.js'; +import { + deepSetValue, + isNumber, + isStr, + logError, + replaceAuctionPrice, + triggerPixel, +} from '../src/utils.js'; + +const ENV = { + BIDDER_CODE: 'michao', + SUPPORTED_MEDIA_TYPES: [BANNER, VIDEO, NATIVE], + 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-video-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)) { + bidRequests.push(buildRequest(validBidRequest, bidderRequest, 'video')); + } + + if (hasBannerMediaType(validBidRequest)) { + bidRequests.push( + buildRequest(validBidRequest, bidderRequest, 'banner') + ); + } + + if (hasNativeMediaType(validBidRequest)) { + bidRequests.push( + buildRequest(validBidRequest, bidderRequest, 'native') + ); + } + }); + + 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 Bid Adapter: 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.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); +} + +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; + openRTBBidRequest.bcat = bidRequest.params?.bcat || []; + openRTBBidRequest.badv = bidRequest.params?.badv || []; + 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); + 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; + }, + + bidResponse(buildBidResponse, bid, context) { + const { bidRequest } = context; + let bidResponse = buildBidResponse(bid, context); + 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; + }, + + 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 hasNativeMediaType(bid) { + return hasMediaType(bid, 'native'); +} + +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..b45e8e2b5bd --- /dev/null +++ b/modules/michaoBidAdapter.md @@ -0,0 +1,87 @@ +# 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) +* Native + +# 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', + } + }] + }, + // 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 new file mode 100644 index 00000000000..47dea68b538 --- /dev/null +++ b/test/spec/modules/michaoBidAdapter_spec.js @@ -0,0 +1,812 @@ +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', () => { + 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: 'placement' + }; + + 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('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', + 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, + }); + }); + + 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, + }); + }); + + 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', + }); + }); + + 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', () => { + 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], + minduration: 0, + maxduration: 30, + protocols: [7] + }, + }, + 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', () => { + describe('`isBidRequestValid`', () => { + it('Happy path', () => { + const validBidRequest = { + params: { + placement: '124', + site: 234, + }, + }; + + const result = spec.isBidRequestValid(validBidRequest); + + 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`', () => { + 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', + }, + }, + ]; + const bidderRequest = { + auctionId: 'auction-1', + auctionStart: 1579746300522, + bidderCode: 'michao', + bidderRequestId: 'bidder-request-1', + }; + + const result = spec.buildRequests(validBidRequests, bidderRequest); + + expect(result.length).to.equal(3); + }); + + 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', + }, + }; + 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', '
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(); + }); + }); +});