diff --git a/modules/bidglassBidAdapter.js b/modules/bidglassBidAdapter.js index c0b5bddd5f7..43762162ace 100644 --- a/modules/bidglassBidAdapter.js +++ b/modules/bidglassBidAdapter.js @@ -5,7 +5,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest - * @typedef {import('../src/adapters/bidderFactory.js').validBidRequests} validBidRequests + * @typedef {import('../src/adapters/bidderFactory.js').ServerRequest} ServerRequest * @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse */ @@ -26,9 +26,9 @@ export const spec = { /** * Make a server request from the list of BidRequests. * - * @param {validBidRequests} validBidRequests an array of bids + * @param {BidRequest[]} validBidRequests an array of bids * @param {BidderRequest} bidderRequest request by bidder - * @return ServerRequest Info describing the request to the server. + * @return {ServerRequest} Info describing the request to the server. */ buildRequests: function(validBidRequests, bidderRequest) { /* @@ -102,12 +102,31 @@ export const spec = { }); }); - // Stuff to send: page URL + // Consent data + const gdprConsentObj = bidderRequest && bidderRequest.gdprConsent; + const gppConsentObj = bidderRequest && bidderRequest.gppConsent; + const gppApplicableSections = gppConsentObj && gppConsentObj.applicableSections; + const ortb2Regs = bidderRequest && bidderRequest.ortb2 && bidderRequest.ortb2.regs; + const ortb2Gpp = ortb2Regs && ortb2Regs.gpp; + + // Build bid request data to be sent to ad server const bidReq = { reqId: getUniqueIdentifierStr(), imps: imps, ref: getReferer(), - ori: getOrigins() + ori: getOrigins(), + + // GDPR applies? numeric boolean + gdprApplies: (gdprConsentObj && gdprConsentObj.gdprApplies) ? 1 : '', + // IAB TCF consent string + gdprConsent: (gdprConsentObj && gdprConsentObj.consentString) || '', + + // IAB GPP consent string + gppString: (gppConsentObj && gppConsentObj.gppString) || ortb2Gpp || '', + // GPP Applicable Section IDs + gppSid: (isArray(gppApplicableSections) && gppApplicableSections.length) + ? gppApplicableSections.join(',') + : ((ortb2Gpp && ortb2Regs.gpp_sid) || '') }; let url = 'https://bid.glass/ad/hb.php?' + @@ -128,10 +147,12 @@ export const spec = { * Unpack the response from the server into a list of bids. * * @param {ServerResponse} serverResponse A successful response from the server. + * @param {ServerRequest} serverRequest The original server request for this bid * @return {Bid[]} An array of bids which were nested inside the server. */ - interpretResponse: function(serverResponse) { + interpretResponse: function(serverResponse, serverRequest) { const bidResponses = []; + const bidReq = JSON.parse(serverRequest.data); _each(serverResponse.body.bidResponses, function(serverBid) { const bidResponse = { @@ -145,7 +166,19 @@ export const spec = { mediaType: serverBid.mediaType || 'banner', netRevenue: true, ttl: serverBid.ttl || 10, - ad: serverBid.ad, + // Replace the &replaceme placeholder in the returned ', 'cpm': '0.01', 'creativeId': '-1', 'width': '300', @@ -86,14 +95,14 @@ describe('Bid Glass Adapter', function () { 'mediaType': 'banner', 'netRevenue': true, 'ttl': 10, - 'ad': '', + 'ad': '', 'meta': { 'advertiserDomains': ['https://example.com'] } }]; - let result = spec.interpretResponse(response); - expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0])); + let result = spec.interpretResponse(serverResponse, serverRequest); + expect(result[0]).to.deep.equal(expectedResponse[0]); }); it('handles empty bid response', function () { @@ -102,7 +111,7 @@ describe('Bid Glass Adapter', function () { 'bidResponses': [] } }; - let result = spec.interpretResponse(response); + let result = spec.interpretResponse(response, serverRequest); expect(result.length).to.equal(0); }); }); diff --git a/test/spec/modules/conversantAnalyticsAdapter_spec.js b/test/spec/modules/conversantAnalyticsAdapter_spec.js deleted file mode 100644 index f46de31b19c..00000000000 --- a/test/spec/modules/conversantAnalyticsAdapter_spec.js +++ /dev/null @@ -1,1113 +0,0 @@ -import sinon from 'sinon'; -import { expect } from 'chai'; -import { default as conversantAnalytics, CNVR_CONSTANTS, cnvrHelper } from 'modules/conversantAnalyticsAdapter'; -import * as utils from 'src/utils.js'; -import * as prebidGlobal from 'src/prebidGlobal'; -import { server } from '../../mocks/xhr.js'; - -import {EVENTS} from 'src/constants.js' - -const events = require('src/events'); - -describe('Conversant analytics adapter tests', function() { - let sandbox; // sinon sandbox to make restoring all stubbed objects easier - let clock; // clock stub from sinon to mock our cache cleanup interval - let logInfoStub; - - const PREBID_VERSION = '$prebid.version$'; - const SITE_ID = 108060; - - let requests; - const DATESTAMP = Date.now(); - - const VALID_CONFIGURATION = { - options: { - site_id: SITE_ID, - send_error_data: true - } - }; - - const VALID_ALWAYS_SAMPLE_CONFIG = { - options: { - site_id: SITE_ID, - cnvr_sampling: 1, - send_error_data: true - } - }; - - beforeEach(function () { - requests = server.requests; - sandbox = sinon.sandbox.create(); - sandbox.stub(events, 'getEvents').returns([]); // need to stub this otherwise unwanted events seem to get fired during testing - const getGlobalStub = { - version: PREBID_VERSION, - getUserIds: function() { // userIdTargeting.js init() gets called on AUCTION_END so we need to mock this function. - return {}; - } - }; - sandbox.stub(prebidGlobal, 'getGlobal').returns(getGlobalStub); // getGlobal does not seem to be available in testing so need to mock it - clock = sandbox.useFakeTimers(DATESTAMP); // to use sinon fake timers they MUST be created before the interval/timeout is created in the code you are testing. - - logInfoStub = sandbox.stub(utils, 'logInfo');/* .callsFake((arg, arg1, arg2) => { //debugging stuff - console.log(arg); - if (arg1) console.log(arg1); - if (arg2) console.log(arg2); - }); */ - - conversantAnalytics.enableAnalytics(VALID_ALWAYS_SAMPLE_CONFIG); - }); - - afterEach(function () { - sandbox.restore(); - conversantAnalytics.disableAnalytics(); - }); - - describe('Initialization Tests', function() { - it('should log error if site id is not passed', function() { - sandbox.stub(utils, 'logError'); - conversantAnalytics.disableAnalytics(); - conversantAnalytics.enableAnalytics(); - expect(utils.logError.calledWith(CNVR_CONSTANTS.LOG_PREFIX + 'siteId is required.')).to.be.true; - }); - - it('should not log error if valid config is passed', function() { - sandbox.stub(utils, 'logError'); - - conversantAnalytics.enableAnalytics(VALID_CONFIGURATION); - expect(utils.logError.called).to.equal(false); - expect(utils.logInfo.called).to.equal(true); - expect( - utils.logInfo.calledWith( - CNVR_CONSTANTS.LOG_PREFIX + 'Conversant sample rate set to ' + CNVR_CONSTANTS.DEFAULT_SAMPLE_RATE - ) - ).to.be.true; - expect( - utils.logInfo.calledWith( - CNVR_CONSTANTS.LOG_PREFIX + 'Global sample rate set to 1' - ) - ).to.be.true; - }); - - it('should sample when sampling set to 1', function() { - sandbox.stub(utils, 'logError'); - conversantAnalytics.enableAnalytics(VALID_ALWAYS_SAMPLE_CONFIG); - expect(utils.logError.called).to.equal(false); - expect(cnvrHelper.doSample).to.equal(true); - }); - - it('should NOT sample when sampling set to 0', function() { - sandbox.stub(utils, 'logError'); - const NEVER_SAMPLE_CONFIG = utils.deepClone(VALID_ALWAYS_SAMPLE_CONFIG); - NEVER_SAMPLE_CONFIG.options.cnvr_sampling = 0; - conversantAnalytics.disableAnalytics(); - conversantAnalytics.enableAnalytics(NEVER_SAMPLE_CONFIG); - expect(utils.logError.called).to.equal(false); - expect(cnvrHelper.doSample).to.equal(false); - }); - }); - - describe('Helper Function Tests', function() { - it('should cleanup up cache objects', function() { - conversantAnalytics.enableAnalytics(VALID_CONFIGURATION); - - cnvrHelper.adIdLookup.keep = { timeReceived: DATESTAMP + 1 }; - cnvrHelper.adIdLookup.delete = { timeReceived: DATESTAMP - CNVR_CONSTANTS.MAX_MILLISECONDS_IN_CACHE }; - - cnvrHelper.timeoutCache.keep = { timeReceived: DATESTAMP + 1 }; - cnvrHelper.timeoutCache.delete = { timeReceived: DATESTAMP - CNVR_CONSTANTS.MAX_MILLISECONDS_IN_CACHE }; - - cnvrHelper.auctionIdTimestampCache.keep = { timeReceived: DATESTAMP + 1 }; - cnvrHelper.auctionIdTimestampCache.delete = { timeReceived: DATESTAMP - CNVR_CONSTANTS.MAX_MILLISECONDS_IN_CACHE }; - - cnvrHelper.bidderErrorCache.keep = { timeReceived: DATESTAMP + 1, errors: [] }; - cnvrHelper.bidderErrorCache.delete = { timeReceived: DATESTAMP - CNVR_CONSTANTS.MAX_MILLISECONDS_IN_CACHE, errors: [] }; - - expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(2); - expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(2); - expect(Object.keys(cnvrHelper.auctionIdTimestampCache)).to.have.lengthOf(2); - expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(2); - - clock.tick(CNVR_CONSTANTS.CACHE_CLEANUP_TIME_IN_MILLIS); - expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); - expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(1); - expect(Object.keys(cnvrHelper.auctionIdTimestampCache)).to.have.lengthOf(1); - expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(1); - - conversantAnalytics.disableAnalytics(); - - // After disable we should cleanup the cache - expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); - expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(0); - expect(Object.keys(cnvrHelper.auctionIdTimestampCache)).to.have.lengthOf(0); - expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(0); - }); - - it('createBid() should return correct object', function() { - const EVENT_CODE = 1; - const TIME = 2; - const bid = cnvrHelper.createBid(EVENT_CODE, 2); - expect(bid).to.deep.equal({ eventCodes: [EVENT_CODE], timeToRespond: TIME }); - }); - - it('createAdUnit() should return correct object', function() { - const adUnit = cnvrHelper.createAdUnit(); - expect(adUnit).to.deep.equal({ - sizes: [], - mediaTypes: [], - bids: {} - }); - }); - - it('createAdSize() should return correct object', function() { - let adSize = cnvrHelper.createAdSize(1, 2); - expect(adSize).to.deep.equal({ w: 1, h: 2 }); - - adSize = cnvrHelper.createAdSize(); - expect(adSize).to.deep.equal({ w: -1, h: -1 }); - - adSize = cnvrHelper.createAdSize('foo', 'bar'); - expect(adSize).to.deep.equal({ w: -1, h: -1 }); - }); - - it('getLookupKey() should return correct object', function() { - let key = cnvrHelper.getLookupKey(undefined, undefined, undefined); - expect(key).to.equal('undefined-undefined-undefined'); - - key = cnvrHelper.getLookupKey('foo', 'bar', 'baz'); - expect(key).to.equal('foo-bar-baz'); - }); - - it('createPayload() should return correct object', function() { - const REQUEST_TYPE = 'foo'; - const AUCTION_ID = '124 abc'; - const myDate = Date.now(); - conversantAnalytics.enableAnalytics(VALID_ALWAYS_SAMPLE_CONFIG); - - const payload = cnvrHelper.createPayload(REQUEST_TYPE, AUCTION_ID, myDate); - expect(payload).to.deep.equal({ - bidderErrors: [], - cnvrSampleRate: 1, - globalSampleRate: 1, - requestType: REQUEST_TYPE, - auction: { - auctionId: AUCTION_ID, - auctionTimestamp: myDate, - sid: VALID_ALWAYS_SAMPLE_CONFIG.options.site_id, - preBidVersion: PREBID_VERSION - }, - adUnits: {} - }); - }); - - it('keyExistsAndIsObject() should return correct data', function() { - const data = { - a: [], - b: 1, - c: 'foo', - d: function () { return true; }, - e: {} - }; - expect(cnvrHelper.keyExistsAndIsObject(data, 'foobar')).to.be.false; - expect(cnvrHelper.keyExistsAndIsObject(data, 'a')).to.be.false; - expect(cnvrHelper.keyExistsAndIsObject(data, 'b')).to.be.false; - expect(cnvrHelper.keyExistsAndIsObject(data, 'c')).to.be.false; - expect(cnvrHelper.keyExistsAndIsObject(data, 'd')).to.be.false; - expect(cnvrHelper.keyExistsAndIsObject(data, 'e')).to.be.true; - }); - - it('deduplicateArray() should return correct data', function () { - const arrayOfObjects = [{ w: 1, h: 2 }, { w: 2, h: 3 }, { w: 1, h: 2 }]; - const array = [3, 2, 1, 1, 2, 3]; - let empty; - const notArray = 3; - const emptyArray = []; - - expect(JSON.stringify(cnvrHelper.deduplicateArray(array))).to.equal(JSON.stringify([3, 2, 1])); - expect(JSON.stringify(cnvrHelper.deduplicateArray(arrayOfObjects))).to.equal(JSON.stringify([{ w: 1, h: 2 }, { w: 2, h: 3 }])); - expect(JSON.stringify(cnvrHelper.deduplicateArray(emptyArray))).to.equal(JSON.stringify([])); - expect(cnvrHelper.deduplicateArray(empty)).to.be.undefined; - expect(cnvrHelper.deduplicateArray(notArray)).to.equal(notArray); - }); - - it('getSampleRate() should return correct data', function () { - const obj = { - sampling: 1, - cnvr_sampling: 0.5, - too_big: 1.2, - too_small: -1, - string: 'foo', - object: {}, - } - const DEFAULT_VAL = 0.11; - expect(cnvrHelper.getSampleRate(obj, 'sampling', DEFAULT_VAL)).to.equal(1); - expect(cnvrHelper.getSampleRate(obj, 'cnvr_sampling', DEFAULT_VAL)).to.equal(0.5); - expect(cnvrHelper.getSampleRate(obj, 'too_big', DEFAULT_VAL)).to.equal(DEFAULT_VAL); - expect(cnvrHelper.getSampleRate(obj, 'string', DEFAULT_VAL)).to.equal(DEFAULT_VAL); - expect(cnvrHelper.getSampleRate(obj, 'object', DEFAULT_VAL)).to.equal(DEFAULT_VAL); - expect(cnvrHelper.getSampleRate(obj, 'not_a_key', DEFAULT_VAL)).to.equal(DEFAULT_VAL); - expect(cnvrHelper.getSampleRate(obj, 'too_small', DEFAULT_VAL)).to.equal(0); - }); - - it('getPageUrl() should return correct data', function() { - const url = cnvrHelper.getPageUrl(); - expect(url.length).to.be.above(1); - }); - - it('sendErrorData() should send data via ajax', function() { - const error = { - stack: 'foobar', - message: 'foobar message' - }; - const eventType = 'fooType'; - - expect(requests).to.have.lengthOf(0); - cnvrHelper.sendErrorData(eventType, error); - expect(requests).to.have.lengthOf(1); - - expect(requests[0].url).to.contain('cvx/event/prebidanalyticerrors'); - const data = JSON.parse(requests[0].requestBody); - expect(data.event).to.be.equal(eventType); - expect(data.siteId).to.be.equal(SITE_ID); - expect(data.message).to.not.be.undefined; - expect(data.prebidVersion).to.not.be.undefined; - expect(data.userAgent).to.not.be.undefined; - expect(data.url).to.not.be.undefined; - }); - - it('Should not send data when error logging disabled', function() { - const error = { - stack: 'foobar', - message: 'foobar message' - }; - const eventType = 'fooType'; - - conversantAnalytics.disableAnalytics(); - conversantAnalytics.enableAnalytics({ - options: { - site_id: SITE_ID, - cnvr_sampling: 1, - send_error_data: false - } - }); - expect(cnvrHelper.doSendErrorData).to.be.false; - - expect(requests).to.have.lengthOf(0); - cnvrHelper.sendErrorData(eventType, error); - expect(requests).to.have.lengthOf(0); - - conversantAnalytics.disableAnalytics(); - conversantAnalytics.enableAnalytics({ - options: { - site_id: SITE_ID, - cnvr_sampling: 1, - send_error_data: 0 - } - }); - expect(cnvrHelper.doSendErrorData).to.be.false; - - expect(requests).to.have.lengthOf(0); - cnvrHelper.sendErrorData(eventType, error); - expect(requests).to.have.lengthOf(0); - }); - }); - - describe('Bid Timeout Event Tests', function() { - const BID_TIMEOUT_PAYLOAD = [{ - bidId: '80882409358b8a8', - bidder: 'conversant', - adUnitCode: 'MedRect', - auctionId: 'afbd6e0b-e45b-46ab-87bf-c0bac0cb8881' - }, { - bidId: '9da4c107a6f24c8', - bidder: 'conversant', - adUnitCode: 'Leaderboard', - auctionId: 'afbd6e0b-e45b-46ab-87bf-c0bac0cb8881' - }]; - - it('should put both items in timeout cache', function() { - expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(0); - events.emit(EVENTS.BID_TIMEOUT, BID_TIMEOUT_PAYLOAD); - expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(2); - - BID_TIMEOUT_PAYLOAD.forEach(timeoutBid => { - const key = cnvrHelper.getLookupKey(timeoutBid.auctionId, timeoutBid.adUnitCode, timeoutBid.bidder); - expect(cnvrHelper.timeoutCache[key].timeReceived).to.not.be.undefined; - }); - expect(requests).to.have.lengthOf(0); - }); - }); - - describe('Render Failed Tests', function() { - const RENDER_FAILED_PAYLOAD = { - reason: 'reason', - message: 'value', - adId: '57e03aeafd83a68' - }; - - const RENDER_FAILED_PAYLOAD_NO_ADID = { - reason: 'reason', - message: 'value' - }; - - it('should empty adIdLookup and send data', function() { - cnvrHelper.adIdLookup[RENDER_FAILED_PAYLOAD.adId] = { - bidderCode: 'bidderCode', - adUnitCode: 'adUnitCode', - auctionId: 'auctionId', - timeReceived: Date.now() - }; - - expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); - events.emit(EVENTS.AD_RENDER_FAILED, RENDER_FAILED_PAYLOAD); - expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); // object should be removed - expect(requests).to.have.lengthOf(1); - const data = JSON.parse(requests[0].requestBody); - - expect(data.auction.auctionId).to.equal('auctionId'); - expect(data.auction.preBidVersion).to.equal(PREBID_VERSION); - expect(data.auction.sid).to.equal(SITE_ID); - expect(data.adUnits.adUnitCode.bids.bidderCode[0].eventCodes.includes(CNVR_CONSTANTS.RENDER_FAILED)).to.be.true; - expect(data.adUnits.adUnitCode.bids.bidderCode[0].message).to.have.lengthOf.above(0); - }); - - it('should not send data if no adId', function() { - cnvrHelper.adIdLookup[RENDER_FAILED_PAYLOAD.adId] = { - bidderCode: 'bidderCode', - adUnitCode: 'adUnitCode', - auctionId: 'auctionId', - timeReceived: Date.now() - }; - - expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); - events.emit(EVENTS.AD_RENDER_FAILED, RENDER_FAILED_PAYLOAD_NO_ADID); - expect(requests).to.have.lengthOf(1); - expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); // same object in cache as before... no change - expect(cnvrHelper.adIdLookup[RENDER_FAILED_PAYLOAD.adId]).to.not.be.undefined; - - expect(requests[0].url).to.contain('cvx/event/prebidanalyticerrors'); - const data = JSON.parse(requests[0].requestBody); - expect(data.event).to.be.equal(EVENTS.AD_RENDER_FAILED); - expect(data.siteId).to.be.equal(SITE_ID); - expect(data.message).to.not.be.undefined; - expect(data.prebidVersion).to.not.be.undefined; - expect(data.userAgent).to.not.be.undefined; - expect(data.url).to.not.be.undefined; - }); - - it('should not send data if bad data in lookup', function() { - cnvrHelper.adIdLookup[RENDER_FAILED_PAYLOAD.adId] = { - bidderCode: 'bidderCode', - auctionId: 'auctionId', - timeReceived: Date.now() - }; - expect(requests).to.have.lengthOf(0); - expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); - events.emit(EVENTS.AD_RENDER_FAILED, RENDER_FAILED_PAYLOAD); - expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); // object should be removed but no call made to send data - expect(requests).to.have.lengthOf(1); - - expect(requests[0].url).to.contain('cvx/event/prebidanalyticerrors'); - const data = JSON.parse(requests[0].requestBody); - expect(data.event).to.be.equal(EVENTS.AD_RENDER_FAILED); - expect(data.siteId).to.be.equal(SITE_ID); - expect(data.message).to.not.be.undefined; - expect(data.prebidVersion).to.not.be.undefined; - expect(data.userAgent).to.not.be.undefined; - expect(data.url).to.not.be.undefined; - }); - }); - - describe('Bid Won Tests', function() { - const GOOD_BID_WON_ARGS = { - bidderCode: 'conversant', - width: 300, - height: 250, - statusMessage: 'Bid available', - adId: '57e03aeafd83a68', - requestId: '2c2a5485a076898', - mediaType: 'banner', - source: 'client', - currency: 'USD', - cpm: 4, - creativeId: '29123_55016759', - ttl: 300, - netRevenue: true, - ad: '', - originalCpm: 0.04, - originalCurrency: 'USD', - auctionId: '85e1bf44-4035-4e24-bd3c-b1ba367fe294', - responseTimestamp: 1583851418626, - requestTimestamp: 1583851418292, - bidder: 'conversant', - adUnitCode: 'div-gpt-ad-1460505748561-0', - timeToRespond: 334, - pbLg: '4.00', - pbMg: '4.00', - pbHg: '4.00', - pbAg: '4.00', - pbDg: '4.00', - pbCg: '', - size: '300x250', - adserverTargeting: { - hb_bidder: 'conversant', - hb_adid: '57e03aeafd83a68', - hb_pb: '4.00', - hb_size: '300x250', - hb_source: 'client', - hb_format: 'banner' - }, - status: 'rendered', - params: [ - { - site_id: '108060' - } - ] - }; - - // no adUnitCode, auctionId or bidderCode will cause a failure - const BAD_BID_WON_ARGS = { - bidderCode: 'conversant', - width: 300, - height: 250, - statusMessage: 'Bid available', - adId: '57e03aeafd83a68', - requestId: '2c2a5485a076898', - mediaType: 'banner', - source: 'client', - currency: 'USD', - cpm: 4, - originalCpm: 0.04, - originalCurrency: 'USD', - bidder: 'conversant', - adUnitCode: 'div-gpt-ad-1460505748561-0', - size: '300x250', - status: 'rendered', - params: [ - { - site_id: '108060' - } - ] - }; - - it('should not send data or put a record in adIdLookup when bad data provided', function() { - expect(requests).to.have.lengthOf(0); - expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); - events.emit(EVENTS.BID_WON, BAD_BID_WON_ARGS); - expect(requests).to.have.lengthOf(1); - expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); - - // check for error event - expect(requests[0].url).to.contain('cvx/event/prebidanalyticerrors'); - const data = JSON.parse(requests[0].requestBody); - expect(data.event).to.be.equal(EVENTS.BID_WON); - expect(data.siteId).to.be.equal(SITE_ID); - expect(data.message).to.not.be.undefined; - expect(data.prebidVersion).to.not.be.undefined; - expect(data.userAgent).to.not.be.undefined; - expect(data.url).to.not.be.undefined; - }); - - it('should send data and put a record in adIdLookup', function() { - const myAuctionStart = Date.now(); - cnvrHelper.auctionIdTimestampCache[GOOD_BID_WON_ARGS.auctionId] = { timeReceived: myAuctionStart }; - - expect(requests).to.have.lengthOf(0); - expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(0); - events.emit(EVENTS.BID_WON, GOOD_BID_WON_ARGS); - - // Check that adIdLookup was set correctly - expect(Object.keys(cnvrHelper.adIdLookup)).to.have.lengthOf(1); - expect(cnvrHelper.adIdLookup[GOOD_BID_WON_ARGS.adId].auctionId).to.equal(GOOD_BID_WON_ARGS.auctionId); - expect(cnvrHelper.adIdLookup[GOOD_BID_WON_ARGS.adId].adUnitCode).to.equal(GOOD_BID_WON_ARGS.adUnitCode); - expect(cnvrHelper.adIdLookup[GOOD_BID_WON_ARGS.adId].bidderCode).to.equal(GOOD_BID_WON_ARGS.bidderCode); - expect(cnvrHelper.adIdLookup[GOOD_BID_WON_ARGS.adId].timeReceived).to.not.be.undefined; - - expect(requests).to.have.lengthOf(1); - const data = JSON.parse(requests[0].requestBody); - expect(data.requestType).to.equal('bid_won'); - expect(data.auction.auctionId).to.equal(GOOD_BID_WON_ARGS.auctionId); - expect(data.auction.preBidVersion).to.equal(PREBID_VERSION); - expect(data.auction.sid).to.equal(VALID_ALWAYS_SAMPLE_CONFIG.options.site_id); - expect(data.auction.auctionTimestamp).to.equal(myAuctionStart); - - expect(typeof data.adUnits).to.equal('object'); - expect(Object.keys(data.adUnits)).to.have.lengthOf(1); - - expect(Object.keys(data.adUnits[GOOD_BID_WON_ARGS.adUnitCode].bids)).to.have.lengthOf(1); - expect(data.adUnits[GOOD_BID_WON_ARGS.adUnitCode].bids[GOOD_BID_WON_ARGS.bidderCode][0].eventCodes.includes(CNVR_CONSTANTS.WIN)).to.be.true; - expect(data.adUnits[GOOD_BID_WON_ARGS.adUnitCode].bids[GOOD_BID_WON_ARGS.bidderCode][0].cpm).to.equal(GOOD_BID_WON_ARGS.cpm); - expect(data.adUnits[GOOD_BID_WON_ARGS.adUnitCode].bids[GOOD_BID_WON_ARGS.bidderCode][0].originalCpm).to.equal(GOOD_BID_WON_ARGS.originalCpm); - expect(data.adUnits[GOOD_BID_WON_ARGS.adUnitCode].bids[GOOD_BID_WON_ARGS.bidderCode][0].currency).to.equal(GOOD_BID_WON_ARGS.currency); - expect(data.adUnits[GOOD_BID_WON_ARGS.adUnitCode].bids[GOOD_BID_WON_ARGS.bidderCode][0].timeToRespond).to.equal(GOOD_BID_WON_ARGS.timeToRespond); - expect(data.adUnits[GOOD_BID_WON_ARGS.adUnitCode].bids[GOOD_BID_WON_ARGS.bidderCode][0].adSize.w).to.equal(GOOD_BID_WON_ARGS.width); - expect(data.adUnits[GOOD_BID_WON_ARGS.adUnitCode].bids[GOOD_BID_WON_ARGS.bidderCode][0].adSize.h).to.equal(GOOD_BID_WON_ARGS.height); - }); - }); - - describe('Auction End Tests', function() { - const AUCTION_END_PAYLOAD = { - auctionId: '85e1bf44-4035-4e24-bd3c-b1ba367fe294', - timestamp: 1583851418288, - auctionEnd: 1583851418628, - auctionStatus: 'completed', - adUnits: [ - { - code: 'div-gpt-ad-1460505748561-0', - mediaTypes: { - banner: { - sizes: [ - [300, 250], - [100, 200] - ] - } - }, - bids: [ - { - bidder: 'appnexus', - params: { - placementId: 13144370 - } - }, - { - bidder: 'conversant', - params: { - site_id: '108060' - } - } - ], - sizes: [ - [300, 250], - [100, 200] - ], - transactionId: '5fa8a7d7-2a73-4d1c-b73a-ff9f5b53ba17' - }, - { - code: 'div-gpt-ad-1460505748561-0', - mediaTypes: { - banner: { - sizes: [ - [300, 250], - [100, 200] - ] - }, - video: { - playerSize: [ - [300, 250], - [600, 400] - ] - } - }, - sizes: [ - [300, 250], - [100, 200], - [600, 400] - ], - bids: [ - { - bidder: 'appnexus', - params: { - placementId: 13144370 - } - }, - { - bidder: 'conversant', - params: { - site_id: '108060' - } - } - ], - transactionId: '5fa8a7d7-2a73-4d1c-b73a-ff9f5b53ba18' - }, - { - code: 'div-gpt-ad-1460505748561-1', - mediaTypes: { - native: { - type: 'image' - } - }, - bids: [ - { - bidder: 'appnexus', - params: { - placementId: 13144371 - } - } - ], - transactionId: '5fa8a7d7-2a73-4d1c-b73a-ff9f5b53ba10' - } - ], - adUnitCodes: [ - 'div-gpt-ad-1460505748561-0' - ], - bidderRequests: [ - { - bidderCode: 'conversant', - auctionId: '85e1bf44-4035-4e24-bd3c-b1ba367fe294', - bidderRequestId: '13f16db358d4c58', - bids: [ - { - bidder: 'conversant', - params: { - site_id: '108060' - }, - mediaTypes: { - banner: { - sizes: [ - [ - 300, - 250 - ] - ] - } - }, - adUnitCode: 'div-gpt-ad-1460505748561-0', - transactionId: '5fa8a7d7-2a73-4d1c-b73a-ff9f5b53ba17', - sizes: [ - [ - 300, - 250 - ] - ], - bidId: '2c2a5485a076898', - bidderRequestId: '13f16db358d4c58', - auctionId: '85e1bf44-4035-4e24-bd3c-b1ba367fe294', - src: 'client', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0 - } - ], - auctionStart: 1583851418288, - timeout: 3000, - refererInfo: { - referer: 'http://localhost:9999/integrationExamples/gpt/hello_analytics1.html', - reachedTop: true, - numIframes: 0, - stack: [ - 'http://localhost:9999/integrationExamples/gpt/hello_analytics1.html' - ] - }, - start: 1583851418292 - }, - { - bidderCode: 'appnexus', - auctionId: '85e1bf44-4035-4e24-bd3c-b1ba367fe294', - bidderRequestId: '3e8179f67f31b98', - bids: [ - { - bidder: 'appnexus', - params: { - placementId: 13144370 - }, - mediaTypes: { - banner: { - sizes: [ - [ - 300, - 250 - ] - ] - } - }, - adUnitCode: 'div-gpt-ad-1460505748561-0', - transactionId: '5fa8a7d7-2a73-4d1c-b73a-ff9f5b53ba17', - sizes: [ - [ - 300, - 250 - ] - ], - bidId: '40a1d3ac6b79668', - bidderRequestId: '3e8179f67f31b98', - auctionId: '85e1bf44-4035-4e24-bd3c-b1ba367fe294', - src: 'client', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0 - }, - { - bidder: 'appnexus', - params: { - placementId: 13144370 - }, - mediaTypes: { - native: { - type: 'image' - } - }, - adUnitCode: 'div-gpt-ad-1460505748561-1', - transactionId: '5fa8a7d7-2a73-4d1c-b73a-ff9f5b53ba17', - sizes: [], - bidId: '40a1d3ac6b79668', - bidderRequestId: '3e8179f67f31b98', - auctionId: '85e1bf44-4035-4e24-bd3c-b1ba367fe294', - src: 'client', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0 - } - ], - auctionStart: 1583851418288, - timeout: 3000, - refererInfo: { - referer: 'http://localhost:9999/integrationExamples/gpt/hello_analytics1.html', - reachedTop: true, - numIframes: 0, - stack: [ - 'http://localhost:9999/integrationExamples/gpt/hello_analytics1.html' - ] - }, - start: 1583851418295 - } - ], - noBids: [ - { - bidder: 'appnexus', - params: { - placementId: 13144370 - }, - mediaTypes: { - banner: { - sizes: [ - [ - 300, - 250 - ] - ] - } - }, - adUnitCode: 'div-gpt-ad-1460505748561-0', - transactionId: '5fa8a7d7-2a73-4d1c-b73a-ff9f5b53ba17', - sizes: [ - [ - 300, - 250 - ] - ], - bidId: '40a1d3ac6b79668', - bidderRequestId: '3e8179f67f31b98', - auctionId: '85e1bf44-4035-4e24-bd3c-b1ba367fe294', - src: 'client', - bidRequestsCount: 1, - bidderRequestsCount: 1, - bidderWinsCount: 0 - } - ], - bidsReceived: [ - { - bidderCode: 'conversant', - width: 300, - height: 250, - statusMessage: 'Bid available', - adId: '57e03aeafd83a68', - requestId: '2c2a5485a076898', - mediaType: 'banner', - source: 'client', - currency: 'USD', - cpm: 4, - creativeId: '29123_55016759', - ttl: 300, - netRevenue: true, - ad: '', - originalCpm: 0.04, - originalCurrency: 'USD', - auctionId: '85e1bf44-4035-4e24-bd3c-b1ba367fe294', - responseTimestamp: 1583851418626, - requestTimestamp: 1583851418292, - bidder: 'conversant', - adUnitCode: 'div-gpt-ad-1460505748561-0', - timeToRespond: 334, - pbLg: '4.00', - pbMg: '4.00', - pbHg: '4.00', - pbAg: '4.00', - pbDg: '4.00', - pbCg: '', - size: '300x250', - adserverTargeting: { - hb_bidder: 'conversant', - hb_adid: '57e03aeafd83a68', - hb_pb: '4.00', - hb_size: '300x250', - hb_source: 'client', - hb_format: 'banner' - } - }, { - bidderCode: 'conversant', - height: 100, - statusMessage: 'Bid available', - width: 200, - adId: '57e03aeafd83a68', - requestId: '2c2a5485a076898', - mediaType: 'banner', - source: 'client', - currency: 'USD', - cpm: 4, - creativeId: '29123_55016759', - ttl: 300, - netRevenue: true, - ad: '', - originalCpm: 0.04, - originalCurrency: 'USD', - auctionId: '85e1bf44-4035-4e24-bd3c-b1ba367fe294', - responseTimestamp: 1583851418626, - requestTimestamp: 1583851418292, - bidder: 'conversant', - adUnitCode: 'div-gpt-ad-1460505748561-0', - timeToRespond: 334, - pbLg: '4.00', - pbMg: '4.00', - pbHg: '4.00', - pbAg: '4.00', - pbDg: '4.00', - pbCg: '', - size: '100x200', - adserverTargeting: { - hb_bidder: 'conversant', - hb_adid: '57e03aeafd83a68', - hb_pb: '4.00', - hb_size: '300x250', - hb_source: 'client', - hb_format: 'banner' - } - }, { - bidderCode: 'appnexus', - statusMessage: 'Bid available', - adId: '57e03aeafd83a68', - requestId: '2c2a5485a076898', - mediaType: 'native', - source: 'client', - currency: 'USD', - cpm: 4, - creativeId: '29123_55016759', - ttl: 300, - netRevenue: true, - ad: '', - originalCpm: 0.04, - originalCurrency: 'USD', - auctionId: '85e1bf44-4035-4e24-bd3c-b1ba367fe294', - responseTimestamp: 1583851418626, - requestTimestamp: 1583851418292, - bidder: 'appnexus', - adUnitCode: 'div-gpt-ad-1460505748561-1', - timeToRespond: 334, - pbLg: '4.00', - pbMg: '4.00', - pbHg: '4.00', - pbAg: '4.00', - pbDg: '4.00', - pbCg: '', - adserverTargeting: { - hb_bidder: 'appnexus', - hb_adid: '57e03aeafd83a68', - hb_pb: '4.00', - hb_size: '300x250', - hb_source: 'client', - hb_format: 'banner' - } - } - ], - winningBids: [], - timeout: 3000 - }; - - it('should not do anything when auction id doesnt exist', function() { - sandbox.stub(utils, 'logError'); - - const BAD_ARGS = JSON.parse(JSON.stringify(AUCTION_END_PAYLOAD)); - delete BAD_ARGS.auctionId; - expect(requests).to.have.lengthOf(0); - events.emit(EVENTS.AUCTION_END, BAD_ARGS); - expect(requests).to.have.lengthOf(1); - - // check for error event - expect(requests[0].url).to.contain('cvx/event/prebidanalyticerrors'); - const data = JSON.parse(requests[0].requestBody); - expect(data.event).to.be.equal(EVENTS.AUCTION_END); - expect(data.siteId).to.be.equal(SITE_ID); - expect(data.message).to.not.be.undefined; - expect(data.prebidVersion).to.not.be.undefined; - expect(data.userAgent).to.not.be.undefined; - expect(data.url).to.not.be.undefined; - }); - - it('should send the expected data', function() { - sandbox.stub(utils, 'logError'); - sandbox.stub(utils, 'logWarn'); - - expect(requests).to.have.lengthOf(0); - const AUCTION_ID = AUCTION_END_PAYLOAD.auctionId; - const AD_UNIT_CODE = AUCTION_END_PAYLOAD.adUnits[0].code; - const AD_UNIT_CODE_NATIVE = AUCTION_END_PAYLOAD.adUnits[2].code; - const timeoutKey = cnvrHelper.getLookupKey(AUCTION_ID, AD_UNIT_CODE, 'appnexus'); - const URL = 'some url'; - cnvrHelper.bidderErrorCache[AUCTION_ID] = { - errors: [{ - status: 500, - message: 'error msg', - bidderCode: 'bidderCode', - url: URL, - }, { - status: 501, - message: 'error msg1', - bidderCode: 'bidderCode1', - url: URL, - }], - timeReceived: Date.now() - }; - cnvrHelper.timeoutCache[timeoutKey] = { timeReceived: Date.now() }; - expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(1); - expect(utils.logError.called).to.equal(false); - expect(Object.keys(cnvrHelper.auctionIdTimestampCache)).to.have.lengthOf(0); - expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(1); - - events.emit(EVENTS.AUCTION_END, AUCTION_END_PAYLOAD); - expect(utils.logError.called).to.equal(false); - expect(requests).to.have.lengthOf(1); - expect(Object.keys(cnvrHelper.timeoutCache)).to.have.lengthOf(0); - expect(Object.keys(cnvrHelper.auctionIdTimestampCache)).to.have.lengthOf(1); - expect(cnvrHelper.auctionIdTimestampCache[AUCTION_END_PAYLOAD.auctionId].timeReceived).to.equal(AUCTION_END_PAYLOAD.timestamp); - - const data = JSON.parse(requests[0].requestBody); - expect(data.requestType).to.equal('auction_end'); - expect(data.auction.auctionId).to.equal(AUCTION_ID); - expect(data.auction.preBidVersion).to.equal(PREBID_VERSION); - expect(data.auction.sid).to.equal(VALID_ALWAYS_SAMPLE_CONFIG.options.site_id); - - expect(Object.keys(data.adUnits)).to.have.lengthOf(2); - - expect(data.adUnits[AD_UNIT_CODE].sizes).to.have.lengthOf(3); - expect(data.adUnits[AD_UNIT_CODE].sizes[0].w).to.equal(300); - expect(data.adUnits[AD_UNIT_CODE].sizes[0].h).to.equal(250); - expect(data.adUnits[AD_UNIT_CODE].sizes[1].w).to.equal(100); - expect(data.adUnits[AD_UNIT_CODE].sizes[1].h).to.equal(200); - expect(data.adUnits[AD_UNIT_CODE].sizes[2].w).to.equal(600); - expect(data.adUnits[AD_UNIT_CODE].sizes[2].h).to.equal(400); - - expect(data.adUnits[AD_UNIT_CODE].mediaTypes).to.have.lengthOf(2); - expect(data.adUnits[AD_UNIT_CODE].mediaTypes[0]).to.equal('banner'); - expect(data.adUnits[AD_UNIT_CODE].mediaTypes[1]).to.equal('video'); - - expect(data.adUnits[AD_UNIT_CODE_NATIVE].mediaTypes).to.have.lengthOf(1); - expect(data.adUnits[AD_UNIT_CODE_NATIVE].mediaTypes[0]).to.equal('native'); - expect(data.adUnits[AD_UNIT_CODE_NATIVE].sizes).to.have.lengthOf(0); - - expect(Object.keys(data.adUnits[AD_UNIT_CODE].bids)).to.have.lengthOf(2); - const cnvrBidsArray = data.adUnits[AD_UNIT_CODE].bids.conversant; - // testing multiple bids from same bidder - expect(cnvrBidsArray).to.have.lengthOf(2); - expect(cnvrBidsArray[0].eventCodes.includes(CNVR_CONSTANTS.BID)).to.be.true; - expect(cnvrBidsArray[0].cpm).to.equal(4); - expect(cnvrBidsArray[0].originalCpm).to.equal(0.04); - expect(cnvrBidsArray[0].currency).to.equal('USD'); - expect(cnvrBidsArray[0].timeToRespond).to.equal(334); - expect(cnvrBidsArray[0].adSize.w).to.equal(300); - expect(cnvrBidsArray[0].adSize.h).to.equal(250); - expect(cnvrBidsArray[0].mediaType).to.equal('banner'); - // 2nd bid different size - expect(cnvrBidsArray[1].eventCodes.includes(CNVR_CONSTANTS.BID)).to.be.true; - expect(cnvrBidsArray[1].cpm).to.equal(4); - expect(cnvrBidsArray[1].originalCpm).to.equal(0.04); - expect(cnvrBidsArray[1].currency).to.equal('USD'); - expect(cnvrBidsArray[1].timeToRespond).to.equal(334); - expect(cnvrBidsArray[1].adSize.w).to.equal(200); - expect(cnvrBidsArray[1].adSize.h).to.equal(100); - expect(cnvrBidsArray[1].mediaType).to.equal('banner'); - - const apnBidsArray = data.adUnits[AD_UNIT_CODE].bids.appnexus; - expect(apnBidsArray).to.have.lengthOf(2); - let apnBid = apnBidsArray[0]; - expect(apnBid.originalCpm).to.be.undefined; - expect(apnBid.eventCodes.includes(CNVR_CONSTANTS.TIMEOUT)).to.be.true; - expect(apnBid.cpm).to.be.undefined; - expect(apnBid.currency).to.be.undefined; - expect(apnBid.timeToRespond).to.equal(3000); - expect(apnBid.adSize).to.be.undefined; - expect(apnBid.mediaType).to.be.undefined; - apnBid = apnBidsArray[1]; - expect(apnBid.originalCpm).to.be.undefined; - expect(apnBid.eventCodes.includes(CNVR_CONSTANTS.NO_BID)).to.be.true; - expect(apnBid.cpm).to.be.undefined; - expect(apnBid.currency).to.be.undefined; - expect(apnBid.timeToRespond).to.equal(0); - expect(apnBid.adSize).to.be.undefined; - expect(apnBid.mediaType).to.be.undefined; - - expect(Object.keys(data.adUnits[AD_UNIT_CODE_NATIVE].bids)).to.have.lengthOf(1); - const apnNativeBidsArray = data.adUnits[AD_UNIT_CODE_NATIVE].bids.appnexus; - expect(apnNativeBidsArray).to.have.lengthOf(1); - const apnNativeBid = apnNativeBidsArray[0]; - expect(apnNativeBid.eventCodes.includes(CNVR_CONSTANTS.BID)).to.be.true; - expect(apnNativeBid.cpm).to.equal(4); - expect(apnNativeBid.originalCpm).to.equal(0.04); - expect(apnNativeBid.currency).to.equal('USD'); - expect(apnNativeBid.timeToRespond).to.equal(334); - expect(apnNativeBid.adSize.w).to.be.undefined; - expect(apnNativeBid.adSize.h).to.be.undefined; - expect(apnNativeBid.mediaType).to.equal('native'); - - expect(Object.keys(data.bidderErrors)).to.have.lengthOf(2); - expect(data.bidderErrors[0].status).to.equal(500); - expect(data.bidderErrors[0].url).to.equal(URL); - expect(data.bidderErrors[0].message).to.not.be.undefined; - expect(data.bidderErrors[0].bidderCode).to.not.be.undefined; - - expect(data.bidderErrors[1].status).to.equal(501); - expect(data.bidderErrors[1].url).to.equal(URL); - expect(data.bidderErrors[1].message).to.not.be.undefined; - expect(data.bidderErrors[1].bidderCode).to.not.be.undefined; - - expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(0); - }); - }); - - describe('Bidder Error Tests', function() { - // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest - const XHR_ERROR_MOCK = { - status: 500, - statusText: 'Internal Server Error' - }; - - // https://docs.prebid.org/dev-docs/bidder-adaptor.html#registering-on-bidder-error - const MOCK_BID_REQUEST = { - auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - auctionStart: 1579746300522, - bidderCode: 'myBidderCode', - bidderRequestId: '15246a574e859f', - bids: [{}], - gdprConsent: { consentString: 'BOtmiBKOtmiBKABABAENAFAAAAACeAAA', vendorData: {}, gdprApplies: true }, - refererInfo: { - canonicalUrl: null, - page: 'http://mypage.org?pbjs_debug=true', - domain: 'mypage.org', - ref: null, - numIframes: 0, - reachedTop: true, - isAmp: false, - stack: ['http://mypage.org?pbjs_debug=true'] - } - }; - - it('should record error when bidder_error called', function() { - const warnStub = sandbox.stub(utils, 'logWarn'); - expect(requests).to.have.lengthOf(0); - expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(0); - expect(warnStub.calledOnce).to.be.false; - - events.emit(EVENTS.BIDDER_ERROR, { error: XHR_ERROR_MOCK, bidderRequest: MOCK_BID_REQUEST }); - expect(Object.keys(cnvrHelper.bidderErrorCache)).to.have.lengthOf(1); - expect(warnStub.calledOnce).to.be.true; - - let errorObj = cnvrHelper.bidderErrorCache[MOCK_BID_REQUEST.auctionId]; - expect(errorObj.errors).to.have.lengthOf(1); - expect(errorObj.errors[0].status).to.equal(XHR_ERROR_MOCK.status); - expect(errorObj.errors[0].message).to.equal(XHR_ERROR_MOCK.statusText); - expect(errorObj.errors[0].bidderCode).to.equal(MOCK_BID_REQUEST.bidderCode); - expect(errorObj.errors[0].url).to.not.be.undefined; - - events.emit(EVENTS.BIDDER_ERROR, { error: XHR_ERROR_MOCK, bidderRequest: MOCK_BID_REQUEST }); - errorObj = cnvrHelper.bidderErrorCache[MOCK_BID_REQUEST.auctionId]; - expect(errorObj.errors).to.have.lengthOf(2); - }); - }); -}); diff --git a/test/spec/modules/limelightDigitalBidAdapter_spec.js b/test/spec/modules/limelightDigitalBidAdapter_spec.js index b13beb26d28..c84586e9064 100644 --- a/test/spec/modules/limelightDigitalBidAdapter_spec.js +++ b/test/spec/modules/limelightDigitalBidAdapter_spec.js @@ -516,10 +516,10 @@ describe('limelightDigitalAdapter', function () { { headers: { get: function (header) { - if (header === 'X-PLL-UserSync-Image') { + if (header === 'x-pll-usersync-image') { return 'https://tracker-lm.ortb.net/sync'; } - if (header === 'X-PLL-UserSync-Iframe') { + if (header === 'x-pll-usersync-iframe') { return 'https://tracker-lm.ortb.net/sync.html'; } } @@ -543,10 +543,10 @@ describe('limelightDigitalAdapter', function () { { headers: { get: function (header) { - if (header === 'X-PLL-UserSync-Image') { + if (header === 'x-pll-usersync-image') { return 'https://tracker-1.ortb.net/sync'; } - if (header === 'X-PLL-UserSync-Iframe') { + if (header === 'x-pll-usersync-iframe') { return 'https://tracker-1.ortb.net/sync.html'; } } @@ -578,10 +578,10 @@ describe('limelightDigitalAdapter', function () { { headers: { get: function (header) { - if (header === 'X-PLL-UserSync-Image') { + if (header === 'x-pll-usersync-image') { return 'https://tracker-lm.ortb.net/sync'; } - if (header === 'X-PLL-UserSync-Iframe') { + if (header === 'x-pll-usersync-iframe') { return 'https://tracker-lm.ortb.net/sync.html'; } } @@ -605,10 +605,10 @@ describe('limelightDigitalAdapter', function () { { headers: { get: function (header) { - if (header === 'X-PLL-UserSync-Image') { + if (header === 'x-pll-usersync-image') { return 'https://tracker-1.ortb.net/sync'; } - if (header === 'X-PLL-UserSync-Iframe') { + if (header === 'x-pll-usersync-iframe') { return 'https://tracker-1.ortb.net/sync.html'; } } @@ -618,10 +618,10 @@ describe('limelightDigitalAdapter', function () { { headers: { get: function (header) { - if (header === 'X-PLL-UserSync-Image') { + if (header === 'x-pll-usersync-image') { return 'https://tracker-2.ortb.net/sync'; } - if (header === 'X-PLL-UserSync-Iframe') { + if (header === 'x-pll-usersync-iframe') { return 'https://tracker-2.ortb.net/sync.html'; } } @@ -649,10 +649,10 @@ describe('limelightDigitalAdapter', function () { { headers: { get: function (header) { - if (header === 'X-PLL-UserSync-Image') { + if (header === 'x-pll-usersync-image') { return 'https://tracker-lm.ortb.net/sync'; } - if (header === 'X-PLL-UserSync-Iframe') { + if (header === 'x-pll-usersync-iframe') { return 'https://tracker-lm.ortb.net/sync.html'; } } @@ -662,10 +662,10 @@ describe('limelightDigitalAdapter', function () { { headers: { get: function (header) { - if (header === 'X-PLL-UserSync-Image') { + if (header === 'x-pll-usersync-image') { return 'https://tracker-lm.ortb.net/sync'; } - if (header === 'X-PLL-UserSync-Iframe') { + if (header === 'x-pll-usersync-iframe') { return 'https://tracker-lm.ortb.net/sync.html'; } } @@ -689,10 +689,10 @@ describe('limelightDigitalAdapter', function () { { headers: { get: function (header) { - if (header === 'X-PLL-UserSync-Image') { + if (header === 'x-pll-usersync-image') { return 'https://tracker-lm.ortb.net/sync'; } - if (header === 'X-PLL-UserSync-Iframe') { + if (header === 'x-pll-usersync-iframe') { return 'https://tracker-lm.ortb.net/sync.html'; } } diff --git a/test/spec/modules/mediaforceBidAdapter_spec.js b/test/spec/modules/mediaforceBidAdapter_spec.js index 61e5678b03b..ee88f0a21b8 100644 --- a/test/spec/modules/mediaforceBidAdapter_spec.js +++ b/test/spec/modules/mediaforceBidAdapter_spec.js @@ -1,7 +1,7 @@ import {assert} from 'chai'; import {spec} from 'modules/mediaforceBidAdapter.js'; import * as utils from '../../../src/utils.js'; -import {BANNER, NATIVE} from '../../../src/mediaTypes.js'; +import {BANNER, NATIVE, VIDEO} from '../../../src/mediaTypes.js'; describe('mediaforce bid adapter', function () { let sandbox; @@ -76,7 +76,7 @@ describe('mediaforce bid adapter', function () { sizes: [300, 250], }, sponsoredBy: { - required: true + required: false } }, mediaTypes: { @@ -93,8 +93,20 @@ describe('mediaforce bid adapter', function () { sizes: [300, 250], }, sponsoredBy: { - required: true + required: false } + }, + video: { + playerSize: [[640, 480]], + mimes: ['video/mp4'], + minduration: 5, + maxduration: 30, + protocols: [2, 3], + linearity: 1, + skip: 1, + skipmin: 5, + skipafter: 10, + api: [1, 2] } }, ortb2Imp: { @@ -104,6 +116,82 @@ describe('mediaforce bid adapter', function () { } }; + const refererInfo = { + ref: 'https://www.prebid.org', + reachedTop: true, + stack: [ + 'https://www.prebid.org/page.html', + 'https://www.prebid.org/iframe1.html', + ] + }; + + const dnt = utils.getDNT() ? 1 : 0; + const secure = window.location.protocol === 'https:' ? 1 : 0; + const pageUrl = window.location.href; + const timeout = 1500; + const auctionId = '210a474e-88f0-4646-837f-4253b7cf14fb'; + + const expectedData = { + // id property removed as it is specific for each request generated + tmax: timeout, + ext: { + mediaforce: { + hb_key: auctionId + } + }, + site: { + id: defaultBid.params.publisher_id, + publisher: {id: defaultBid.params.publisher_id}, + ref: encodeURIComponent(refererInfo.ref), + page: pageUrl, + }, + device: { + ua: navigator.userAgent, + dnt: dnt, + js: 1, + language: language, + }, + imp: [{ + tagid: defaultBid.params.placement_id, + secure: secure, + bidfloor: 0, + ext: { + mediaforce: { + transactionId: defaultBid.ortb2Imp.ext.tid, + } + }, + banner: {w: 300, h: 250}, + native: { + ver: '1.2', + request: { + assets: [ + {id: 1, title: {len: 800}, required: 1}, + {id: 3, img: {w: 300, h: 250, type: 3}, required: 1}, + {id: 5, data: {type: 1}, required: 0} + ], + context: 1, + plcmttype: 1, + ver: '1.2' + } + }, + video: { + mimes: ['video/mp4'], + minduration: 5, + maxduration: 30, + protocols: [2, 3], + w: 640, + h: 480, + startdelay: 0, + linearity: 1, + skip: 1, + skipmin: 5, + skipafter: 10, + playbackmethod: [1], + api: [1, 2] + } + }], + }; + const multiBid = [ { publisher_id: 'pub123', @@ -139,30 +227,72 @@ describe('mediaforce bid adapter', function () { } }); - const refererInfo = { - ref: 'https://www.prebid.org', - reachedTop: true, - stack: [ - 'https://www.prebid.org/page.html', - 'https://www.prebid.org/iframe1.html', - ] - }; - const requestUrl = `${baseUrl}/header_bid`; - const dnt = utils.getDNT() ? 1 : 0; - const secure = window.location.protocol === 'https:' ? 1 : 0; - const pageUrl = window.location.href; - const timeout = 1500; it('should return undefined if no validBidRequests passed', function () { assert.equal(spec.buildRequests([]), undefined); }); + it('should not stop on unsupported mediaType', function () { + const bid = utils.deepClone(defaultBid); + bid.mediaTypes.audio = { size: [300, 250] }; + + let bidRequests = [bid]; + let bidderRequest = { + bids: bidRequests, + refererInfo: refererInfo, + timeout: timeout, + auctionId: auctionId, + }; + + let [request] = spec.buildRequests(bidRequests, bidderRequest); + let data = JSON.parse(request.data); + + let expectedDataCopy = utils.deepClone(expectedData); + assert.exists(data.id); + + expectedDataCopy.id = data.id + assert.deepEqual(data, expectedDataCopy); + }); + it('should return proper request url: no refererInfo', function () { let [request] = spec.buildRequests([defaultBid]); assert.equal(request.url, requestUrl); }); + it('should use test endpoint when is_test is true', function () { + const bid = utils.deepClone(defaultBid); + bid.params.is_test = true; + + const [request] = spec.buildRequests([bid]); + assert.equal(request.url, `${baseUrl}/header_bid?debug_key=abcdefghijklmnop`); + }); + + it('should include aspect_ratios in native asset', function () { + const bid = utils.deepClone(defaultBid); + const aspect_ratios = [{ + min_width: 100, + ratio_width: 4, + ratio_height: 3 + }] + bid.mediaTypes.native.image.aspect_ratios = aspect_ratios; + bid.nativeParams.image.aspect_ratios = aspect_ratios; + + const [request] = spec.buildRequests([bid]); + const nativeAsset = JSON.parse(request.data).imp[0].native.request.assets.find(a => a.id === 3); + assert.equal(nativeAsset.img.wmin, 100); + assert.equal(nativeAsset.img.hmin, 75); + }); + + it('should include placement in video object if provided', function () { + const bid = utils.deepClone(defaultBid); + bid.mediaTypes.video.placement = 2; + + const [request] = spec.buildRequests([bid]); + const video = JSON.parse(request.data).imp[0].video; + assert.equal(video.placement, 2, 'placement should be passed into video object'); + }); + it('should return proper banner imp', function () { let bid = utils.deepClone(defaultBid); bid.params.bidfloor = 0; @@ -172,63 +302,19 @@ describe('mediaforce bid adapter', function () { bids: bidRequests, refererInfo: refererInfo, timeout: timeout, - auctionId: '210a474e-88f0-4646-837f-4253b7cf14fb' + auctionId: auctionId, }; let [request] = spec.buildRequests(bidRequests, bidderRequest); let data = JSON.parse(request.data); - assert.deepEqual(data, { - id: data.id, - tmax: timeout, - ext: { - mediaforce: { - hb_key: bidderRequest.auctionId - } - }, - site: { - id: bid.params.publisher_id, - publisher: {id: bid.params.publisher_id}, - ref: encodeURIComponent(refererInfo.ref), - page: pageUrl, - }, - device: { - ua: navigator.userAgent, - dnt: dnt, - js: 1, - language: language, - }, - imp: [{ - tagid: bid.params.placement_id, - secure: secure, - bidfloor: bid.params.bidfloor, - ext: { - mediaforce: { - transactionId: bid.ortb2Imp.ext.tid, - } - }, - banner: {w: 300, h: 250}, - native: { - ver: '1.2', - request: { - assets: [ - {id: 1, title: {len: 800}, required: 1}, - {id: 3, img: {w: 300, h: 250, type: 3}, required: 1}, - {id: 5, data: {type: 1}, required: 1} - ], - context: 1, - plcmttype: 1, - ver: '1.2' - } - }, - }], - }); - assert.deepEqual(request, { - method: 'POST', - url: requestUrl, - data: '{"id":"' + data.id + '","site":{"page":"' + pageUrl + '","ref":"https%3A%2F%2Fwww.prebid.org","id":"pub123","publisher":{"id":"pub123"}},"device":{"ua":"' + navigator.userAgent + '","js":1,"dnt":' + dnt + ',"language":"' + language + '"},"ext":{"mediaforce":{"hb_key":"210a474e-88f0-4646-837f-4253b7cf14fb"}},"tmax":1500,"imp":[{"tagid":"202","secure":' + secure + ',"bidfloor":0,"ext":{"mediaforce":{"transactionId":"d45dd707-a418-42ec-b8a7-b70a6c6fab0b"}},"banner":{"w":300,"h":250},"native":{"ver":"1.2","request":{"assets":[{"required":1,"id":1,"title":{"len":800}},{"required":1,"id":3,"img":{"type":3,"w":300,"h":250}},{"required":1,"id":5,"data":{"type":1}}],"context":1,"plcmttype":1,"ver":"1.2"}}}]}', - }); + let expectedDataCopy = utils.deepClone(expectedData); + assert.exists(data.id); + + expectedDataCopy.id = data.id + expectedDataCopy.imp[0].bidfloor = bid.params.bidfloor + assert.deepEqual(data, expectedDataCopy); }); it('multiple sizes', function () { @@ -244,12 +330,22 @@ describe('mediaforce bid adapter', function () { assert.deepEqual(data.imp[0].banner, {w: 300, h: 600, format: [{w: 300, h: 250}]}); }); + it('should skip banner with empty sizes', function () { + const bid = utils.deepClone(defaultBid); + bid.mediaTypes.banner = { sizes: [] }; + + const [request] = spec.buildRequests([bid]); + const data = JSON.parse(request.data); + assert.notExists(data.imp[0].banner, 'Banner object should be omitted'); + }); + + it('should return proper requests for multiple imps', function () { let bidderRequest = { bids: multiBid, refererInfo: refererInfo, timeout: timeout, - auctionId: '210a474e-88f0-4646-837f-4253b7cf14fb' + auctionId: auctionId, }; let requests = spec.buildRequests(multiBid, bidderRequest); @@ -267,7 +363,7 @@ describe('mediaforce bid adapter', function () { tmax: timeout, ext: { mediaforce: { - hb_key: bidderRequest.auctionId + hb_key: auctionId } }, site: { @@ -323,7 +419,7 @@ describe('mediaforce bid adapter', function () { tmax: timeout, ext: { mediaforce: { - hb_key: bidderRequest.auctionId + hb_key: auctionId } }, site: { @@ -575,6 +671,50 @@ describe('mediaforce bid adapter', function () { }); }); + describe('interpretResponse() video', function () { + it('should interpret video response correctly', function () { + const vast = '...'; + + const bid = { + adid: '2_ssl', + adm: vast, + adomain: ["www3.thehealthyfat.com"], + burl: `${baseUrl}/burl/\${AUCTION_PRICE}`, + cat: ['IAB1-1'], + cid: '2_ssl', + crid: '2_ssl', + dealid: '3901521', + id: '65599d0a-42d2-446a-9d39-6086c1433ffe', + impid: '2b3c9d103723a7', + price: 5.5, + }; + + const response = { + body: { + seatbid: [{ bid: [bid] }], + cur: 'USD', + id: '620190c2-7eef-42fa-91e2-f5c7fbc2bdd3', + } + }; + + const [result] = spec.interpretResponse(response); + + assert.deepEqual(result, { + burl: bid.burl, + cpm: bid.price, + creativeId: bid.adid, + currency: response.body.cur, + dealId: bid.dealid, + mediaType: VIDEO, + meta: { advertiserDomains: bid.adomain }, + netRevenue: true, + requestId: bid.impid, + ttl: 300, + vastXml: vast, + }); + }); + }); + describe('onBidWon()', function () { beforeEach(function() { sinon.stub(utils, 'triggerPixel'); diff --git a/test/spec/modules/onetagBidAdapter_spec.js b/test/spec/modules/onetagBidAdapter_spec.js index a274b141fd6..ac78b2b9ed1 100644 --- a/test/spec/modules/onetagBidAdapter_spec.js +++ b/test/spec/modules/onetagBidAdapter_spec.js @@ -3,6 +3,8 @@ import { expect } from 'chai'; import { find } from 'src/polyfill.js'; import { BANNER, VIDEO, NATIVE } from 'src/mediaTypes.js'; import { INSTREAM, OUTSTREAM } from 'src/video.js'; +import { toOrtbNativeRequest } from 'src/native.js'; +import { hasTypeNative } from '../../../modules/onetagBidAdapter'; const NATIVE_SUFFIX = 'Ad'; @@ -44,6 +46,57 @@ describe('onetag', function () { }; } + function createNativeLegacyBid(bidRequest) { + let bid = bidRequest || createBid(); + bid.mediaTypes = bid.mediaTypes || {}; + bid.mediaTypes.native = { + adTemplate: "
\"##hb_native_brand##\"
##hb_native_brand##

##hb_native_title##

##hb_native_cta####hb_native_brand##
", + title: { + required: 1, + sendId: 1 + }, + body: { + required: 1, + sendId: 1 + }, + cta: { + required: 0, + sendId: 1 + }, + displayUrl: { + required: 0, + sendId: 1 + }, + icon: { + required: 0, + sendId: 1 + }, + image: { + required: 1, + sendId: 1 + }, + sponsoredBy: { + required: 1, + sendId: 1 + } + } + bid = addNativeParams(bid); + const ortbConversion = toOrtbNativeRequest(bid.nativeParams); + bid.mediaTypes.native = {}; + bid.mediaTypes.native.adTemplate = bid.nativeParams.adTemplate; + bid.mediaTypes.native.ortb = ortbConversion; + return bid; + } + + function addNativeParams(bidRequest) { + let bidParams = bidRequest.nativeParams || {}; + for (const property in bidRequest.mediaTypes.native) { + bidParams[property] = bidRequest.mediaTypes.native[property]; + } + bidRequest.nativeParams = bidParams; + return bidRequest; + } + function createNativeBid(bidRequest) { const bid = bidRequest || createBid(); bid.mediaTypes = bid.mediaTypes || {}; @@ -54,7 +107,7 @@ describe('onetag', function () { assets: [{ id: 1, required: 1, - title: { + title: { len: 140 } }, @@ -81,7 +134,7 @@ describe('onetag', function () { minduration: 5, maxduration: 30, protocols: [2, 3] - } + } }], eventtrackers: [{ event: 1, @@ -128,12 +181,13 @@ describe('onetag', function () { return createInstreamVideoBid(createBannerBid()); } - let bannerBid, instreamVideoBid, outstreamVideoBid, nativeBid; + let bannerBid, instreamVideoBid, outstreamVideoBid, nativeBid, nativeLegacyBid; beforeEach(() => { bannerBid = createBannerBid(); instreamVideoBid = createInstreamVideoBid(); outstreamVideoBid = createOutstreamVideoBid(); nativeBid = createNativeBid(); + nativeLegacyBid = createNativeLegacyBid(); }) describe('isBidRequestValid', function () { @@ -150,86 +204,94 @@ describe('onetag', function () { }); describe('banner bidRequest', function () { it('Should return false when the sizes array is empty', function () { - // TODO (dgirardi): this test used to pass because `bannerBid` was global state - // and other test code made it invalid for reasons other than sizes. - // cleaning up the setup code, it now (correctly) fails. - bannerBid.sizes = []; - // expect(spec.isBidRequestValid(bannerBid)).to.be.false; + bannerBid.mediaTypes.banner.sizes = []; + expect(spec.isBidRequestValid(bannerBid)).to.be.false; }); }); describe('native bidRequest', function () { it('Should return true when correct native bid is passed', function () { const nativeBid = createNativeBid(); - expect(spec.isBidRequestValid(nativeBid)).to.be.true; + const nativeLegacyBid = createNativeLegacyBid(); + expect(spec.isBidRequestValid(nativeBid)).to.be.true && expect(spec.isBidRequestValid(nativeLegacyBid)).to.be.true; }); it('Should return false when native is not an object', function () { const nativeBid = createNativeBid(); - nativeBid.mediaTypes.native = 30; - expect(spec.isBidRequestValid(nativeBid)).to.be.false; + const nativeLegacyBid = createNativeLegacyBid(); + nativeBid.mediaTypes.native = nativeLegacyBid.mediaTypes.native = 30; + expect(spec.isBidRequestValid(nativeBid)).to.be.false && expect(spec.isBidRequestValid(nativeLegacyBid)).to.be.false; }); - it('Should return false when native.ortb is not an object', function () { + it('Should return false when native.ortb if defined but it isn\'t an object', function () { const nativeBid = createNativeBid(); nativeBid.mediaTypes.native.ortb = 30 || 'string'; expect(spec.isBidRequestValid(nativeBid)).to.be.false; }); it('Should return false when native.ortb.assets is not an array', function () { const nativeBid = createNativeBid(); - nativeBid.mediaTypes.native.ortb.assets = 30; - expect(spec.isBidRequestValid(nativeBid)).to.be.false; + const nativeLegacyBid = createNativeLegacyBid(); + nativeBid.mediaTypes.native.ortb.assets = nativeLegacyBid.mediaTypes.native.ortb.assets = 30; + expect(spec.isBidRequestValid(nativeBid)).to.be.false && expect(spec.isBidRequestValid(nativeLegacyBid)).to.be.false; }); it('Should return false when native.ortb.assets is an empty array', function () { const nativeBid = createNativeBid(); - nativeBid.mediaTypes.native.ortb.assets = []; - expect(spec.isBidRequestValid(nativeBid)).to.be.false; + const nativeLegacyBid = createNativeLegacyBid(); + nativeBid.mediaTypes.native.ortb.assets = nativeLegacyBid.mediaTypes.native.ortb.assets = []; + expect(spec.isBidRequestValid(nativeBid)).to.be.false && expect(spec.isBidRequestValid(nativeLegacyBid)).to.be.false; }); it('Should return false when native.ortb.assets[i] doesnt have \'id\'', function () { const nativeBid = createNativeBid(); + const nativeLegacyBid = createNativeLegacyBid(); Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[0], 'id'); - expect(spec.isBidRequestValid(nativeBid)).to.be.false; + Reflect.deleteProperty(nativeLegacyBid.mediaTypes.native.ortb.assets[0], 'id'); + expect(spec.isBidRequestValid(nativeBid)).to.be.false && expect(spec.isBidRequestValid(nativeLegacyBid)).to.be.false; }); it('Should return false when native.ortb.assets[i] doesnt have any of \'title\', \'img\', \'data\' and \'video\' properties', function () { const nativeBid = createNativeBid(); - Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[0], 'title'); - expect(spec.isBidRequestValid(nativeBid)).to.be.false; + const nativeLegacyBid = createNativeLegacyBid(); + const titleIndex = nativeBid.mediaTypes.native.ortb.assets.findIndex(asset => asset.title); + const legacyTitleIndex = nativeLegacyBid.mediaTypes.native.ortb.assets.findIndex(asset => asset.title); + Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[titleIndex], 'title'); + Reflect.deleteProperty(nativeLegacyBid.mediaTypes.native.ortb.assets[legacyTitleIndex], 'title'); + expect(spec.isBidRequestValid(nativeBid)).to.be.false && expect(spec.isBidRequestValid(nativeLegacyBid)).to.be.false; }); it('Should return false when native.ortb.assets[i] have title, but doesnt have \'len\' property', function () { const nativeBid = createNativeBid(); - Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[0].title, 'len'); - expect(spec.isBidRequestValid(nativeBid)).to.be.false; - }); - it('Should return false when native.ortb.assets[i] is image but doesnt have \'wmin\' property', function () { - const nativeBid = createNativeBid(); - Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[1].img, 'wmin'); - expect(spec.isBidRequestValid(nativeBid)).to.be.false; - }); - it('Should return false when native.ortb.assets[i] is image but doesnt have \'hmin\' property', function () { - const nativeBid = createNativeBid(); - Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[1].img, 'hmin'); - expect(spec.isBidRequestValid(nativeBid)).to.be.false; + const nativeLegacyBid = createNativeLegacyBid(); + const titleIndex = nativeBid.mediaTypes.native.ortb.assets.findIndex(asset => asset.title); + const legacyTitleIndex = nativeLegacyBid.mediaTypes.native.ortb.assets.findIndex(asset => asset.title); + Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[titleIndex].title, 'len'); + Reflect.deleteProperty(nativeLegacyBid.mediaTypes.native.ortb.assets[legacyTitleIndex].title, 'len'); + expect(spec.isBidRequestValid(nativeBid)).to.be.false && expect(spec.isBidRequestValid(nativeLegacyBid)).to.be.false; }); it('Should return false when native.ortb.assets[i] is data but doesnt have \'type\' property', function () { const nativeBid = createNativeBid(); - Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[2].data, 'type'); - expect(spec.isBidRequestValid(nativeBid)).to.be.false; + const nativeLegacyBid = createNativeLegacyBid(); + const dataIndex = nativeBid.mediaTypes.native.ortb.assets.findIndex(asset => asset.data); + Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[dataIndex].data, 'type'); + Reflect.deleteProperty(nativeLegacyBid.mediaTypes.native.ortb.assets[dataIndex].data, 'type'); + expect(spec.isBidRequestValid(nativeBid)).to.be.false && expect(spec.isBidRequestValid(nativeLegacyBid)).to.be.false; }); it('Should return false when native.ortb.assets[i] is video but doesnt have \'mimes\' property', function () { const nativeBid = createNativeBid(); - Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[3].video, 'mimes'); + const videoIndex = nativeBid.mediaTypes.native.ortb.assets.findIndex(asset => asset.video); + Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[videoIndex].video, 'mimes'); expect(spec.isBidRequestValid(nativeBid)).to.be.false; }); it('Should return false when native.ortb.assets[i] is video but doesnt have \'minduration\' property', function () { const nativeBid = createNativeBid(); - Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[3].video, 'minduration'); + const videoIndex = nativeBid.mediaTypes.native.ortb.assets.findIndex(asset => asset.video); + Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[videoIndex].video, 'minduration'); expect(spec.isBidRequestValid(nativeBid)).to.be.false; }); it('Should return false when native.ortb.assets[i] is video but doesnt have \'maxduration\' property', function () { const nativeBid = createNativeBid(); - Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[3].video, 'maxduration'); + const videoIndex = nativeBid.mediaTypes.native.ortb.assets.findIndex(asset => asset.video); + Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[videoIndex].video, 'maxduration'); expect(spec.isBidRequestValid(nativeBid)).to.be.false; }); it('Should return false when native.ortb.assets[i] is video but doesnt have \'protocols\' property', function () { const nativeBid = createNativeBid(); - Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[3].video, 'protocols'); + const videoIndex = nativeBid.mediaTypes.native.ortb.assets.findIndex(asset => asset.video); + Reflect.deleteProperty(nativeBid.mediaTypes.native.ortb.assets[videoIndex].video, 'protocols'); expect(spec.isBidRequestValid(nativeBid)).to.be.false; }); it('Should return false when native.ortb.eventtrackers is not an array', function () { @@ -324,7 +386,7 @@ describe('onetag', function () { describe('buildRequests', function () { let serverRequest, data; before(() => { - serverRequest = spec.buildRequests([bannerBid, instreamVideoBid, nativeBid]); + serverRequest = spec.buildRequests([bannerBid, instreamVideoBid, nativeBid, nativeLegacyBid]); data = JSON.parse(serverRequest.data); }); @@ -387,6 +449,21 @@ describe('onetag', function () { 'type', 'priceFloors' ); + } else if (hasTypeNative(bid)) { + expect(bid).to.have.all.keys( + 'adUnitCode', + 'auctionId', + 'bidId', + 'bidderRequestId', + 'pubId', + 'ortb2Imp', + 'transactionId', + 'mediaTypeInfo', + 'sizes', + 'type', + 'priceFloors' + ) && + expect(bid.mediaTypeInfo).to.have.key('ortb'); } else if (isValid(BANNER, bid)) { expect(bid).to.have.all.keys( 'adUnitCode',