diff --git a/src/native.js b/src/native.js index 05347e47f1f..a641beb71d5 100644 --- a/src/native.js +++ b/src/native.js @@ -364,7 +364,7 @@ export function getNativeTargeting(bid, {index = auctionManager.index} = {}) { let keyValues = {}; const adUnit = index.getAdUnit(bid); - const globalSendTargetingKeys = deepAccess( + const globalSendTargetingKeys = adUnit?.nativeParams?.ortb == null && deepAccess( adUnit, `nativeParams.sendTargetingKeys` ) !== false; @@ -806,20 +806,20 @@ export function toOrtbNativeResponse(legacyResponse, ortbRequest) { export function toLegacyResponse(ortbResponse, ortbRequest) { const legacyResponse = {}; const requestAssets = ortbRequest?.assets || []; - legacyResponse.clickUrl = ortbResponse.link.url; + legacyResponse.clickUrl = ortbResponse.link?.url; legacyResponse.privacyLink = ortbResponse.privacy; for (const asset of ortbResponse?.assets || []) { const requestAsset = requestAssets.find(reqAsset => asset.id === reqAsset.id); if (asset.title) { legacyResponse.title = asset.title.text; } else if (asset.img) { - legacyResponse[requestAsset.img.type === NATIVE_IMAGE_TYPES.MAIN ? 'image' : 'icon'] = { + legacyResponse[requestAsset?.img?.type === NATIVE_IMAGE_TYPES.MAIN ? 'image' : 'icon'] = { url: asset.img.url, width: asset.img.w, height: asset.img.h }; } else if (asset.data) { - legacyResponse[PREBID_NATIVE_DATA_KEYS_TO_ORTB_INVERSE[NATIVE_ASSET_TYPES_INVERSE[requestAsset.data.type]]] = asset.data.value; + legacyResponse[PREBID_NATIVE_DATA_KEYS_TO_ORTB_INVERSE[NATIVE_ASSET_TYPES_INVERSE[requestAsset?.data?.type]]] = asset.data.value; } } diff --git a/test/spec/native_spec.js b/test/spec/native_spec.js index a611a9dd789..877306c1c04 100644 --- a/test/spec/native_spec.js +++ b/test/spec/native_spec.js @@ -22,7 +22,7 @@ import { convertOrtbRequestToProprietaryNative, fromOrtbNativeRequest } from '.. import {auctionManager} from '../../src/auctionManager.js'; import {getRenderingData} from '../../src/adRendering.js'; import {getCreativeRendererSource} from '../../src/creativeRenderers.js'; -import {deepClone} from '../../src/utils.js'; +import {deepClone, deepSetValue} from '../../src/utils.js'; const utils = require('src/utils'); const bid = { @@ -211,6 +211,18 @@ describe('native.js', function () { expect(targeting.hb_native_foo).to.equal(bid.native.foo); }); + it('does not include targeting keys if request is ortb', () => { + const targeting = getNativeTargeting(bid, deps({ + adUnitId: bid.adUnitId, + nativeParams: { + ortb: { + assets: [{id: 1, type: '2'}] + } + } + })); + expect(Object.keys(targeting)).to.eql([]); + }); + it('can get targeting from null native keys', () => { const targeting = getNativeTargeting({...bid, native: {...bid.native, displayUrl: null}}); expect(targeting.hb_native_displayurl).to.not.be.ok; @@ -647,6 +659,14 @@ describe('native.js', function () { expect(actual.impressionTrackers).to.contain('https://sampleurl.com'); expect(actual.impressionTrackers).to.contain('https://sample-imp.com'); }); + ['img.type', 'title.text', 'data.type'].forEach(prop => { + it(`does not choke when the request does not have ${prop}, but the response does`, () => { + const request = {ortb: {assets: [{id: 1}]}}; + const response = {ortb: {assets: [{id: 1}]}}; + deepSetValue(response, `assets.0.${prop}`, 'value'); + toLegacyResponse(response, request); + }) + }) }); describe('setNativeResponseProperties', () => {