UNPKG

mk9-prebid

Version:

Header Bidding Management Library

687 lines (636 loc) 23.4 kB
import {expect} from 'chai'; import {spec} from 'modules/sovrnBidAdapter.js'; import {config} from 'src/config.js'; import * as utils from 'src/utils.js' const ENDPOINT = `https://ap.lijit.com/rtb/bid?src=$$REPO_AND_VERSION$$`; const adUnitBidRequest = { 'bidder': 'sovrn', 'params': { 'tagid': 403370 }, 'adUnitCode': 'adunit-code', 'sizes': [ [300, 250], [300, 600] ], 'bidId': '30b31c1838de1e', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', } const bidderRequest = { refererInfo: { referer: 'http://example.com/page.html', } }; describe('sovrnBidAdapter', function() { describe('isBidRequestValid', function () { it('should return true when required params found', function () { expect(spec.isBidRequestValid(adUnitBidRequest)).to.equal(true); }); it('should return false when tagid not passed correctly', function () { const bid = {...adUnitBidRequest} const params = adUnitBidRequest.params bid.params = {...params} bid.params.tagid = 'ABCD' expect(spec.isBidRequestValid(bid)).to.equal(false) }); it('should return false when require params are not passed', function () { const bid = {...adUnitBidRequest} bid.params = {}; expect(spec.isBidRequestValid(bid)).to.equal(false); }); }); describe('buildRequests', function () { describe('basic bid parameters', function() { const bidRequests = [adUnitBidRequest]; const request = spec.buildRequests(bidRequests, bidderRequest); it('sends bid request to our endpoint via POST', function () { expect(request.method).to.equal('POST'); }); it('attaches source and version to endpoint URL as query params', function () { expect(request.url).to.equal(ENDPOINT) }); it('sets the proper banner object', function() { const payload = JSON.parse(request.data) expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}, {w: 300, h: 600}]) expect(payload.imp[0].banner.w).to.equal(1) expect(payload.imp[0].banner.h).to.equal(1) }) it('includes the ad unit code int the request', function() { const payload = JSON.parse(request.data); expect(payload.imp[0].adunitcode).to.equal('adunit-code') }) it('converts tagid to string', function () { expect(request.data).to.contain('"tagid":"403370"') }); }) it('accepts a single array as a size', function() { const singleSize = [{ 'bidder': 'sovrn', 'params': { 'tagid': '403370', 'iv': 'vet' }, 'adUnitCode': 'adunit-code', 'sizes': [300, 250], 'bidId': '30b31c1838de1e', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475' }] const request = spec.buildRequests(singleSize, bidderRequest) const payload = JSON.parse(request.data) expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}]) expect(payload.imp[0].banner.w).to.equal(1) expect(payload.imp[0].banner.h).to.equal(1) }) it('sends \'iv\' as query param if present', function () { const ivBidRequests = [{ 'bidder': 'sovrn', 'params': { 'tagid': '403370', 'iv': 'vet' }, 'adUnitCode': 'adunit-code', 'sizes': [ [300, 250], [300, 600] ], 'bidId': '30b31c1838de1e', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475' }]; const bidderRequest = { refererInfo: { referer: 'http://example.com/page.html', } }; const request = spec.buildRequests(ivBidRequests, bidderRequest); expect(request.url).to.contain('iv=vet') }); it('sends gdpr info if exists', function () { let consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; const bidderRequest = { 'bidderCode': 'sovrn', 'auctionId': '1d1a030790a475', 'bidderRequestId': '22edbae2733bf6', 'timeout': 3000, gdprConsent: { consentString: consentString, gdprApplies: true }, refererInfo: { referer: 'http://example.com/page.html', } }; bidderRequest.bids = [adUnitBidRequest]; const data = JSON.parse(spec.buildRequests([adUnitBidRequest], bidderRequest).data); expect(data.regs.ext.gdpr).to.exist.and.to.be.a('number'); expect(data.regs.ext.gdpr).to.equal(1); expect(data.user.ext.consent).to.exist.and.to.be.a('string'); expect(data.user.ext.consent).to.equal(consentString); }); it('should send us_privacy if bidderRequest has a value for uspConsent', function () { const uspString = '1NYN'; const bidderRequest = { 'bidderCode': 'sovrn', 'auctionId': '1d1a030790a475', 'bidderRequestId': '22edbae2733bf6', 'timeout': 3000, uspConsent: uspString, refererInfo: { referer: 'http://example.com/page.html', } }; bidderRequest.bids = [adUnitBidRequest]; const data = JSON.parse(spec.buildRequests([adUnitBidRequest], bidderRequest).data); expect(data.regs.ext['us_privacy']).to.equal(uspString); }); it('should add schain if present', function() { const schainRequests = [{ 'bidder': 'sovrn', 'params': { 'tagid': 403370 }, 'adUnitCode': 'adunit-code', 'sizes': [ [300, 250], [300, 600] ], 'bidId': '30b31c1838de1e', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', 'schain': { 'ver': '1.0', 'complete': 1, 'nodes': [ { 'asi': 'directseller.com', 'sid': '00001', 'rid': 'BidRequest1', 'hp': 1 } ] } }].concat(adUnitBidRequest); const bidderRequest = { refererInfo: { referer: 'http://example.com/page.html', } }; const data = JSON.parse(spec.buildRequests(schainRequests, bidderRequest).data); expect(data.source.ext.schain.nodes.length).to.equal(1) }); it('should add ids to the bid request', function() { const criteoIdRequest = [{ 'bidder': 'sovrn', 'params': { 'tagid': 403370 }, 'adUnitCode': 'adunit-code', 'sizes': [ [300, 250], [300, 600] ], 'bidId': '30b31c1838de1e', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', 'userId': { 'criteoId': 'A_CRITEO_ID', 'tdid': 'SOMESORTOFID', } }].concat(adUnitBidRequest); const bidderRequest = { refererInfo: { referer: 'http://example.com/page.html', } }; const data = JSON.parse(spec.buildRequests(criteoIdRequest, bidderRequest).data); expect(data.user.ext.eids[0].source).to.equal('criteo.com') expect(data.user.ext.eids[0].uids[0].id).to.equal('A_CRITEO_ID') expect(data.user.ext.eids[0].uids[0].atype).to.equal(1) expect(data.user.ext.eids[1].source).to.equal('adserver.org') expect(data.user.ext.eids[1].uids[0].id).to.equal('SOMESORTOFID') expect(data.user.ext.eids[1].uids[0].ext.rtiPartner).to.equal('TDID') expect(data.user.ext.eids[1].uids[0].atype).to.equal(1) expect(data.user.ext.tpid[0].source).to.equal('criteo.com') expect(data.user.ext.tpid[0].uid).to.equal('A_CRITEO_ID') expect(data.user.ext.prebid_criteoid).to.equal('A_CRITEO_ID') }); it('should ignore empty segments', function() { const request = spec.buildRequests([adUnitBidRequest], bidderRequest) const payload = JSON.parse(request.data) expect(payload.imp[0].ext).to.be.undefined }) it('should pass the segments param value as trimmed deal ids array', function() { const segmentsRequests = [{ 'bidder': 'sovrn', 'params': { 'segments': ' test1,test2 ' }, 'adUnitCode': 'adunit-code', 'sizes': [ [300, 250], [300, 600] ], 'bidId': '30b31c1838de1e', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475' }] const request = spec.buildRequests(segmentsRequests, bidderRequest) const payload = JSON.parse(request.data) expect(payload.imp[0].ext.deals[0]).to.equal('test1') expect(payload.imp[0].ext.deals[1]).to.equal('test2') }) it('should use the floor provided from the floor module if present', function() { const floorBid = {...adUnitBidRequest, getFloor: () => ({currency: 'USD', floor: 1.10})} floorBid.params = { tagid: 1234, bidfloor: 2.00 } const request = spec.buildRequests([floorBid], bidderRequest) const payload = JSON.parse(request.data) expect(payload.imp[0].bidfloor).to.equal(1.10) }) it('should use the floor from the param if there is no floor from the floor module', function() { const floorBid = {...adUnitBidRequest, getFloor: () => ({})} floorBid.params = { tagid: 1234, bidfloor: 2.00 } const request = spec.buildRequests([floorBid], bidderRequest) const payload = JSON.parse(request.data) expect(payload.imp[0].bidfloor).to.equal(2.00) }) describe('First Party Data', function () { let sandbox beforeEach(function() { sandbox = sinon.sandbox.create() }) afterEach(function() { sandbox.restore() }) it('should provide first party data if provided', function() { sandbox.stub(config, 'getConfig').callsFake(key => { const cfg = { ortb2: { site: { keywords: 'test keyword' }, user: { data: 'some user data' } } }; return utils.deepAccess(cfg, key); }); const request = spec.buildRequests([adUnitBidRequest], bidderRequest) const payload = JSON.parse(request.data) expect(payload.user.data).to.equal('some user data') expect(payload.site.keywords).to.equal('test keyword') expect(payload.site.page).to.equal('http://example.com/page.html') expect(payload.site.domain).to.equal('example.com') }) it('should append impression first party data', function () { const fpdBid = {...adUnitBidRequest} fpdBid.ortb2Imp = { ext: { data: { pbadslot: 'homepage-top-rect', adUnitSpecificAttribute: '123' } } } const request = spec.buildRequests([fpdBid], bidderRequest) const payload = JSON.parse(request.data) expect(payload.imp[0].ext.data.pbadslot).to.equal('homepage-top-rect') expect(payload.imp[0].ext.data.adUnitSpecificAttribute).to.equal('123') }) it('should not overwrite deals when impression fpd is present', function() { const fpdBid = {...adUnitBidRequest} fpdBid.params = {...adUnitBidRequest.params} fpdBid.params.segments = 'seg1, seg2' fpdBid.ortb2Imp = { ext: { data: { pbadslot: 'homepage-top-rect', adUnitSpecificAttribute: '123' } } } const request = spec.buildRequests([fpdBid], bidderRequest) const payload = JSON.parse(request.data) expect(payload.imp[0].ext.data.pbadslot).to.equal('homepage-top-rect') expect(payload.imp[0].ext.data.adUnitSpecificAttribute).to.equal('123') expect(payload.imp[0].ext.deals).to.deep.equal(['seg1', 'seg2']) }) }) }); describe('interpretResponse', function () { let response; beforeEach(function () { response = { body: { 'id': '37386aade21a71', 'seatbid': [{ 'bid': [{ 'id': 'a_403370_332fdb9b064040ddbec05891bd13ab28', 'crid': 'creativelycreatedcreativecreative', 'impid': '263c448586f5a1', 'price': 0.45882675, 'nurl': '<!-- NURL -->', 'adm': '<!-- Creative -->', 'h': 90, 'w': 728 }] }] } }; }); it('should get the correct bid response', function () { let expectedResponse = [{ 'requestId': '263c448586f5a1', 'cpm': 0.45882675, 'width': 728, 'height': 90, 'creativeId': 'creativelycreatedcreativecreative', 'dealId': null, 'currency': 'USD', 'netRevenue': true, 'mediaType': 'banner', 'ad': decodeURIComponent(`<!-- Creative --><img src=<!-- NURL -->>`), 'ttl': 60000, 'meta': { advertiserDomains: [] } }]; let result = spec.interpretResponse(response); expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0])); }); it('crid should default to the bid id if not on the response', function () { delete response.body.seatbid[0].bid[0].crid; let expectedResponse = [{ 'requestId': '263c448586f5a1', 'cpm': 0.45882675, 'width': 728, 'height': 90, 'creativeId': response.body.seatbid[0].bid[0].id, 'dealId': null, 'currency': 'USD', 'netRevenue': true, 'mediaType': 'banner', 'ad': decodeURIComponent(`<!-- Creative --><img src="<!-- NURL -->">`), 'ttl': 90, 'meta': { advertiserDomains: [] } }]; let result = spec.interpretResponse(response); expect(result[0]).to.deep.equal(expectedResponse[0]); }); it('should get correct bid response when dealId is passed', function () { response.body.seatbid[0].bid[0].dealid = 'baking'; let expectedResponse = [{ 'requestId': '263c448586f5a1', 'cpm': 0.45882675, 'width': 728, 'height': 90, 'creativeId': 'creativelycreatedcreativecreative', 'dealId': 'baking', 'currency': 'USD', 'netRevenue': true, 'mediaType': 'banner', 'ad': decodeURIComponent(`<!-- Creative --><img src="<!-- NURL -->">`), 'ttl': 90, 'meta': { advertiserDomains: [] } }]; let result = spec.interpretResponse(response); expect(result[0]).to.deep.equal(expectedResponse[0]); }); it('should get correct bid response when ttl is set', function () { response.body.seatbid[0].bid[0].ext = { 'ttl': 480 }; let expectedResponse = [{ 'requestId': '263c448586f5a1', 'cpm': 0.45882675, 'width': 728, 'height': 90, 'creativeId': 'creativelycreatedcreativecreative', 'dealId': null, 'currency': 'USD', 'netRevenue': true, 'mediaType': 'banner', 'ad': decodeURIComponent(`<!-- Creative --><img src="<!-- NURL -->">`), 'ttl': 480, 'meta': { advertiserDomains: [] } }]; let result = spec.interpretResponse(response); expect(result[0]).to.deep.equal(expectedResponse[0]); }); it('handles empty bid response', function () { let response = { body: { 'id': '37386aade21a71', 'seatbid': [] } }; let result = spec.interpretResponse(response); expect(result.length).to.equal(0); }); }); describe('getUserSyncs ', function() { let syncOptions = { iframeEnabled: true, pixelEnabled: false }; let iframeDisabledSyncOptions = { iframeEnabled: false, pixelEnabled: false }; let serverResponse = [ { 'body': { 'id': '546956d68c757f', 'seatbid': [ { 'bid': [ { 'id': 'a_448326_16c2ada014224bee815a90d2248322f5', 'impid': '2a3826aae345f4', 'price': 1.0099999904632568, 'nurl': 'http://localhost/rtb/impression?bannerid=220958&campaignid=3890&rtb_tid=15588614-75d2-40ab-b27e-13d2127b3c2e&rpid=1295&seatid=seat1&zoneid=448326&cb=26900712&tid=a_448326_16c2ada014224bee815a90d2248322f5', 'adm': 'yo a creative', 'crid': 'cridprebidrtb', 'w': 160, 'h': 600 }, { 'id': 'a_430392_beac4c1515da4576acf6cb9c5340b40c', 'impid': '3cf96fd26ed4c5', 'price': 1.0099999904632568, 'nurl': 'http://localhost/rtb/impression?bannerid=220957&campaignid=3890&rtb_tid=5bc0e68b-3492-448d-a6f9-26fa3fd0b646&rpid=1295&seatid=seat1&zoneid=430392&cb=62735099&tid=a_430392_beac4c1515da4576acf6cb9c5340b40c', 'adm': 'yo a creative', 'crid': 'cridprebidrtb', 'w': 300, 'h': 250 }, ] } ], 'ext': { 'iid': 13487408, sync: { pixels: [ { url: 'http://idprovider1.com' }, { url: 'http://idprovider2.com' } ] } } }, 'headers': {} } ]; it('should return if iid present on server response & iframe syncs enabled', function() { const expectedReturnStatement = [ { 'type': 'iframe', 'url': 'https://ap.lijit.com/beacon?informer=13487408', } ]; const returnStatement = spec.getUserSyncs(syncOptions, serverResponse); expect(returnStatement[0]).to.deep.equal(expectedReturnStatement[0]); }); it('should include gdpr consent string if present', function() { const gdprConsent = { gdprApplies: 1, consentString: 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A==' } const expectedReturnStatement = [ { 'type': 'iframe', 'url': `https://ap.lijit.com/beacon?gdpr_consent=${gdprConsent.consentString}&informer=13487408`, } ]; const returnStatement = spec.getUserSyncs(syncOptions, serverResponse, gdprConsent, ''); expect(returnStatement[0]).to.deep.equal(expectedReturnStatement[0]); }); it('should include us privacy string if present', function() { const uspString = '1NYN'; const expectedReturnStatement = [ { 'type': 'iframe', 'url': `https://ap.lijit.com/beacon?us_privacy=${uspString}&informer=13487408`, } ]; const returnStatement = spec.getUserSyncs(syncOptions, serverResponse, null, uspString); expect(returnStatement[0]).to.deep.equal(expectedReturnStatement[0]); }); it('should include all privacy strings if present', function() { const gdprConsent = { gdprApplies: 1, consentString: 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A==' } const uspString = '1NYN'; const expectedReturnStatement = [ { 'type': 'iframe', 'url': `https://ap.lijit.com/beacon?gdpr_consent=${gdprConsent.consentString}&us_privacy=${uspString}&informer=13487408`, } ]; const returnStatement = spec.getUserSyncs(syncOptions, serverResponse, gdprConsent, uspString); expect(returnStatement[0]).to.deep.equal(expectedReturnStatement[0]); }); it('should not return if iid missing on server response', function() { const returnStatement = spec.getUserSyncs(syncOptions, []); expect(returnStatement).to.be.empty; }); it('should not return if iframe syncs disabled', function() { const returnStatement = spec.getUserSyncs(iframeDisabledSyncOptions, serverResponse); expect(returnStatement).to.be.empty; }); it('should include pixel syncs', function() { let pixelEnabledOptions = { iframeEnabled: false, pixelEnabled: true }; const resp2 = { 'body': { 'id': '546956d68c757f-2', 'seatbid': [ { 'bid': [ { 'id': 'a_448326_16c2ada014224bee815a90d2248322f5-2', 'impid': '2a3826aae345f4', 'price': 1.0099999904632568, 'nurl': 'http://localhost/rtb/impression?bannerid=220958&campaignid=3890&rtb_tid=15588614-75d2-40ab-b27e-13d2127b3c2e&rpid=1295&seatid=seat1&zoneid=448326&cb=26900712&tid=a_448326_16c2ada014224bee815a90d2248322f5', 'adm': 'yo a creative', 'crid': 'cridprebidrtb', 'w': 160, 'h': 600 }, { 'id': 'a_430392_beac4c1515da4576acf6cb9c5340b40c-2', 'impid': '3cf96fd26ed4c5', 'price': 1.0099999904632568, 'nurl': 'http://localhost/rtb/impression?bannerid=220957&campaignid=3890&rtb_tid=5bc0e68b-3492-448d-a6f9-26fa3fd0b646&rpid=1295&seatid=seat1&zoneid=430392&cb=62735099&tid=a_430392_beac4c1515da4576acf6cb9c5340b40c', 'adm': 'yo a creative', 'crid': 'cridprebidrtb', 'w': 300, 'h': 250 }, ] } ], 'ext': { 'iid': 13487408, sync: { pixels: [ { url: 'http://idprovider3.com' }, { url: 'http://idprovider4.com' } ] } } }, 'headers': {} } const returnStatement = spec.getUserSyncs(pixelEnabledOptions, [...serverResponse, resp2]); expect(returnStatement.length).to.equal(4); expect(returnStatement).to.deep.include.members([ { type: 'image', url: 'http://idprovider1.com' }, { type: 'image', url: 'http://idprovider2.com' }, { type: 'image', url: 'http://idprovider3.com' }, { type: 'image', url: 'http://idprovider4.com' } ]); }); }); describe('prebid 3 upgrade', function() { const bidRequests = [{ 'bidder': 'sovrn', 'params': { 'tagid': '403370' }, 'adUnitCode': 'adunit-code', mediaTypes: { banner: { sizes: [ [300, 250], [300, 600] ] } }, 'bidId': '30b31c1838de1e', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475' }]; const bidderRequest = { refererInfo: { referer: 'http://example.com/page.html', } }; const request = spec.buildRequests(bidRequests, bidderRequest); const payload = JSON.parse(request.data); it('gets sizes from mediaTypes.banner', function() { expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}, {w: 300, h: 600}]) expect(payload.imp[0].banner.w).to.equal(1) expect(payload.imp[0].banner.h).to.equal(1) }) it('gets correct site info', function() { expect(payload.site.page).to.equal('http://example.com/page.html'); expect(payload.site.domain).to.equal('example.com'); }) }) })