UNPKG

mk9-prebid

Version:

Header Bidding Management Library

1,399 lines (1,216 loc) 105 kB
import { expect } from 'chai'; import { PrebidServer as Adapter, resetSyncedStatus, resetWurlMap } from 'modules/prebidServerBidAdapter/index.js'; import adapterManager from 'src/adapterManager.js'; import * as utils from 'src/utils.js'; import { ajax } from 'src/ajax.js'; import { config } from 'src/config.js'; import events from 'src/events.js'; import CONSTANTS from 'src/constants.json'; import { server } from 'test/mocks/xhr.js'; import { createEidsArray } from 'modules/userId/eids.js'; let CONFIG = { accountId: '1', enabled: true, bidders: ['appnexus'], timeout: 1000, cacheMarkup: 2, endpoint: { p1Consent: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction', noP1Consent: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' } }; const REQUEST = { 'account_id': '1', 'tid': '437fbbf5-33f5-487a-8e16-a7112903cfe5', 'max_bids': 1, 'timeout_millis': 1000, 'secure': 0, 'url': '', 'prebid_version': '0.30.0-pre', 's2sConfig': CONFIG, 'ad_units': [ { 'code': 'div-gpt-ad-1460505748561-0', 'sizes': [[300, 250], [300, 600]], 'mediaTypes': { 'banner': { 'sizes': [[300, 250], [300, 300]] }, 'native': { 'title': { 'required': true, 'len': 800 }, 'image': { 'required': true, 'sizes': [989, 742], }, 'icon': { 'required': true, 'aspect_ratios': [{ 'min_height': 10, 'min_width': 10, 'ratio_height': 1, 'ratio_width': 1 }] }, 'sponsoredBy': { 'required': true } } }, 'transactionId': '4ef956ad-fd83-406d-bd35-e4bb786ab86c', 'bids': [ { 'bid_id': '123', 'bidder': 'appnexus', 'params': { 'placementId': '10433394', 'member': 123 } } ] } ] }; const VIDEO_REQUEST = { 'account_id': '1', 'tid': '437fbbf5-33f5-487a-8e16-a7112903cfe5', 'max_bids': 1, 'timeout_millis': 1000, 'secure': 0, 'url': '', 'prebid_version': '1.4.0-pre', 's2sConfig': CONFIG, 'ad_units': [ { 'code': 'div-gpt-ad-1460505748561-0', 'sizes': [640, 480], 'mediaTypes': { 'video': { 'playerSize': [[640, 480]], 'mimes': ['video/mp4'] } }, 'transactionId': '4ef956ad-fd83-406d-bd35-e4bb786ab86c', 'bids': [ { 'bid_id': '123', 'bidder': 'appnexus', 'params': { 'placementId': '12349520' } } ] } ] }; const OUTSTREAM_VIDEO_REQUEST = { 'account_id': '1', 'tid': '437fbbf5-33f5-487a-8e16-a7112903cfe5', 'max_bids': 1, 'timeout_millis': 1000, 'secure': 0, 'url': '', 'prebid_version': '1.4.0-pre', 's2sConfig': CONFIG, 'ad_units': [ { 'code': 'div-gpt-ad-1460505748561-0', 'sizes': [640, 480], 'mediaTypes': { 'video': { playerSize: [[640, 480]], context: 'outstream', mimes: ['video/mp4'], renderer: { url: 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js', render: function (bid) { ANOutstreamVideo.renderAd({ targetId: bid.adUnitCode, adResponse: bid.adResponse, }); } } }, banner: { sizes: [[300, 250]] } }, 'transactionId': '4ef956ad-fd83-406d-bd35-e4bb786ab86c', 'bids': [ { 'bid_id': '123', 'bidder': 'appnexus', 'params': { 'placementId': '12349520' } } ] }, { code: 'video1', mediaTypes: { video: { playerSize: [640, 480], context: 'outstream', mimes: ['video/mp4'], skip: 1 } }, bids: [ { bidder: 'appnexus', params: { placementId: 13232385, video: { skippable: true, playback_method: ['auto_play_sound_off'] } } } ] } ], }; let BID_REQUESTS; const RESPONSE_NO_BID_NO_UNIT = { 'tid': '437fbbf5-33f5-487a-8e16-a7112903cfe5', 'status': 'OK', 'bidder_status': [{ 'bidder': 'appnexus', 'response_time_ms': 132, 'no_bid': true }] }; const RESPONSE_NO_BID_UNIT_SET = { 'tid': '437fbbf5-33f5-487a-8e16-a7112903cfe5', 'status': 'OK', 'bidder_status': [{ 'bidder': 'appnexus', 'ad_unit': 'div-gpt-ad-1460505748561-0', 'response_time_ms': 91, 'no_bid': true }] }; const RESPONSE_NO_COOKIE = { 'tid': 'd6eca075-4a59-4346-bdb3-86531830ef2c', 'status': 'OK', 'bidder_status': [{ 'bidder': 'pubmatic', 'no_cookie': true, 'usersync': { 'url': '//ads.pubmatic.com/AdServer/js/user_sync.html?predirect=http://localhost:8000/setuid?bidder=pubmatic&uid=', 'type': 'iframe' } }] }; const RESPONSE_NO_PBS_COOKIE = { 'tid': '882fe33e-2981-4257-bd44-bd3b03945f48', 'status': 'no_cookie', 'bidder_status': [{ 'bidder': 'rubicon', 'no_cookie': true, 'usersync': { 'url': 'https://pixel.rubiconproject.com/exchange/sync.php?p=prebid', 'type': 'redirect' } }, { 'bidder': 'pubmatic', 'no_cookie': true, 'usersync': { 'url': '//ads.pubmatic.com/AdServer/js/user_sync.html?predirect=https%3A%2F%2Fprebid.adnxs.com%2Fpbs%2Fv1%2Fsetuid%3Fbidder%3Dpubmatic%26uid%3D', 'type': 'iframe' } }, { 'bidder': 'appnexus', 'response_time_ms': 162, 'num_bids': 1, 'debug': [{ 'request_uri': 'http://ib.adnxs.com/openrtb2', 'request_body': '{"id":"882fe33e-2981-4257-bd44-bd3b03945f48","imp":[{"id":"/19968336/header-bid-tag-0","banner":{"w":300,"h":250,"format":[{"w":300,"h":250}]},"secure":1,"ext":{"appnexus":{"placement_id":5914989}}}],"site":{"domain":"nytimes.com","page":"http://www.nytimes.com"},"device":{"ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36","ip":"75.97.0.47"},"user":{"id":"3519479852893340159","buyeruid":"3519479852893340159"},"at":1,"tmax":1000,"source":{"fd":1,"tid":"882fe33e-2981-4257-bd44-bd3b03945f48"}}', 'response_body': '{"id":"882fe33e-2981-4257-bd44-bd3b03945f48"}', 'status_code': 200 }] }], 'bids': [{ 'bid_id': '123', 'code': 'div-gpt-ad-1460505748561-0', 'creative_id': '70928274', 'bidder': 'appnexus', 'price': 0.07425, 'adm': '<script type="application/javascript" src="https://secure-nym.adnxs.com/ab?e=wqT_3QLeCPBOXgQAAAMA1gAFAQi5krDKBRCwho2ft8LKoCMY_4PozveI7eswIAEqLQnbgoxDEVi5PxElYqnyDAKzPxkAAAAgXA8zQCHOzMzMzMy8PykzMwECsMM_MO2C6QI47RtA_AxIAlCSj-khWL-tNGAAaNfUTniivwSAAQGKAQNVU0SSAQEG8FSYAawCoAH6AagBAbABALgBAsABBcgBAtABCdgBAOABAPABAIoCkgF1ZignYScsIDE2OTc2MjksIDE0OTgxNTUzMjEpO3VmKCdyJywgNzA5MjgyNzQsQh4ABGMnATsQODY2NTVKPAAgZycsIDM5OTgzTh0AKGknLCA0OTM1MTUsMlcA8IeSAs0CIWhWRE5jZ2pfdVlVSUVKS1A2U0VZQUNDX3JUUXdBRGdBUUFCSV9BeFE3WUxwQWxnQVlKOEJhQUJ3QUhnQWdBRUFpQUVBa0FFQm1BRUJvQUVCcUFFRHNBRUF1UUhPRGRmZE16UERQOEVCemczWDNUTXp3el9KQVFBQUFBQUFBUEFfMlFFCQw0QUR3UC1BQnk0OGU5UUUFFChnQUlCaUFLMzdjRQEIQEIzNWNCaUFMZzZJNEVpQUxoDQgAag0IAG4NCABvAQhIa0FJSG1BSUFvQUlBcUFJR3RRSQVUAHYNCPBed0FJQXlBSUEwQUlBMkFJQTRBTDYtd2ZvQXBqaXI4b0Y4Z0lGZG1semFUSDRBZ0NBQXdHUUF3Q1lBd0dvQV8tNWhRaTZBd2xPV1UweU9qTTJNamcumgItIV93ajdud2oyUAHwTHY2MDBJQUFvQURvSlRsbE5Nam96TmpJNNgCAOACvtUr6gIWaHR0cDovL3d3dy5ueXRpbWVzLmNvbfICEQoGQURWX0lEEgcxNjk3NjI5BRQIQ1BHBRQt9AEUCAVDUAETBAgxTSXA8gINCghBRFZfRlJFURIBMPICGQoPQ1VTVE9NX01PREVMX0lEEgYxMzA1NTTyAh8KFjIcAFBMRUFGX05BTUUSBXZpc2kx8gIoCho2IgAIQVNUAUkcSUZJRUQSCjFBzvB4NDkxNDSAAwCIAwGQAwCYAxSgAwGqAwDAA6wCyAMA2APjBuADAOgDAPgDA4AEAJIECS9vcGVucnRiMpgEAKIECjc1Ljk3LjAuNDeoBACyBAoIABAAGAAgADAAuAQAwAQAyAQA0gQJTllNMjozNjI42gQCCAHgBADwBGGlIIgFAZgFAKAF_xEBuAGqBSQ4ODJmZTMzZS0yOTgxLTQyNTctYmQ0NC1iZDNiMDM5NDVmNDjABQDJBQAAAQI08D_SBQkJAAAAAAAAAAA.&s=d4bc7cd2e5d7e1910a591bc97df6ae9e63333e52&referrer=http%3A%2F%2Fwww.nytimes.com&pp=${AUCTION_PRICE}&"></script>', 'width': 300, 'height': 250, 'response_time_ms': 162 }] }; const RESPONSE_OPENRTB = { 'id': 'c7dcf14f', 'seatbid': [ { 'bid': [ { 'id': '8750901685062148', 'impid': 'div-gpt-ad-1460505748561-0', 'price': 0.5, 'adm': '<script src="http://lax1-ib.adnxs.com/ab?e=wqT_3QKgB6CgAwAAAwDWAAUBCJ7kvtMFEPft7JnIuImSdBj87IDv8q21rXcqNgkAAAECCOA_EQEHNAAA4D8ZAAAAgOtR4D8hERIAKREJADERG6Aw8ub8BDi-B0C-B0gCUNbLkw5Y4YBIYABokUB48NIEgAEBigEDVVNEkgUG8FKYAawCoAH6AagBAbABALgBAsABA8gBAtABCdgBAOABAPABAIoCOnVmKCdhJywgNDk0NDcyLCAxNTE3MjY5NTM0KTt1ZigncicsIDI5NjgxMTEwLDIeAPCckgKBAiFqRHF3RUFpNjBJY0VFTmJMa3c0WUFDRGhnRWd3QURnQVFBUkl2Z2RROHViOEJGZ0FZUF9fX184UGFBQndBWGdCZ0FFQmlBRUJrQUVCbUFFQm9BRUJxQUVEc0FFQXVRRXBpNGlEQUFEZ1A4RUJLWXVJZ3dBQTREX0pBVkx3MU5mdl9lMF8yUUVBQUFBQUFBRHdQLUFCQVBVQgUPKEpnQ0FLQUNBTFVDBRAETDAJCPBUTUFDQWNnQ0FkQUNBZGdDQWVBQ0FPZ0NBUGdDQUlBREFaQURBSmdEQWFnRHV0Q0hCTG9ERVdSbFptRjFiSFFqVEVGWU1Ub3pPRFk1mgI5IS1ndndfUTYEAfCENFlCSUlBUW9BRG9SWkdWbVlYVnNkQ05NUVZneE9qTTROamsu2ALoB-ACx9MB6gJHaHR0cDovL3ByZWJpZC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2dwdC9hcHBuZXh1cy10ZXN0Lmh0bWzyAhAKBkFEVl9JRBIGNCXTHPICEQoGQ1BHARM4BzE5Nzc5MzPyAhAKBUNQBRPwljg1MTM1OTSAAwGIAwGQAwCYAxSgAwGqAwDAA6wCyAMA2AMA4AMA6AMA-AMDgAQAkgQJL29wZW5ydGIymAQAogQMMjE2LjU1LjQ3Ljk0qAQAsgQMCAAQABgAIAAwADgAuAQAwAQAyAQA0gQRZGVmYXVsdCNMQVgxOjM4NjnaBAIIAeAEAPAE1suTDogFAZgFAKAF______8BA7ABqgUkYzdkY2YxNGYtZjliYS00Yzc3LWEzYjQtMjdmNmRmMzkwNjdmwAUAyQVpLhTwP9IFCQkJDFAAANgFAeAFAfAFAfoFBAgAEACQBgA.&s=f4dc8b6fa65845d08f0a87c145e12cb7d6288c2a&referrer=http%3A%2F%2Fprebid.localhost%3A9999%2FintegrationExamples%2Fgpt%2Fappnexus-test.html&pp=${AUCTION_PRICE}"></script>', 'adid': '29681110', 'adomain': ['appnexus.com'], 'iurl': 'http://lax1-ib.adnxs.com/cr?id=2968111', 'cid': '958', 'crid': '2968111', 'dealid': 'test-dealid', 'w': 300, 'h': 250, 'ext': { 'prebid': { 'type': 'banner', 'event': { 'win': 'http://wurl.org?id=333' }, 'meta': { 'dchain': { 'ver': '1.0', 'complete': 0, 'nodes': [ { 'asi': 'magnite.com', 'bsid': '123456789', } ] } } }, 'bidder': { 'appnexus': { 'brand_id': 1, 'auction_id': 3, 'bidder_id': 2 } } } } ], 'seat': 'appnexus' }, ], 'cur': 'EUR', 'ext': { 'responsetimemillis': { 'appnexus': 8, } } }; const RESPONSE_OPENRTB_VIDEO = { id: 'c7dcf14f', seatbid: [ { bid: [ { id: '1987250005171537465', impid: 'div-gpt-ad-1460505748561-0', price: 10, adm: '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><VAST version="3.0"><Ad id="81877115" sequence="0"><Wrapper><AdSystem version="3.0">adnxs</AdSystem><VASTAdTagURI><![CDATA[http://lax1-ib.adnxs.com/ab?e=wqT_3QLZBq]]></VASTAdTagURI><Impression><![CDATA[http://ib.adnxs.com/nop]]></Impression><Creatives><Creative adID="81877115"><Linear></Linear></Creative></Creatives></Wrapper></Ad></VAST>', adid: '81877115', adomain: ['appnexus.com'], iurl: 'http://lax1-ib.adnxs.com/cr?id=81877115', cid: '3535', crid: '81877115', dealid: 'test-dealid', w: 1, h: 1, ext: { prebid: { type: 'video', bidid: '654321' }, bidder: { appnexus: { brand_id: 1, auction_id: 6673622101799484743, bidder_id: 2, bid_ad_type: 1, }, }, }, }, ], seat: 'appnexus', }, ], ext: { responsetimemillis: { appnexus: 81, }, }, }; const RESPONSE_OPENRTB_NATIVE = { 'id': 'c7dcf14f', 'seatbid': [ { 'bid': [ { 'id': '6451317310275562039', 'impid': 'div-gpt-ad-1460505748561-0', 'price': 10, 'adm': { 'ver': '1.2', 'assets': [ { 'id': 1, 'img': { 'url': 'https://vcdn.adnxs.com/p/creative-image/f8/7f/0f/13/f87f0f13-230c-4f05-8087-db9216e393de.jpg', 'w': 989, 'h': 742, 'ext': { 'appnexus': { 'prevent_crop': 0 } } } }, { 'id': 2, 'img': { 'url': 'https://vcdn.adnxs.com/p/creative-image/1a/3e/e9/5b/1a3ee95b-06cd-4260-98c7-0258627c9197.png', 'w': 127, 'h': 83, 'ext': { 'appnexus': { 'prevent_crop': 0 } } } }, { 'id': 0, 'title': { 'text': 'This is a Prebid Native Creative' } }, { 'id': 3, 'data': { 'value': 'Prebid.org' } } ], 'link': { 'url': 'https://lax1-ib.adnxs.com/click?AAAAAAAAJEAAAAAAAAAkQAAAAAAAACRAAAAAAAAAJEAAAAAAAAAkQGdce2vBWudAJZpFu1er1zA7ZzddAAAAAOLoyQBtJAAAbSQAAAIAAAC8pM8FnPgWAAAAAABVU0QAVVNEAAEAAQBNXQAAAAABAgMCAAAAALsAuhVqdgAAAAA./cpcpm=AAAAAAAAAAA=/bcr=AAAAAAAA8D8=/pp=${AUCTION_PRICE}/cnd=%213Q5HCQj8-LwKELzJvi4YnPFbIAQoADEAAAAAAAAkQDoJTEFYMTo0MDc3QKcPSQAAAAAAAPA_UQAAAAAAAAAAWQAAAAAAAAAAYQAAAAAAAAAAaQAAAAAAAAAAcQAAAAAAAAAA/cca=OTMyNSNMQVgxOjQwNzc=/bn=84305/test=1/clickenc=http%3A%2F%2Fprebid.org%2Fdev-docs%2Fshow-native-ads.html' }, 'eventtrackers': [ { 'event': 1, 'method': 1, 'url': 'https://lax1-ib.adnxs.com/it?an_audit=0&test=1&referrer=http%3A%2F%2Flocalhost%3A9999%2FintegrationExamples%2Fgpt%2Fdemo_native.html&e=wqT_3QKCCKACBAAAAwDWAAUBCLvO3ekFEOe47duW2NbzQBiltJba--rq6zAqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlC8yb4uWJzxW2AAaM26dXjRkgWAAQGKAQNVU0SSAQEG8FKYAQGgAQGoAQGwAQC4AQLAAQPIAQLQAQnYAQDgAQHwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NjM5MTE5OTUpO3VmKCdyJywgOTc0OTQyMDQsIC4eAPQ0AZICnQIhb2pkaWlnajgtTHdLRUx6SnZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWVAwQmFBQndBSGdBZ0FFQWlBRUFrQUVCbUFFQm9BRUJxQUVEc0FFQXVRSHpyV3FrQUFBa1FNRUI4NjFxcEFBQUpFREpBVVZpYmxDaFpRQkEyUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBUGdCQUpnQ0FLQUNBTFVDQUFBQUFMMENBQUFBQU1BQ0FNZ0NBT0FDQU9nQ0FQZ0NBSUFEQVpBREFKZ0RBYWdEX1BpOENyb0RDVXhCV0RFNk5EQTNOLUFEcHctUUJBQ1lCQUhCQkFBQUFBQUFBQUFBeVFRQUFBQUFBQUFBQU5nRUFBLi6aAoUBITNRNUhDUWo4LUx3S0VMeiUhJG5QRmJJQVFvQUQRvVhBa1FEb0pURUZZTVRvME1EYzNRS2NQUxFUDFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0FwHYAgDgAq2YSOoCPmh0dHA6Ly9sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2dwdC9kZW1vX25hdGl2ZS5odG1sgAMAiAMBkAMAmAMUoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwOABACSBAkvb3BlbnJ0YjKYBACiBA0xNzMuMjQ0LjM2LjQwqATtoySyBAwIABAAGAAgADAAOAC4BADABADIBADSBA45MzI1I0xBWDE6NDA3N9oEAggB4AQA8AS8yb4uiAUBmAUAoAX___________8BqgUkZTU5YzNlYjYtNmRkNi00MmQ5LWExMWEtM2FhMTFjOTc5MGUwwAUAyQUAAAAAAADwP9IFCQkAaVh0ANgFAeAFAfAFmfQh-gUECAAQAJAGAZgGALgGAMEGCSQk8D_IBgDaBhYKEAkQGQEBwTTgBgzyBgIIAIAHAYgHAA..&s=11ababa390e9f7983de260493fc5b91ec5b1b3d4&pp=${AUCTION_PRICE}' } ] }, 'adid': '97494204', 'adomain': [ 'http://prebid.org' ], 'iurl': 'https://lax1-ib.adnxs.com/cr?id=97494204', 'cid': '9325', 'crid': '97494204', 'cat': [ 'IAB3-1' ], 'ext': { 'prebid': { 'targeting': { 'hb_bidder': 'appnexus', 'hb_pb': '10.00' }, 'type': 'native', 'video': { 'duration': 0, 'primary_category': '' } }, 'bidder': { 'appnexus': { 'brand_id': 555545, 'auction_id': 4676806524825984103, 'bidder_id': 2, 'bid_ad_type': 3 } } } } ], 'seat': 'appnexus' } ] }; describe('S2S Adapter', function () { let adapter, addBidResponse = sinon.spy(), done = sinon.spy(); beforeEach(function () { config.resetConfig(); adapter = new Adapter(); BID_REQUESTS = [ { 'bidderCode': 'appnexus', 'auctionId': '173afb6d132ba3', 'bidderRequestId': '3d1063078dfcc8', 'tid': '437fbbf5-33f5-487a-8e16-a7112903cfe5', 'bids': [ { 'bidder': 'appnexus', 'params': { 'placementId': '10433394', 'member': 123, 'keywords': { 'foo': ['bar', 'baz'], 'fizz': ['buzz'] } }, 'bid_id': '123', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'mediaTypes': { 'banner': { 'sizes': [[300, 250]] } }, 'transactionId': '4ef956ad-fd83-406d-bd35-e4bb786ab86c', 'sizes': [300, 250], 'bidId': '123', 'bidderRequestId': '3d1063078dfcc8', 'auctionId': '173afb6d132ba3', 'storedAuctionResponse': 11111 } ], 'auctionStart': 1510852447530, 'timeout': 5000, 'src': 's2s', 'doneCbCallCount': 0, 'refererInfo': { 'referer': 'http://mytestpage.com' } } ]; }); afterEach(function () { addBidResponse.resetHistory(); done.resetHistory(); }); after(function () { config.resetConfig(); }); describe('request function', function () { beforeEach(function () { resetSyncedStatus(); }); it('should block request if config did not define p1Consent URL in endpoint object config', function() { let badConfig = utils.deepClone(CONFIG); badConfig.endpoint = { noP1Consent: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' }; config.setConfig({ s2sConfig: badConfig }); let badCfgRequest = utils.deepClone(REQUEST); badCfgRequest.s2sConfig = badConfig; adapter.callBids(badCfgRequest, BID_REQUESTS, addBidResponse, done, ajax); expect(server.requests.length).to.equal(0); }); it('should block request if config did not define noP1Consent URL in endpoint object config', function() { let badConfig = utils.deepClone(CONFIG); badConfig.endpoint = { p1Consent: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' }; config.setConfig({ s2sConfig: badConfig }); let badCfgRequest = utils.deepClone(REQUEST); badCfgRequest.s2sConfig = badConfig; let badBidderRequest = utils.deepClone(BID_REQUESTS); badBidderRequest[0].gdprConsent = { consentString: 'abc123', addtlConsent: 'superduperconsent', gdprApplies: true, apiVersion: 2, vendorData: { purpose: { consents: { 1: false } } } }; adapter.callBids(badCfgRequest, badBidderRequest, addBidResponse, done, ajax); expect(server.requests.length).to.equal(0); }); it('should block request if config did not define any URLs in endpoint object config', function() { let badConfig = utils.deepClone(CONFIG); badConfig.endpoint = {}; config.setConfig({ s2sConfig: badConfig }); let badCfgRequest = utils.deepClone(REQUEST); badCfgRequest.s2sConfig = badConfig; adapter.callBids(badCfgRequest, BID_REQUESTS, addBidResponse, done, ajax); expect(server.requests.length).to.equal(0); }); it('should add outstream bc renderer exists on mediatype', function () { config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(OUTSTREAM_VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.imp[0].banner).to.exist; expect(requestBid.imp[0].video).to.exist; }); it('should default video placement if not defined and instream', function () { let ortb2Config = utils.deepClone(CONFIG); ortb2Config.endpoint.p1Consent = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; config.setConfig({ s2sConfig: ortb2Config }); let videoBid = utils.deepClone(VIDEO_REQUEST); videoBid.ad_units[0].mediaTypes.video.context = 'instream'; adapter.callBids(videoBid, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.imp[0].banner).to.not.exist; expect(requestBid.imp[0].video).to.exist; expect(requestBid.imp[0].video.placement).to.equal(1); }); it('converts video mediaType properties into openRTB format', function () { let ortb2Config = utils.deepClone(CONFIG); ortb2Config.endpoint.p1Consent = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; config.setConfig({ s2sConfig: ortb2Config }); let videoBid = utils.deepClone(VIDEO_REQUEST); videoBid.ad_units[0].mediaTypes.video.context = 'instream'; adapter.callBids(videoBid, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.imp[0].banner).to.not.exist; expect(requestBid.imp[0].video).to.exist; expect(requestBid.imp[0].video.placement).to.equal(1); expect(requestBid.imp[0].video.w).to.equal(640); expect(requestBid.imp[0].video.h).to.equal(480); expect(requestBid.imp[0].video.playerSize).to.be.undefined; expect(requestBid.imp[0].video.context).to.be.undefined; }); it('exists and is a function', function () { expect(adapter.callBids).to.exist.and.to.be.a('function'); }); describe('gdpr tests', function () { afterEach(function () { $$PREBID_GLOBAL$$.requestBids.removeAll(); }); it('adds gdpr consent information to ortb2 request depending on presence of module', function () { let consentConfig = { consentManagement: { cmpApi: 'iab' }, s2sConfig: CONFIG }; config.setConfig(consentConfig); let gdprBidRequest = utils.deepClone(BID_REQUESTS); gdprBidRequest[0].gdprConsent = { consentString: 'abc123', gdprApplies: true }; adapter.callBids(REQUEST, gdprBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.regs.ext.gdpr).is.equal(1); expect(requestBid.user.ext.consent).is.equal('abc123'); config.resetConfig(); config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); requestBid = JSON.parse(server.requests[1].requestBody); expect(requestBid.regs).to.not.exist; expect(requestBid.user).to.not.exist; }); it('adds additional consent information to ortb2 request depending on presence of module', function () { let consentConfig = { consentManagement: { cmpApi: 'iab' }, s2sConfig: CONFIG }; config.setConfig(consentConfig); let gdprBidRequest = utils.deepClone(BID_REQUESTS); gdprBidRequest[0].gdprConsent = { consentString: 'abc123', addtlConsent: 'superduperconsent', gdprApplies: true }; adapter.callBids(REQUEST, gdprBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.regs.ext.gdpr).is.equal(1); expect(requestBid.user.ext.consent).is.equal('abc123'); expect(requestBid.user.ext.ConsentedProvidersSettings.consented_providers).is.equal('superduperconsent'); config.resetConfig(); config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); requestBid = JSON.parse(server.requests[1].requestBody); expect(requestBid.regs).to.not.exist; expect(requestBid.user).to.not.exist; }); it('check gdpr info gets added into cookie_sync request: have consent data', function () { let cookieSyncConfig = utils.deepClone(CONFIG); cookieSyncConfig.syncEndpoint = { p1Consent: 'https://prebid.adnxs.com/pbs/v1/cookie_sync' }; let consentConfig = { consentManagement: { cmpApi: 'iab' }, s2sConfig: cookieSyncConfig }; config.setConfig(consentConfig); let gdprBidRequest = utils.deepClone(BID_REQUESTS); gdprBidRequest[0].gdprConsent = { consentString: 'abc123def', gdprApplies: true }; const s2sBidRequest = utils.deepClone(REQUEST); s2sBidRequest.s2sConfig = cookieSyncConfig; adapter.callBids(s2sBidRequest, gdprBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.gdpr).is.equal(1); expect(requestBid.gdpr_consent).is.equal('abc123def'); expect(requestBid.bidders).to.contain('appnexus').and.to.have.lengthOf(1); expect(requestBid.account).is.equal('1'); }); it('check gdpr info gets added into cookie_sync request: have consent data but gdprApplies is false', function () { let cookieSyncConfig = utils.deepClone(CONFIG); cookieSyncConfig.syncEndpoint = { p1Consent: 'https://prebid.adnxs.com/pbs/v1/cookie_sync' }; let consentConfig = { consentManagement: { cmpApi: 'iab' }, s2sConfig: cookieSyncConfig }; config.setConfig(consentConfig); const s2sBidRequest = utils.deepClone(REQUEST); s2sBidRequest.s2sConfig = cookieSyncConfig; let gdprBidRequest = utils.deepClone(BID_REQUESTS); gdprBidRequest[0].gdprConsent = { consentString: 'xyz789abcc', gdprApplies: false }; adapter.callBids(s2sBidRequest, gdprBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.gdpr).is.equal(0); expect(requestBid.gdpr_consent).is.undefined; }); it('checks gdpr info gets added to cookie_sync request: applies is false', function () { let cookieSyncConfig = utils.deepClone(CONFIG); cookieSyncConfig.syncEndpoint = { p1Consent: 'https://prebid.adnxs.com/pbs/v1/cookie_sync' }; let consentConfig = { consentManagement: { cmpApi: 'iab' }, s2sConfig: cookieSyncConfig }; config.setConfig(consentConfig); let gdprBidRequest = utils.deepClone(BID_REQUESTS); gdprBidRequest[0].gdprConsent = { consentString: undefined, gdprApplies: false }; const s2sBidRequest = utils.deepClone(REQUEST); s2sBidRequest.s2sConfig = cookieSyncConfig; adapter.callBids(s2sBidRequest, gdprBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.gdpr).is.equal(0); expect(requestBid.gdpr_consent).is.undefined; }); }); describe('us_privacy (ccpa) consent data', function () { afterEach(function () { $$PREBID_GLOBAL$$.requestBids.removeAll(); }); it('is added to ortb2 request when in bidRequest', function () { config.setConfig({ s2sConfig: CONFIG }); let uspBidRequest = utils.deepClone(BID_REQUESTS); uspBidRequest[0].uspConsent = '1NYN'; adapter.callBids(REQUEST, uspBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.regs.ext.us_privacy).is.equal('1NYN'); config.resetConfig(); config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); requestBid = JSON.parse(server.requests[1].requestBody); expect(requestBid.regs).to.not.exist; }); it('is added to cookie_sync request when in bidRequest', function () { let cookieSyncConfig = utils.deepClone(CONFIG); cookieSyncConfig.syncEndpoint = { p1Consent: 'https://prebid.adnxs.com/pbs/v1/cookie_sync' }; config.setConfig({ s2sConfig: cookieSyncConfig }); let uspBidRequest = utils.deepClone(BID_REQUESTS); uspBidRequest[0].uspConsent = '1YNN'; const s2sBidRequest = utils.deepClone(REQUEST); s2sBidRequest.s2sConfig = cookieSyncConfig; adapter.callBids(s2sBidRequest, uspBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.us_privacy).is.equal('1YNN'); expect(requestBid.bidders).to.contain('appnexus').and.to.have.lengthOf(1); expect(requestBid.account).is.equal('1'); }); }); describe('gdpr and us_privacy (ccpa) consent data', function () { afterEach(function () { $$PREBID_GLOBAL$$.requestBids.removeAll(); }); it('is added to ortb2 request when in bidRequest', function () { config.setConfig({ s2sConfig: CONFIG }); let consentBidRequest = utils.deepClone(BID_REQUESTS); consentBidRequest[0].uspConsent = '1NYN'; consentBidRequest[0].gdprConsent = { consentString: 'abc123', gdprApplies: true }; adapter.callBids(REQUEST, consentBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.regs.ext.us_privacy).is.equal('1NYN'); expect(requestBid.regs.ext.gdpr).is.equal(1); expect(requestBid.user.ext.consent).is.equal('abc123'); config.resetConfig(); config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); requestBid = JSON.parse(server.requests[1].requestBody); expect(requestBid.regs).to.not.exist; expect(requestBid.user).to.not.exist; }); it('is added to cookie_sync request when in bidRequest', function () { let cookieSyncConfig = utils.deepClone(CONFIG); cookieSyncConfig.syncEndpoint = { p1Consent: 'https://prebid.adnxs.com/pbs/v1/cookie_sync' }; config.setConfig({ s2sConfig: cookieSyncConfig }); let consentBidRequest = utils.deepClone(BID_REQUESTS); consentBidRequest[0].uspConsent = '1YNN'; consentBidRequest[0].gdprConsent = { consentString: 'abc123def', gdprApplies: true }; const s2sBidRequest = utils.deepClone(REQUEST); s2sBidRequest.s2sConfig = cookieSyncConfig adapter.callBids(s2sBidRequest, consentBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.us_privacy).is.equal('1YNN'); expect(requestBid.gdpr).is.equal(1); expect(requestBid.gdpr_consent).is.equal('abc123def'); expect(requestBid.bidders).to.contain('appnexus').and.to.have.lengthOf(1); expect(requestBid.account).is.equal('1'); }); }); it('adds device and app objects to request', function () { const _config = { s2sConfig: CONFIG, device: { ifa: '6D92078A-8246-4BA4-AE5B-76104861E7DC' }, app: { bundle: 'com.test.app' }, }; config.setConfig(_config); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.device).to.deep.equal({ ifa: '6D92078A-8246-4BA4-AE5B-76104861E7DC', w: window.innerWidth, h: window.innerHeight }); expect(requestBid.app).to.deep.equal({ bundle: 'com.test.app', publisher: { 'id': '1' } }); }); it('adds device and app objects to request for OpenRTB', function () { const s2sConfig = Object.assign({}, CONFIG, { endpoint: { p1Consent: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' } }); const _config = { s2sConfig: s2sConfig, device: { ifa: '6D92078A-8246-4BA4-AE5B-76104861E7DC' }, app: { bundle: 'com.test.app' }, }; config.setConfig(_config); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.device).to.deep.equal({ ifa: '6D92078A-8246-4BA4-AE5B-76104861E7DC', w: window.innerWidth, h: window.innerHeight }); expect(requestBid.app).to.deep.equal({ bundle: 'com.test.app', publisher: { 'id': '1' } }); }); it('adds debugging value from storedAuctionResponse to OpenRTB', function () { const _config = { s2sConfig: CONFIG, device: { ifa: '6D92078A-8246-4BA4-AE5B-76104861E7DC' }, app: { bundle: 'com.test.app' } }; config.setConfig(_config); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.imp).to.exist.and.to.be.a('array'); expect(requestBid.imp).to.have.lengthOf(1); expect(requestBid.imp[0].ext).to.exist.and.to.be.a('object'); expect(requestBid.imp[0].ext.prebid).to.exist.and.to.be.a('object'); expect(requestBid.imp[0].ext.prebid.storedauctionresponse).to.exist.and.to.be.a('object'); expect(requestBid.imp[0].ext.prebid.storedauctionresponse.id).to.equal('11111'); }); describe('price floors module', function () { function runTest(expectedFloor, expectedCur) { adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[requestCount].requestBody); expect(requestBid.imp[0].bidfloor).to.equal(expectedFloor); expect(requestBid.imp[0].bidfloorcur).to.equal(expectedCur); requestCount += 1; } let getFloorResponse, requestCount; beforeEach(function () { getFloorResponse = {}; requestCount = 0; }); it('should NOT pass bidfloor and bidfloorcur when getFloor not present or returns invalid response', function () { const _config = { s2sConfig: CONFIG, }; config.setConfig(_config); // if no get floor runTest(undefined, undefined); // if getFloor returns empty object BID_REQUESTS[0].bids[0].getFloor = () => getFloorResponse; sinon.spy(BID_REQUESTS[0].bids[0], 'getFloor'); runTest(undefined, undefined); // make sure getFloor was called expect( BID_REQUESTS[0].bids[0].getFloor.calledWith({ currency: 'USD', }) ).to.be.true; // if getFloor does not return number getFloorResponse = {currency: 'EUR', floor: 'not a number'}; runTest(undefined, undefined); // if getFloor does not return currency getFloorResponse = {floor: 1.1}; runTest(undefined, undefined); }); it('should correctly pass bidfloor and bidfloorcur', function () { const _config = { s2sConfig: CONFIG, }; config.setConfig(_config); BID_REQUESTS[0].bids[0].getFloor = () => getFloorResponse; sinon.spy(BID_REQUESTS[0].bids[0], 'getFloor'); // returns USD and string floor getFloorResponse = {currency: 'USD', floor: '1.23'}; runTest(1.23, 'USD'); // make sure getFloor was called expect( BID_REQUESTS[0].bids[0].getFloor.calledWith({ currency: 'USD', }) ).to.be.true; // returns non USD and number floor getFloorResponse = {currency: 'EUR', floor: 0.85}; runTest(0.85, 'EUR'); }); it('should correctly pass adServerCurrency when set to getFloor not default', function () { config.setConfig({ s2sConfig: CONFIG, currency: { adServerCurrency: 'JPY' }, }); // we have to start requestCount at 1 because a conversion rates fetch occurs when adServerCur is not USD! requestCount = 1; BID_REQUESTS[0].bids[0].getFloor = () => getFloorResponse; sinon.spy(BID_REQUESTS[0].bids[0], 'getFloor'); // returns USD and string floor getFloorResponse = {currency: 'JPY', floor: 97.2}; runTest(97.2, 'JPY'); // make sure getFloor was called with JPY expect( BID_REQUESTS[0].bids[0].getFloor.calledWith({ currency: 'JPY', }) ).to.be.true; }); }); it('adds device.w and device.h even if the config lacks a device object', function () { const _config = { s2sConfig: CONFIG, app: { bundle: 'com.test.app' }, }; config.setConfig(_config); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.device).to.deep.equal({ w: window.innerWidth, h: window.innerHeight }); expect(requestBid.app).to.deep.equal({ bundle: 'com.test.app', publisher: { 'id': '1' } }); }); it('adds native request for OpenRTB', function () { const _config = { s2sConfig: CONFIG }; config.setConfig(_config); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.imp[0].native).to.deep.equal({ request: JSON.stringify({ 'context': 1, 'plcmttype': 1, 'eventtrackers': [{ event: 1, methods: [1] }], 'assets': [ { 'required': 1, 'title': { 'len': 800 } }, { 'required': 1, 'img': { 'type': 3, 'w': 989, 'h': 742 } }, { 'required': 1, 'img': { 'type': 1, 'wmin': 10, 'hmin': 10, 'ext': { 'aspectratios': ['1:1'] } } }, { 'required': 1, 'data': { 'type': 1 } } ] }), ver: '1.2' }); }); it('adds site if app is not present', function () { const _config = { s2sConfig: CONFIG, site: { publisher: { id: '1234', domain: 'test.com' }, content: { language: 'en' } } }; config.setConfig(_config); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.site).to.exist.and.to.be.a('object'); expect(requestBid.site.publisher).to.exist.and.to.be.a('object'); expect(requestBid.site.publisher.id).to.exist.and.to.be.a('string'); expect(requestBid.site.publisher.domain).to.exist.and.to.be.a('string'); expect(requestBid.site.page).to.exist.and.to.be.a('string'); expect(requestBid.site.content).to.exist.and.to.be.a('object'); expect(requestBid.site.content.language).to.exist.and.to.be.a('string'); expect(requestBid.site).to.deep.equal({ publisher: { id: '1234', domain: 'test.com' }, content: { language: 'en' }, page: 'http://mytestpage.com' }); }); it('adds appnexus aliases to request', function () { config.setConfig({ s2sConfig: CONFIG }); const aliasBidder = { bidder: 'brealtime', params: { placementId: '123456' } }; const request = utils.deepClone(REQUEST); request.ad_units[0].bids = [aliasBidder]; adapter.callBids(request, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.ext).to.haveOwnProperty('prebid'); expect(requestBid.ext.prebid).to.deep.include({ aliases: { brealtime: 'appnexus' }, auctiontimestamp: 1510852447530, targeting: { includebidderkeys: false, includewinners: true } }); }); it('adds dynamic aliases to request', function () { config.setConfig({ s2sConfig: CONFIG }); const alias = 'foobar'; const aliasBidder = { bidder: alias, params: { placementId: '123456' } }; const request = utils.deepClone(REQUEST); request.ad_units[0].bids = [aliasBidder]; // TODO: stub this $$PREBID_GLOBAL$$.aliasBidder('appnexus', alias); adapter.callBids(request, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.ext).to.haveOwnProperty('prebid'); expect(requestBid.ext.prebid).to.deep.include({ aliases: { [alias]: 'appnexus' }, auctiontimestamp: 1510852447530, targeting: { includebidderkeys: false, includewinners: true } }); }); it('skips pbs alias when skipPbsAliasing is enabled in adapter', function() { const s2sConfig = Object.assign({}, CONFIG, { endpoint: { p1Consent: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' } }); config.setConfig({ s2sConfig: s2sConfig }); const aliasBidder = { bidder: 'mediafuse', params: { aid: 123 } }; const request = utils.deepClone(REQUEST); request.ad_units[0].bids = [aliasBidder]; adapter.callBids(request, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.ext).to.deep.equal({ prebid: { auctiontimestamp: 1510852447530, targeting: { includebidderkeys: false, includewinners: true }, channel: { name: 'pbjs', version: 'v$prebid.version$' } } }); }); it('skips dynamic aliases to request when skipPbsAliasing enabled', function () { const s2sConfig = Object.assign({}, CONFIG, { endpoint: { p1Consent: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' } }); config.setConfig({ s2sConfig: s2sConfig }); const alias = 'foobar_1'; const aliasBidder = { bidder: alias, params: { aid: 123456 } }; const request = utils.deepClone(REQUEST); request.ad_units[0].bids = [aliasBidder]; // TODO: stub this $$PREBID_GLOBAL$$.aliasBidder('appnexus', alias, { skipPbsAliasing: true }); adapter.callBids(request, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.ext).to.deep.equal({ prebid: { auctiontimestamp: 1510852447530, targeting: { includebidderkeys: false, includewinners: true }, channel: { name: 'pbjs', version: 'v$prebid.version$' } } }); }); it('converts appnexus params to expected format for PBS', function () { const s2sConfig = Object.assign({}, CONFIG, { endpoint: { p1Consent: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' } }); config.setConfig({ s2sConfig: s2sConfig }); const myRequest = utils.deepClone(REQUEST); myRequest.ad_units[0].bids[0].params.usePaymentRule = true; myRequest.ad_units[0].bids[0].params.keywords = { foo: ['bar', 'baz'], fizz: ['buzz'] }; adapter.callBids(myRequest, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.imp[0].ext.appnexus).to.exist; expect(requestBid.imp[0].ext.appnexus.placement_id).to.exist.and.to.equal(10433394); expect(requestBid.imp[0].ext.appnexus.use_pmt_rule).to.exist.and.to.be.true; expect(requestBid.imp[0].ext.appnexus.member).to.exist; expect(requestBid.imp[0].ext.appnexus.keywords).to.exist.and.to.deep.equal([{ key: 'foo', value: ['bar', 'baz'] }, { key: 'fizz', value: ['buzz'] }]); }); it('adds limit to the cookie_sync request if userSyncLimit is greater than 0', function () { let cookieSyncConfig = utils.deepClone(CONFIG); cookieSyncConfig.syncEndpoint = { p1Consent: 'https://prebid.adnxs.com/pbs/v1/cookie_sync' }; cookieSyncConfig.userSyncLimit = 1; const s2sBidRequest = utils.deepClone(REQUEST); s2sBidRequest.s2sConfig = cookieSyncConfig; config.setConfig({ s2sConfig: cookieSyncConfig }); let bidRequest = utils.deepClone(BID_REQUESTS); adapter.callBids(s2sBidRequest, bidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.bidders).to.contain('appnexus').and.to.have.lengthOf(1); expect(requestBid.account).is.equal('1'); expect(requestBid.limit).is.equal(1); }); it('does not add limit to cooke_sync request if userSyncLimit is missing or 0', function () { let cookieSyncConfig = utils.deepClone(CONFIG); cookieSyncConfig.syncEndpoint = { p1Consent: 'https://prebid.adnxs.com/pbs/v1/cookie_sync' }; config.setConfig({ s2sConfig: cookieSyncConfig }); const s2sBidRequest = utils.deepClone(REQUEST); s2sBidRequest.s2sConfig = cookieSyncConfig; let bidRequest = utils.deepClone(BID_REQUESTS); adapter.callBids(s2sBidRequest, bidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.bidders).to.contain('appnexus').and.to.have.lengthOf(1); expect(requestBid.account).is.equal('1'); expect(requestBid.limit).is.undefined; cookieSyncConfig.userSyncLimit = 0; config.resetConfig(); config.setConfig({ s2sConfig: cookieSyncConfig }); const s2sBidRequest2 = utils.deepClone(REQUEST); s2sBidRequest2.s2sConfig = cookieSyncConfig; bidRequest = utils.deepClone(BID_REQUESTS); adapter.callBids(s2sBidRequest2, bidRequest, addBidResponse, done, ajax); requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.bidders).to.contain('appnexus').and.to.have.lengthOf(1); expect(requestBid.account).is.equal('1'); expect(requestBid.limit).is.undefined; }); it('adds s2sConfig adapterOptions to request for ORTB', function () { const s2sConfig = Object.assign({}, CONFIG, { adapterOptions: { appnexus: { key: 'value' } } }); const _config = { s2sConfig: s2sConfig, device: { ifa: '6D92078A-8246-4BA4-AE5B-76104861E7DC' }, app: { bundle: 'com.test.app' }, }; const s2sBidRequest = utils.deepClone(REQUEST); s2sBidRequest.s2sConfig = s2sConfig; config.setConfig(_config); adapter.callBids(s2sBidRequest, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.imp[0].ext.appnexus).to.haveOwnProperty('key'); expect(requestBid.imp[0].ext.appnexus.key).to.be.equal('value') }); describe('config site value is added to the oRTB request', function () { const s2sConfig = Object.assign({}, CONFIG, { adapterOptions: { appnexus: { key: 'value' } } }); const device = { ua: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36', ip: '75.97.0.47' }; const s2sBidRequest = utils.deepClone(REQUEST); s2sBidRequest.s2sConfig = s2sConfig; it('and overrides publisher and page', function () { config.setConfig({ s2sConfig: s2sConfig, site: { domain: 'nytimes.com', page: 'http://www.nytimes.com', publisher: { id: '2' } }, device: device }); adapter.callBids(s2sBidRequest, BID_REQUESTS, addBidResponse, done, ajax); const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.site).to.exist.and.to.be.a('object'); expect(requestBid.site.domain).to.equal('nytimes.com'); expect(requestBid.site.page).to.equal('http://www.nytimes.com'); expect(requestBid.site.publisher).to.exist.and.to.be.a('object'); expect(requestBid.site.publisher.id).to.equal('2'); }); it('and merges domain and page with the config site value', function () { config.setConfig({ s2sConfig: s2sConfig, site: { foo: 'bar' },