UNPKG

mk9-prebid

Version:

Header Bidding Management Library

539 lines (479 loc) 19.2 kB
import { expect } from 'chai'; import { spec } from 'modules/mediakeysBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; import * as utils from 'src/utils.js'; import { config } from 'src/config.js'; import { BANNER, NATIVE, VIDEO } from '../../../src/mediaTypes.js'; describe('mediakeysBidAdapter', function () { const adapter = newBidder(spec); let utilsMock; let sandbox; const bid = { bidder: 'mediakeys', params: {}, mediaTypes: { banner: { sizes: [ [300, 250], [300, 600], ], }, }, adUnitCode: 'div-gpt-ad-1460505748561-0', transactionId: '47789656-9e5c-4250-b7e0-2ce4cbe71a55', sizes: [ [300, 250], [300, 600], ], bidId: '299320f4de980d', bidderRequestId: '1c1b642f803242', auctionId: '84212956-c377-40e8-b000-9885a06dc692', src: 'client', bidRequestsCount: 1, bidderRequestsCount: 1, bidderWinsCount: 0, ortb2Imp: { ext: { data: { something: 'test' } } } }; const bidderRequest = { bidderCode: 'mediakeys', auctionId: '84212956-c377-40e8-b000-9885a06dc692', bidderRequestId: '1c1b642f803242', bids: [ { bidder: 'mediakeys', params: {}, mediaTypes: { banner: { sizes: [ [300, 250], [300, 600], ], }, }, adUnitCode: 'div-gpt-ad-1460505748561-0', transactionId: '47789656-9e5c-4250-b7e0-2ce4cbe71a55', sizes: [ [300, 250], [300, 600], ], bidId: '299320f4de980d', bidderRequestId: '1c1b642f803242', auctionId: '84212956-c377-40e8-b000-9885a06dc692', src: 'client', bidRequestsCount: 1, bidderRequestsCount: 1, bidderWinsCount: 0, ortb2Imp: { ext: { data: { something: 'test' } } } }, ], auctionStart: 1620973766319, timeout: 1000, refererInfo: { referer: 'https://local.url/integrationExamples/gpt/hello_world.html?pbjs_debug=true', reachedTop: true, isAmp: false, numIframes: 0, stack: [ 'https://local.url/integrationExamples/gpt/hello_world.html?pbjs_debug=true', ], canonicalUrl: null, }, start: 1620973766325, }; beforeEach(function () { utilsMock = sinon.mock(utils); sandbox = sinon.createSandbox(); }); afterEach(function () { utilsMock.restore(); sandbox.restore(); }); describe('isBidRequestValid', function () { it('should returns true when bid is provided even with empty params', function () { expect(spec.isBidRequestValid(bid)).to.equal(true); }); it('should returns false when bid is falsy or empty', function () { const emptyBid = {}; expect(spec.isBidRequestValid()).to.equal(false); expect(spec.isBidRequestValid(false)).to.equal(false); expect(spec.isBidRequestValid(emptyBid)).to.equal(false); }); }); describe('buildRequests', function () { it('should create imp for supported mediaType only', function() { const bidRequests = [utils.deepClone(bid)]; const bidderRequestCopy = utils.deepClone(bidderRequest); bidRequests[0].mediaTypes.video = { playerSize: [300, 250], context: 'outstream' } bidRequests[0].mediaTypes.native = { type: 'image' } const request = spec.buildRequests(bidRequests, bidderRequestCopy); const data = request.data; expect(data.imp.length).to.equal(1); expect(data.imp[0].banner).to.exist; expect(data.imp[0].video).to.not.exist; expect(data.imp[0].native).to.not.exist; }); it('should get expected properties with default values (no params set)', function () { const bidRequests = [utils.deepClone(bid)]; const request = spec.buildRequests(bidRequests, bidderRequest); const data = request.data; // openRTB 2.5 expect(data.at).to.equal(1); expect(data.cur[0]).to.equal('USD'); // default currency expect(data.source.tid).to.equal(bidderRequest.auctionId); expect(data.imp.length).to.equal(1); expect(data.imp[0].id).to.equal(bidRequests[0].bidId); expect(data.imp[0].banner.w).to.equal(300); expect(data.imp[0].banner.h).to.equal(250); expect(data.imp[0].banner.format[0].w).to.equal(300); expect(data.imp[0].banner.format[0].h).to.equal(250); expect(data.imp[0].banner.format[1].w).to.equal(300); expect(data.imp[0].banner.format[1].h).to.equal(600); expect(data.imp[0].banner.topframe).to.equal(0); expect(data.imp[0].banner.pos).to.equal(0); // Ortb2Imp ext expect(data.imp[0].ext).to.exist; expect(data.imp[0].ext.data.something).to.equal('test'); }); it('should get expected properties with values from params', function () { const bidRequests = [utils.deepClone(bid)]; bidRequests[0].params = { pos: 2, }; const request = spec.buildRequests(bidRequests, bidderRequest); const data = request.data; expect(data.imp[0].banner.pos).to.equal(2); }); it('should get expected properties with schain', function () { const schain = { ver: '1.0', complete: 1, nodes: [ { asi: 'ssp.test', sid: '00001', hp: 1, }, ], }; const bidRequests = [utils.deepClone(bid)]; bidRequests[0].schain = schain; const request = spec.buildRequests(bidRequests, bidderRequest); const data = request.data; expect(data.source.ext.schain).to.equal(schain); }); it('should get expected properties with coppa', function () { sinon.stub(config, 'getConfig').withArgs('coppa').returns(true); const bidRequests = [utils.deepClone(bid)]; const request = spec.buildRequests(bidRequests, bidderRequest); const data = request.data; expect(data.regs.coppa).to.equal(1); config.getConfig.restore(); }); it('should get expected properties with US privacy', function () { const consent = 'Y11N'; const bidRequests = [utils.deepClone(bid)]; const bidderRequestWithUsPrivcay = utils.deepClone(bidderRequest); bidderRequestWithUsPrivcay.uspConsent = consent; const request = spec.buildRequests( bidRequests, bidderRequestWithUsPrivcay ); const data = request.data; expect(data.regs.ext.us_privacy).to.equal(consent); }); it('should get expected properties with GDPR', function () { const consent = { consentString: 'kjfdniwjnifwenrif3', gdprApplies: true, }; const bidRequests = [utils.deepClone(bid)]; const bidderRequestWithGDPR = utils.deepClone(bidderRequest); bidderRequestWithGDPR.gdprConsent = consent; const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR); const data = request.data; expect(data.regs.ext.gdpr).to.equal(1); expect(data.user.ext.consent).to.equal(consent.consentString); }); describe('PriceFloors module support', function() { const getFloorTest = (options) => { switch (options.mediaType) { case BANNER: return { floor: 1, currency: 'USD' } case VIDEO: return { floor: 5, currency: 'USD' } case NATIVE: return { floor: 3, currency: 'USD' } default: return false } }; it('should not set `imp[]bidfloor` property when priceFloors module is not available', function () { const bidRequests = [bid]; const request = spec.buildRequests(bidRequests, bidderRequest); const data = request.data; expect(data.imp[0].banner).to.exist; expect(data.imp[0].bidfloor).to.not.exist }); it('should not set `imp[]bidfloor` property when priceFloors module returns false', function () { const bidWithPriceFloors = utils.deepClone(bid); bidWithPriceFloors.getFloor = () => { return false; }; const bidRequests = [bidWithPriceFloors]; const request = spec.buildRequests(bidRequests, bidderRequest); const data = request.data; expect(data.imp[0].banner).to.exist; expect(data.imp[0].bidfloor).to.not.exist; }); it('should get and set floor by mediatype', function() { const bidWithPriceFloors = utils.deepClone(bid); bidWithPriceFloors.mediaTypes.video = { playerSize: [600, 480] }; bidWithPriceFloors.getFloor = getFloorTest; const bidRequests = [bidWithPriceFloors]; const request = spec.buildRequests(bidRequests, bidderRequest); const data = request.data; expect(data.imp[0].banner).to.exist; expect(data.imp[0].bidfloor).to.equal(1); // expect(data.imp[1].video).to.exist; // expect(data.imp[1].bidfloor).to.equal(5); }); it('should set properties at payload level from FPD', function() { sandbox.stub(config, 'getConfig').callsFake(key => { const config = { ortb2: { site: { domain: 'domain.example', cat: ['IAB12'], ext: { data: { category: 'sport', } } }, user: { yob: 1985, gender: 'm' }, device: { geo: { country: 'FR', city: 'Marseille' } } } }; return utils.deepAccess(config, key); }); const bidRequests = [utils.deepClone(bid)]; const request = spec.buildRequests(bidRequests, bidderRequest); const data = request.data; expect(data.site.domain).to.equal('domain.example'); expect(data.site.cat[0]).to.equal('IAB12'); expect(data.site.ext.data.category).to.equal('sport'); expect(data.user.yob).to.equal(1985); expect(data.user.gender).to.equal('m'); expect(data.device.geo.country).to.equal('FR'); expect(data.device.geo.city).to.equal('Marseille'); }); }); describe('should support userId modules', function() { const userId = { pubcid: '01EAJWWNEPN3CYMM5N8M5VXY22', unsuported: '666' }; it('should send "user.eids" in the request for Prebid.js supported modules only', function() { const bidCopy = utils.deepClone(bid); bidCopy.userId = userId; const bidderRequestCopy = utils.deepClone(bidderRequest); bidderRequestCopy.bids[0].userId = userId; const bidRequests = [utils.deepClone(bidCopy)]; const request = spec.buildRequests(bidRequests, bidderRequestCopy); const data = request.data; const expected = [{ source: 'pubcid.org', uids: [ { atype: 1, id: '01EAJWWNEPN3CYMM5N8M5VXY22' } ] }]; expect(data.user.ext).to.exist; expect(data.user.ext.eids).to.have.lengthOf(1); expect(data.user.ext.eids).to.deep.equal(expected); }); }); }); describe('intrepretResponse', function () { const rawServerResponse = { body: { id: '60839f99-d5f2-3ab3-b6ac-736b4fe9d0ae', seatbid: [ { bid: [ { id: '60839f99-d5f2-3ab3-b6ac-736b4fe9d0ae_0_0', impid: '1', price: 0.4319, nurl: 'https://local.url/notif?index=ab-cd-ef&price=${AUCTION_PRICE}', burl: 'https://local.url/notif?index=ab-cd-ef&price=${AUCTION_PRICE}', adm: '<iframe src="https://local.url"></iframe>', adomain: ['domain.io'], iurl: 'https://local.url', cid: 'string-id', crid: 'string-id', cat: ['IAB2'], attr: [], w: 300, h: 250, ext: { advertiser_name: 'Advertiser', agency_name: 'mediakeys', prebid: { type: 'B' } }, }, ], seat: '337', }, ], cur: 'USD', ext: { protocol: '5.3' }, } } it('Returns empty array if no bid', function () { const bidRequests = [utils.deepClone(bid)]; const request = spec.buildRequests(bidRequests, bidderRequest); const response01 = spec.interpretResponse({ body: { seatbid: [{ bid: [] }] } }, request); const response02 = spec.interpretResponse({ body: { seatbid: [] } }, request); const response03 = spec.interpretResponse({ body: { seatbid: null } }, request); const response04 = spec.interpretResponse({ body: { seatbid: null } }, request); const response05 = spec.interpretResponse({ body: {} }, request); const response06 = spec.interpretResponse({}, request); expect(response01.length).to.equal(0); expect(response02.length).to.equal(0); expect(response03.length).to.equal(0); expect(response04.length).to.equal(0); expect(response05.length).to.equal(0); expect(response06.length).to.equal(0); }); it('Log an error', function () { const bidRequests = [utils.deepClone(bid)]; const request = spec.buildRequests(bidRequests, bidderRequest); sinon.stub(utils, 'isArray').throws(); spec.interpretResponse(rawServerResponse, request); utilsMock.expects('logError').once(); utils.isArray.restore(); }); it('Meta Primary category handling', function() { const rawServerResponseCopy = utils.deepClone(rawServerResponse); const rawServerResponseCopy2 = utils.deepClone(rawServerResponse); const rawServerResponseCopy3 = utils.deepClone(rawServerResponse); const rawServerResponseCopy4 = utils.deepClone(rawServerResponse); const rawServerResponseCopy5 = utils.deepClone(rawServerResponse); const rawServerResponseCopy6 = utils.deepClone(rawServerResponse); rawServerResponseCopy.body.seatbid[0].bid[0].cat = 'IAB12-1'; rawServerResponseCopy2.body.seatbid[0].bid[0].cat = ['IAB12', 'IAB12-1']; rawServerResponseCopy3.body.seatbid[0].bid[0].cat = ''; rawServerResponseCopy4.body.seatbid[0].bid[0].cat = []; rawServerResponseCopy5.body.seatbid[0].bid[0].cat = 123; delete rawServerResponseCopy6.body.seatbid[0].bid[0].cat; const bidRequests = [utils.deepClone(bid)]; const request = spec.buildRequests(bidRequests, bidderRequest); const response = spec.interpretResponse(rawServerResponseCopy, request); const response2 = spec.interpretResponse(rawServerResponseCopy2, request); const response3 = spec.interpretResponse(rawServerResponseCopy3, request); const response4 = spec.interpretResponse(rawServerResponseCopy4, request); const response5 = spec.interpretResponse(rawServerResponseCopy5, request); const response6 = spec.interpretResponse(rawServerResponseCopy6, request); expect(response[0].meta.primaryCatId).to.equal('IAB12-1'); expect(response2[0].meta.primaryCatId).to.equal('IAB12'); expect(response3[0].meta.primaryCatId).to.not.exist; expect(response4[0].meta.primaryCatId).to.not.exist; expect(response5[0].meta.primaryCatId).to.not.exist; expect(response6[0].meta.primaryCatId).to.not.exist; }); it('Build banner response', function () { const bidRequests = [utils.deepClone(bid)]; const request = spec.buildRequests(bidRequests, bidderRequest); const response = spec.interpretResponse(rawServerResponse, request); expect(response.length).to.equal(1); expect(response[0].requestId).to.equal(rawServerResponse.body.seatbid[0].bid[0].impid); expect(response[0].cpm).to.equal(rawServerResponse.body.seatbid[0].bid[0].price); expect(response[0].width).to.equal(rawServerResponse.body.seatbid[0].bid[0].w); expect(response[0].height).to.equal(rawServerResponse.body.seatbid[0].bid[0].h); expect(response[0].creativeId).to.equal(rawServerResponse.body.seatbid[0].bid[0].crid); expect(response[0].dealId).to.equal(null); expect(response[0].currency).to.equal(rawServerResponse.body.cur); expect(response[0].netRevenue).to.equal(true); expect(response[0].ttl).to.equal(360); expect(response[0].referrer).to.equal(''); expect(response[0].ad).to.equal(rawServerResponse.body.seatbid[0].bid[0].adm); expect(response[0].mediaType).to.equal('banner'); expect(response[0].burl).to.equal(rawServerResponse.body.seatbid[0].bid[0].burl); expect(response[0].meta).to.deep.equal({ advertiserDomains: rawServerResponse.body.seatbid[0].bid[0].adomain, advertiserName: 'Advertiser', agencyName: 'mediakeys', primaryCatId: 'IAB2', mediaType: 'banner' }); }); it('Build video response', function () { const bidRequests = [utils.deepClone(bid)]; const request = spec.buildRequests(bidRequests, bidderRequest); const rawServerResponseVideo = utils.deepClone(rawServerResponse); rawServerResponseVideo.body.seatbid[0].bid[0].ext.prebid.type = 'V'; const response = spec.interpretResponse(rawServerResponseVideo, request); expect(response.length).to.equal(1); expect(response[0].mediaType).to.equal('video'); expect(response[0].meta.mediaType).to.equal('video'); }); it('Build native response', function () { const bidRequests = [utils.deepClone(bid)]; const request = spec.buildRequests(bidRequests, bidderRequest); const rawServerResponseVideo = utils.deepClone(rawServerResponse); rawServerResponseVideo.body.seatbid[0].bid[0].ext.prebid.type = 'N'; const response = spec.interpretResponse(rawServerResponseVideo, request); expect(response.length).to.equal(1); expect(response[0].mediaType).to.equal('native'); expect(response[0].meta.mediaType).to.equal('native'); }); }); describe('onBidWon', function() { beforeEach(function() { sinon.stub(utils, 'triggerPixel'); }); afterEach(function() { utils.triggerPixel.restore(); }); it('Should not trigger pixel if bid does not contain burl', function() { const result = spec.onBidWon({}); expect(result).to.be.undefined; expect(utils.triggerPixel.callCount).to.equal(0); }) it('Should trigger pixel if bid.burl exists', function() { const result = spec.onBidWon({ cpm: 4.2, burl: 'https://example.com/p=${AUCTION_PRICE}&foo=bar' }); expect(utils.triggerPixel.callCount).to.equal(1) expect(utils.triggerPixel.firstCall.args[0]).to.be.equal( 'https://example.com/p=4.2&foo=bar' ); }) }) });