diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index ce4fdcc2431..61e518d306d 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -25,7 +25,6 @@ import {find} from '../src/polyfill.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {INSTREAM, OUTSTREAM} from '../src/video.js'; import {Renderer} from '../src/Renderer.js'; -import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; const BIDDER_CODE = 'ix'; const ALIAS_BIDDER_CODE = 'roundel'; @@ -100,93 +99,6 @@ const VIDEO_PARAMS_ALLOW_LIST = [ 'delivery', 'pos', 'companionad', 'api', 'companiontype', 'ext', 'playerSize', 'w', 'h' ]; -const NATIVE_ASSET_TYPES = { - TITLE: 100, - IMG: 200, - VIDEO: 300, - DATA: 400 -}; -const NATIVE_IMAGE_TYPES = { - ICON: 1, - MAIN: 3 -}; -const NATIVE_DATA_TYPES = { - SPONSORED: 1, - DESC: 2, - RATING: 3, - LIKES: 4, - DOWNLOADS: 5, - PRICE: 6, - SALEPRICE: 7, - PHONE: 8, - ADDRESS: 9, - DESC2: 10, - DISPLAYURL: 11, - CTATEXT: 12 -}; -const NATIVE_DATA_MAP = { - [NATIVE_DATA_TYPES.SPONSORED]: 'sponsoredBy', - [NATIVE_DATA_TYPES.DESC]: 'body', - [NATIVE_DATA_TYPES.RATING]: 'rating', - [NATIVE_DATA_TYPES.LIKES]: 'likes', - [NATIVE_DATA_TYPES.DOWNLOADS]: 'downloads', - [NATIVE_DATA_TYPES.PRICE]: 'price', - [NATIVE_DATA_TYPES.SALEPRICE]: 'salePrice', - [NATIVE_DATA_TYPES.PHONE]: 'phone', - [NATIVE_DATA_TYPES.ADDRESS]: 'address', - [NATIVE_DATA_TYPES.DESC2]: 'body2', - [NATIVE_DATA_TYPES.DISPLAYURL]: 'displayUrl', - [NATIVE_DATA_TYPES.CTATEXT]: 'cta' -}; -const NATIVE_ASSETS_MAP = { - 'title': { assetType: NATIVE_ASSET_TYPES.TITLE }, - 'icon': { assetType: NATIVE_ASSET_TYPES.IMG, subtype: NATIVE_IMAGE_TYPES.ICON }, - 'image': { assetType: NATIVE_ASSET_TYPES.IMG, subtype: NATIVE_IMAGE_TYPES.MAIN }, - 'sponsoredBy': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.SPONSORED }, - 'body': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.DESC }, - 'rating': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.RATING }, - 'likes': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.LIKES }, - 'downloads': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.DOWNLOADS }, - 'price': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.PRICE }, - 'salePrice': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.SALEPRICE }, - 'phone': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.PHONE }, - 'address': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.ADDRESS }, - 'body2': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.DESC2 }, - 'displayUrl': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.DISPLAYURL }, - 'cta': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.CTATEXT }, - 'video': { assetType: NATIVE_ASSET_TYPES.VIDEO } -}; -const NATIVE_ALLOWED_PROPERTIES = [ - 'rendererUrl', - 'sendTargetingKeys', - 'adTemplate', - 'type', - 'ext', - 'privacyLink', - 'clickUrl', - 'privacyIcon' -]; -const NATIVE_ASSET_DEFAULT = { - TITLE: { - LEN: 25 - }, - VIDEO: { - MIMES: [ - 'video/mp4', - 'video/webm' - ], - MINDURATION: 0, - MAXDURATION: 120, - PROTOCOLS: [2, 3, 5, 6], - } -}; -const NATIVE_EVENT_TYPES = { - IMRESSION: 1 -}; -const NATIVE_EVENT_TRACKING_METHOD = { - IMG: 1, - JS: 2 -}; const LOCAL_STORAGE_KEY = 'ixdiag'; let hasRegisteredHandler = false; export const storage = getStorageManager({gvlid: GLOBAL_VENDOR_ID, bidderCode: BIDDER_CODE}); @@ -307,50 +219,13 @@ function bidToVideoImp(bid) { */ function bidToNativeImp(bid) { const imp = bidToImp(bid); - const nativeAdUnitRef = deepAccess(bid, 'mediaTypes.native'); - - const assets = []; - - // Convert all native assets to imp object - for (const [adUnitProperty, adUnitValues] of Object.entries(nativeAdUnitRef)) { - if (!NATIVE_ASSETS_MAP[adUnitProperty]) { - continue; - } - - const { assetType, subtype } = NATIVE_ASSETS_MAP[adUnitProperty]; - let asset; - switch (assetType) { - case NATIVE_ASSET_TYPES.TITLE: - asset = createNativeTitleRequest(adUnitValues); - break; - case NATIVE_ASSET_TYPES.IMG: - asset = createNativeImgRequest(adUnitValues, subtype); - break; - case NATIVE_ASSET_TYPES.VIDEO: - asset = createNativeVideoRequest(adUnitValues); - break; - case NATIVE_ASSET_TYPES.DATA: - asset = createNativeDataRequest(adUnitValues, subtype); - break; - } - asset.id = assetType + (subtype || 0); - assets.push(asset); - } - - if (assets.length === 0) { - logWarn('IX Bid Adapter: Native bid does not contain recognised assets in [mediaTypes.native]'); - return {}; - } - const request = { - assets: assets, - ver: '1.2', - eventtrackers: [{ - event: 1, - methods: [1, 2] - }], - privacy: 1 - }; + const request = bid.nativeOrtbRequest + request.eventtrackers = [{ + event: 1, + methods: [1, 2] + }]; + request.privacy = 1; imp.native = { request: JSON.stringify(request), @@ -365,80 +240,6 @@ function bidToNativeImp(bid) { return imp; } -/** - * Converts native bid asset to a native impression asset - * @param {object} bidAsset PBJS bid asset object - * @returns {object} IX impression asset object - */ -function createNativeTitleRequest(bidAsset) { - return { - required: bidAsset.required ? 1 : 0, - title: { - len: bidAsset.len ? bidAsset.len : NATIVE_ASSET_DEFAULT.TITLE.LEN, - ext: bidAsset.ext - } - } -} - -/** - * Converts native bid asset to a native impression asset - * @param {object} bidAsset PBJS bid asset object - * @param {int} type The image type - * @returns {object} IX impression asset object - */ -function createNativeImgRequest(bidAsset, type) { - let asset = { - required: bidAsset.required ? 1 : 0, - img: { - type: type, - mimes: bidAsset.mimes, - ext: bidAsset.ext - } - } - - if (bidAsset.hasOwnProperty('sizes') && bidAsset.sizes.length === 2) { - asset.img.wmin = bidAsset.sizes[0]; - asset.img.hmin = bidAsset.sizes[1]; - } - - return asset -} - -/** - * Converts native bid asset to a native impression asset - * @param {object} bidAsset PBJS bid asset object - * @returns {object} IX impression asset object - */ -function createNativeVideoRequest(bidAsset) { - return { - required: bidAsset.required ? 1 : 0, - video: { - mimes: bidAsset.mimes ? bidAsset.mimes : NATIVE_ASSET_DEFAULT.VIDEO.MIMES, - minduration: bidAsset.minduration ? bidAsset.minduration : NATIVE_ASSET_DEFAULT.VIDEO.MINDURATION, - maxduration: bidAsset.maxduration ? bidAsset.maxduration : NATIVE_ASSET_DEFAULT.VIDEO.MAXDURATION, - protocols: bidAsset.protocols ? bidAsset.protocols : NATIVE_ASSET_DEFAULT.VIDEO.PROTOCOLS, - ext: bidAsset.ext - } - } -} - -/** - * Converts native bid asset to a native impression asset - * @param {object} bidAsset PBJS bid asset object - * @param {int} type The image type - * @returns {object} IX impression asset object - */ -function createNativeDataRequest(bidAsset, type) { - return { - required: bidAsset.required ? 1 : 0, - data: { - type: type, - len: bidAsset.len, - ext: bidAsset.ext - } - } -} - /** * Converts an incoming PBJS bid to an IX Impression * @param {object} bid PBJS bid object @@ -559,7 +360,7 @@ function parseBid(rawBid, currency, bidRequest) { bid.mediaTypes = bidRequest.mediaTypes; bid.ttl = isValidExpiry ? rawBid.exp : VIDEO_TIME_TO_LIVE; } else if (parsedAdm && parsedAdm.native) { - bid.native = interpretNativeAdm(parsedAdm.native); + bid.native = {ortb: parsedAdm.native}; bid.width = rawBid.w ? rawBid.w : 1; bid.height = rawBid.h ? rawBid.h : 1; bid.mediaType = NATIVE; @@ -583,84 +384,6 @@ function parseBid(rawBid, currency, bidRequest) { return bid; } -/** - * Parse native adm and set native asset key names recognized by Prebid.js - * @param {string} adm Native adm complience - */ -function interpretNativeAdm(nativeResponse) { - const native = { - clickUrl: nativeResponse.link.url, - privacyLink: nativeResponse.privacy - }; - - for (const asset of nativeResponse.assets) { - const subtype = asset.id % 100; - const assetType = asset.id - subtype; - - switch (assetType) { - case NATIVE_ASSET_TYPES.TITLE: - native.title = asset.title && asset.title.text; - break; - case NATIVE_ASSET_TYPES.IMG: - const image = { - url: asset.img && asset.img.url, - height: asset.img && asset.img.h, - width: asset.img && asset.img.w - }; - native[subtype === NATIVE_IMAGE_TYPES.ICON ? 'icon' : 'image'] = image; - break; - case NATIVE_ASSET_TYPES.VIDEO: - native.video = asset.video && asset.video.vasttag; - break; - case NATIVE_ASSET_TYPES.DATA: - setDataAsset(native, asset, subtype); - break; - default: - logWarn(`IX Bid Adapter: native asset ID ${asset.id} could not be recognized`); - } - } - - setTrackers(native, nativeResponse); - return native; -} - -function setDataAsset(native, asset, type) { - if (!(type in NATIVE_DATA_MAP)) { - logWarn(`IX Bid Adapter: native data asset type ${type} is not supported`); - return; - } - native[NATIVE_DATA_MAP[type]] = asset.data && asset.data.value; -} - -function setTrackers(native, nativeResponse) { - native.impressionTrackers = [] - - if (Array.isArray(nativeResponse.imptrackers)) { - native.impressionTrackers.push(...nativeResponse.imptrackers) - } - - if (Array.isArray(nativeResponse.link.clicktrackers)) { - native.impressionTrackers.push(...nativeResponse.link.clicktrackers) - } - - if (Array.isArray(nativeResponse.eventtrackers)) { - nativeResponse.eventtrackers.forEach(tracker => { - if (tracker.event !== NATIVE_EVENT_TYPES.IMRESSION) { - return - } - - switch (tracker.method) { - case NATIVE_EVENT_TRACKING_METHOD.IMG: - native.impressionTrackers.push(tracker.url); - break; - case NATIVE_EVENT_TRACKING_METHOD.JS: - native.javascriptTrackers = ``; - break; - } - }) - } -} - /** * Determines whether or not the given object is valid size format. * @@ -758,25 +481,13 @@ function isValidBidFloorParams(bidFloor, bidFloorCur) { bidFloorCur.match(curRegex)); } -function nativeMediaTypeValid(nativeObj) { - if (nativeObj === undefined) { - return true; - } - - let hasValidAsset = false; - - for (const property in nativeObj) { - if (!(property in NATIVE_ASSETS_MAP) && !NATIVE_ALLOWED_PROPERTIES.includes(property)) { - logError('IX Bid Adapter: native', { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); - return false; - } - - if (property in NATIVE_ASSETS_MAP) { - hasValidAsset = true; - } +function nativeMediaTypeValid(bid) { + const nativeMediaTypes = deepAccess(bid, 'mediaTypes.native'); + if (nativeMediaTypes === undefined) { + return true } - return hasValidAsset; + return bid.nativeOrtbRequest && Array.isArray(bid.nativeOrtbRequest.assets) && bid.nativeOrtbRequest.assets.length > 0 } /** @@ -837,8 +548,6 @@ function getEidInfo(allEids) { * */ function buildRequest(validBidRequests, bidderRequest, impressions, version) { - // convert Native ORTB definition to old-style prebid native definition - validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); // Always use secure HTTPS protocol. let baseUrl = SECURE_BID_URL; // Get ids from Prebid User ID Modules @@ -966,7 +675,6 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { // Use the siteId in the first bid request as the main siteId. siteID = validBidRequests[0].params.siteId; payload.s = siteID; - payload.v = version; if (version) { payload.v = version; } @@ -1603,7 +1311,6 @@ export const spec = { const paramsSize = deepAccess(bid, 'params.size'); const mediaTypeBannerSizes = deepAccess(bid, 'mediaTypes.banner.sizes'); const mediaTypeVideoRef = deepAccess(bid, 'mediaTypes.video'); - const mediaTypeNativeRef = deepAccess(bid, 'mediaTypes.native'); const mediaTypeVideoPlayerSize = deepAccess(bid, 'mediaTypes.video.playerSize'); const hasBidFloor = bid.params.hasOwnProperty('bidFloor'); const hasBidFloorCur = bid.params.hasOwnProperty('bidFloorCur'); @@ -1670,7 +1377,7 @@ export const spec = { } } - return nativeMediaTypeValid(mediaTypeNativeRef); + return nativeMediaTypeValid(bid); }, /** diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index 243b702f03d..7360024eed2 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -10,7 +10,6 @@ describe('IndexexchangeAdapter', function () { const IX_SECURE_ENDPOINT = 'https://htlb.casalemedia.com/openrtb/pbjs'; const VIDEO_ENDPOINT_VERSION = 8.1; const BANNER_ENDPOINT_VERSION = 7.2; - const NATIVE_ENDPOINT_VERSION = undefined; const SAMPLE_SCHAIN = { 'ver': '1.0', @@ -378,6 +377,7 @@ describe('IndexexchangeAdapter', function () { required: false }, title: { + len: 25, required: true }, body: { @@ -387,13 +387,20 @@ describe('IndexexchangeAdapter', function () { required: true }, video: { - required: false + required: false, + mimes: ['video/mp4', 'video/webm'], + minduration: 0, + maxduration: 120, + protocols: [2, 3, 5, 6] }, sponsoredBy: { required: true } } }, + nativeOrtbRequest: { + assets: [{id: 0, required: 0, img: {type: 1}}, {id: 1, required: 1, title: {len: 140}}, {id: 2, required: 1, data: {type: 2}}, {id: 3, required: 1, img: {type: 3}}, {id: 4, required: false, video: {mimes: ['video/mp4', 'video/webm'], minduration: 0, maxduration: 120, protocols: [2, 3, 5, 6]}}] + }, adUnitCode: 'div-gpt-ad-1460505748563-0', transactionId: '173f49a8-7549-4218-a23c-e7ba59b47231', bidId: '1a2b3c4f', @@ -432,6 +439,9 @@ describe('IndexexchangeAdapter', function () { } } }, + nativeOrtbRequest: { + assets: [{id: 0, required: 0, img: {type: 1}}, {id: 1, required: 1, title: {len: 140}}, {id: 2, required: 1, data: {type: 2}}, {id: 3, required: 1, img: {type: 3}}, {id: 4, required: false, video: {mimes: ['video/mp4', 'video/webm'], minduration: 0, maxduration: 120, protocols: [2, 3, 5, 6]}}] + }, adUnitCode: 'div-gpt-ad-1460505748562-0', transactionId: '173f49a8-7549-4218-a23c-e7ba59b47230', bidId: '1a2b3c4e', @@ -442,7 +452,7 @@ describe('IndexexchangeAdapter', function () { ]; const DEFAULT_NATIVE_IMP = { - request: '{"assets":[{"required":0,"img":{"type":1},"id":201},{"required":1,"title":{"len":25},"id":100},{"required":1,"data":{"type":2},"id":402},{"required":1,"img":{"type":3},"id":203},{"required":0,"video":{"mimes":["video/mp4","video/webm"],"minduration":0,"maxduration":120,"protocols":[2,3,5,6]},"id":300},{"required":1,"data":{"type":1},"id":401}],"ver":"1.2","eventtrackers":[{"event":1,"methods":[1,2]}],"privacy":1}', + request: '{"assets":[{"id":0,"required":0,"img":{"type":1}},{"id":1,"required":1,"title":{"len":140}},{"id":2,"required":1,"data":{"type":2}},{"id":3,"required":1,"img":{"type":3}},{"id":4,"required":false,"video":{"mimes":["video/mp4","video/webm"],"minduration":0,"maxduration":120,"protocols":[2,3,5,6]}}],"eventtrackers":[{"event":1,"methods":[1,2]}],"privacy":1}', ver: '1.2' } @@ -588,7 +598,7 @@ describe('IndexexchangeAdapter', function () { advbrandid: 303325, advbrand: 'OECTA' }, - adm: '{"native":{"ver":"1.2","assets":[{"id":201,"img":{"url":"https://cdn.liftoff.io/customers/1209/creatives/2501-icon-250x250.png","w":250,"h":250}},{"id":203,"img":{"url":"https://cdn.liftoff.io/customers/5a9cab9cc6/image/lambda_png/a0355879b06c09b09232.png","w":1200,"h":627}},{"id":401,"data":{"value":"autodoc.co.uk"}},{"id":402,"data":{"value":"Les pièces automobiles dont vous avez besoin, toujours sous la main."}},{"id":100,"title":{"text":"Autodoc"}},{"id":300,"video":{"vasttag":"blah"}}],"link":{"url":"https://play.google.com/store/apps/details?id=de.autodoc.gmbh","clicktrackers":["https://click.liftoff.io/v1/campaign_click/blah"]},"eventtrackers":[{"event":1,"method":1,"url":"https://impression-europe.liftoff.io/index/impression"},{"event":1,"method":1,"url":"https://a701.casalemedia.com/impression/v1"}],"privacy":"https://privacy.link.com"}}' + adm: '{"native":{"ver":"1.2","assets":[{"id":0,"img":{"url":"https://cdn.liftoff.io/customers/1209/creatives/2501-icon-250x250.png","w":250,"h":250}},{"id":1,"img":{"url":"https://cdn.liftoff.io/customers/5a9cab9cc6/image/lambda_png/a0355879b06c09b09232.png","w":1200,"h":627}},{"id":2,"data":{"value":"autodoc.co.uk"}},{"id":3,"data":{"value":"Les pièces automobiles dont vous avez besoin, toujours sous la main."}},{"id":4,"title":{"text":"Autodoc"}},{"id":5,"video":{"vasttag":"blah"}}],"link":{"url":"https://play.google.com/store/apps/details?id=de.autodoc.gmbh","clicktrackers":["https://click.liftoff.io/v1/campaign_click/blah"]},"eventtrackers":[{"event":1,"method":1,"url":"https://impression-europe.liftoff.io/index/impression"},{"event":1,"method":1,"url":"https://a701.casalemedia.com/impression/v1"}],"privacy":"https://privacy.link.com"}}' } ], seat: '3970' @@ -864,7 +874,7 @@ describe('IndexexchangeAdapter', function () { expect(spec.isBidRequestValid(bid)).to.equal(true); }); - it('should return true when required params found for a banner or video ad', function () { + it('should return true when required params found for a banner, video or native ad', function () { expect(spec.isBidRequestValid(DEFAULT_BANNER_VALID_BID[0])).to.equal(true); expect(spec.isBidRequestValid(DEFAULT_VIDEO_VALID_BID[0])).to.equal(true); expect(spec.isBidRequestValid(DEFAULT_NATIVE_VALID_BID[0])).to.equal(true); @@ -1064,15 +1074,12 @@ describe('IndexexchangeAdapter', function () { expect(spec.isBidRequestValid(bid)).to.equal(false); }); - it('should fail when native contains unrecongized properties', function () { + it('should fail if native openRTB object contains no valid assets', function () { let bid = utils.deepClone(DEFAULT_NATIVE_VALID_BID[0]); - bid.mediaTypes.native.test = {} + bid.nativeOrtbRequest = {} expect(spec.isBidRequestValid(bid)).to.be.false; - }); - it('should fail if native mediaTypes should contains no valid assets', function () { - let bid = utils.deepClone(DEFAULT_NATIVE_VALID_BID[0]); - bid.mediaTypes.native = {} + bid.nativeOrtbRequest = {assets: []} expect(spec.isBidRequestValid(bid)).to.be.false; }); }); @@ -2145,7 +2152,7 @@ describe('IndexexchangeAdapter', function () { it('should have native request', () => { const nativeImpression = JSON.parse(request[1].data.r).imp[0]; - expect(request[1].data.v).to.equal(NATIVE_ENDPOINT_VERSION); + expect(request[1].data.hasOwnProperty('v')).to.equal(false); expect(nativeImpression.id).to.equal(DEFAULT_NATIVE_VALID_BID[0].bidId); expect(nativeImpression.native).to.deep.equal(DEFAULT_NATIVE_IMP); }); @@ -2491,7 +2498,7 @@ describe('IndexexchangeAdapter', function () { const request = spec.buildRequests(DEFAULT_NATIVE_VALID_BID, DEFAULT_OPTION); const query = request[0].data; - expect(query.v).to.equal(NATIVE_ENDPOINT_VERSION); + expect(query.hasOwnProperty('v')).to.equal(false); expect(query.s).to.equal(DEFAULT_NATIVE_VALID_BID[0].params.siteId); expect(query.r).to.exist; expect(query.ac).to.equal('j'); @@ -2516,92 +2523,148 @@ describe('IndexexchangeAdapter', function () { const request = spec.buildRequests(DEFAULT_NATIVE_VALID_BID, DEFAULT_OPTION); const nativeImpression = JSON.parse(request[0].data.r).imp[0]; - expect(request[0].data.v).to.equal(NATIVE_ENDPOINT_VERSION); + expect(request[0].data.hasOwnProperty('v')).to.equal(false); expect(nativeImpression.id).to.equal(DEFAULT_NATIVE_VALID_BID[0].bidId); expect(nativeImpression.native).to.deep.equal(DEFAULT_NATIVE_IMP); }); it('should build request with given asset properties', function() { let bid = utils.deepClone(DEFAULT_NATIVE_VALID_BID) - bid[0].mediaTypes.native = { - title: { - len: 200 - }, - video: { - mimes: [ - 'javascript' - ], - minduration: 10, - maxduration: 60, - protocols: [1] - } + bid[0].nativeOrtbRequest = { + assets: [{id: 0, required: 0, title: {len: 140}}, {id: 1, required: 0, video: {mimes: ['javascript'], minduration: 10, maxduration: 60, protocols: [1]}}] } const request = spec.buildRequests(bid, DEFAULT_OPTION); const nativeImpression = JSON.parse(request[0].data.r).imp[0]; - expect(nativeImpression.native).to.deep.equal({request: '{"assets":[{"required":0,"title":{"len":200},"id":100},{"required":0,"video":{"mimes":["javascript"],"minduration":10,"maxduration":60,"protocols":[1]},"id":300}],"ver":"1.2","eventtrackers":[{"event":1,"methods":[1,2]}],"privacy":1}', ver: '1.2'}); + expect(nativeImpression.native).to.deep.equal({request: '{"assets":[{"id":0,"required":0,"title":{"len":140}},{"id":1,"required":0,"video":{"mimes":["javascript"],"minduration":10,"maxduration":60,"protocols":[1]}}],"eventtrackers":[{"event":1,"methods":[1,2]}],"privacy":1}', ver: '1.2'}); }); it('should build request with all possible Prebid asset properties', function() { let bid = utils.deepClone(DEFAULT_NATIVE_VALID_BID) - bid[0].mediaTypes.native = { - title: { - required: false - }, - body: { - required: false - }, - body2: { - required: false - }, - sponsoredBy: { - required: false - }, - icon: { - required: false - }, - image: { - required: false - }, - clickUrl: { - required: false - }, - displayUrl: { - required: false - }, - privacyLink: { - required: false - }, - privacyIcon: { - required: false - }, - cta: { - required: false - }, - rating: { - required: false - }, - downloads: { - required: false - }, - likes: { - required: false - }, - price: { - required: false - }, - salePrice: { - required: false - }, - address: { - required: false - }, - phone: { - required: false - }, + bid[0].nativeOrtbRequest = { + 'ver': '1.2', + 'assets': [ + { + 'id': 0, + 'required': 0, + 'title': { + 'len': 140 + } + }, + { + 'id': 1, + 'required': 0, + 'data': { + 'type': 2 + } + }, + { + 'id': 2, + 'required': 0, + 'data': { + 'type': 10 + } + }, + { + 'id': 3, + 'required': 0, + 'data': { + 'type': 1 + } + }, + { + 'id': 4, + 'required': 0, + 'img': { + 'type': 1 + } + }, + { + 'id': 5, + 'required': 0, + 'img': { + 'type': 3 + } + }, + { + 'id': 6, + 'required': 0 + }, + { + 'id': 7, + 'required': 0, + 'data': { + 'type': 11 + } + }, + { + 'id': 8, + 'required': 0 + }, + { + 'id': 9, + 'required': 0 + }, + { + 'id': 10, + 'required': 0, + 'data': { + 'type': 12 + } + }, + { + 'id': 11, + 'required': 0, + 'data': { + 'type': 3 + } + }, + { + 'id': 12, + 'required': 0, + 'data': { + 'type': 5 + } + }, + { + 'id': 13, + 'required': 0, + 'data': { + 'type': 4 + } + }, + { + 'id': 14, + 'required': 0, + 'data': { + 'type': 6 + } + }, + { + 'id': 15, + 'required': 0, + 'data': { + 'type': 7 + } + }, + { + 'id': 16, + 'required': 0, + 'data': { + 'type': 9 + } + }, + { + 'id': 17, + 'required': 0, + 'data': { + 'type': 8 + } + } + ] } const request = spec.buildRequests(bid, DEFAULT_OPTION); const nativeImpression = JSON.parse(request[0].data.r).imp[0]; - expect(nativeImpression.native).to.deep.equal({request: '{"assets":[{"required":0,"title":{"len":25},"id":100},{"required":0,"data":{"type":2},"id":402},{"required":0,"data":{"type":10},"id":410},{"required":0,"data":{"type":1},"id":401},{"required":0,"img":{"type":1},"id":201},{"required":0,"img":{"type":3},"id":203},{"required":0,"data":{"type":11},"id":411},{"required":0,"data":{"type":12},"id":412},{"required":0,"data":{"type":3},"id":403},{"required":0,"data":{"type":5},"id":405},{"required":0,"data":{"type":4},"id":404},{"required":0,"data":{"type":6},"id":406},{"required":0,"data":{"type":7},"id":407},{"required":0,"data":{"type":9},"id":409},{"required":0,"data":{"type":8},"id":408}],"ver":"1.2","eventtrackers":[{"event":1,"methods":[1,2]}],"privacy":1}', ver: '1.2'}); + expect(nativeImpression.native).to.deep.equal({request: '{"ver":"1.2","assets":[{"id":0,"required":0,"title":{"len":140}},{"id":1,"required":0,"data":{"type":2}},{"id":2,"required":0,"data":{"type":10}},{"id":3,"required":0,"data":{"type":1}},{"id":4,"required":0,"img":{"type":1}},{"id":5,"required":0,"img":{"type":3}},{"id":6,"required":0},{"id":7,"required":0,"data":{"type":11}},{"id":8,"required":0},{"id":9,"required":0},{"id":10,"required":0,"data":{"type":12}},{"id":11,"required":0,"data":{"type":3}},{"id":12,"required":0,"data":{"type":5}},{"id":13,"required":0,"data":{"type":4}},{"id":14,"required":0,"data":{"type":6}},{"id":15,"required":0,"data":{"type":7}},{"id":16,"required":0,"data":{"type":9}},{"id":17,"required":0,"data":{"type":8}}],"eventtrackers":[{"event":1,"methods":[1,2]}],"privacy":1}', ver: '1.2'}); }) }); @@ -3091,27 +3154,70 @@ describe('IndexexchangeAdapter', function () { advertiserDomains: ['www.abc.com'] }, native: { - body: 'Les pièces automobiles dont vous avez besoin, toujours sous la main.', - clickUrl: 'https://play.google.com/store/apps/details?id=de.autodoc.gmbh', - icon: { - height: 250, - width: 250, - url: 'https://cdn.liftoff.io/customers/1209/creatives/2501-icon-250x250.png' - }, - image: { - height: 627, - width: 1200, - url: 'https://cdn.liftoff.io/customers/5a9cab9cc6/image/lambda_png/a0355879b06c09b09232.png' - }, - impressionTrackers: [ - 'https://click.liftoff.io/v1/campaign_click/blah', - 'https://impression-europe.liftoff.io/index/impression', - 'https://a701.casalemedia.com/impression/v1' - ], - privacyLink: 'https://privacy.link.com', - sponsoredBy: 'autodoc.co.uk', - title: 'Autodoc', - video: 'blah' + ortb: { + assets: [ + { + 'id': 0, + 'img': { + 'h': 250, + 'url': 'https://cdn.liftoff.io/customers/1209/creatives/2501-icon-250x250.png', + 'w': 250 + } + }, + { + 'id': 1, + 'img': { + 'h': 627, + 'url': 'https://cdn.liftoff.io/customers/5a9cab9cc6/image/lambda_png/a0355879b06c09b09232.png', + 'w': 1200 + } + }, + { + 'data': { + 'value': 'autodoc.co.uk' + }, + 'id': 2 + }, + { + 'data': { + 'value': 'Les pièces automobiles dont vous avez besoin, toujours sous la main.' + }, + 'id': 3 + }, + { + 'id': 4, + 'title': { + 'text': 'Autodoc' + } + }, + { + 'id': 5, + 'video': { + 'vasttag': 'blah' + } + } + ], + 'eventtrackers': [ + { + 'event': 1, + 'method': 1, + 'url': 'https://impression-europe.liftoff.io/index/impression' + }, + { + 'event': 1, + 'method': 1, + 'url': 'https://a701.casalemedia.com/impression/v1' + } + ], + 'link': { + 'clicktrackers': [ + 'https://click.liftoff.io/v1/campaign_click/blah' + ], + 'url': 'https://play.google.com/store/apps/details?id=de.autodoc.gmbh' + }, + 'privacy': 'https://privacy.link.com', + 'ver': '1.2' + } }, ttl: 3600 }