From e4f0d669407e6498163bfe963aa714c773ae7b43 Mon Sep 17 00:00:00 2001 From: Jason Snellbaker Date: Fri, 2 Nov 2018 13:04:54 -0400 Subject: [PATCH 1/3] appnexus adapter support empty keyvalues in bidder params --- modules/appnexusBidAdapter.js | 19 +++++- src/utils.js | 2 +- test/spec/modules/appnexusBidAdapter_spec.js | 6 ++ test/spec/utils_spec.js | 69 ++++++++++++++++++++ 4 files changed, 94 insertions(+), 2 deletions(-) diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index 19aa5e7cf73..ceeee559fe1 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -178,6 +178,14 @@ export const spec = { params.use_pmt_rule = (typeof params.usePaymentRule === 'boolean') ? params.usePaymentRule : false; if (params.usePaymentRule) { delete params.usePaymentRule; } + if (utils.isArray(params.keywords) && params.keywords.length > 0) { + params.keywords.forEach(function(keyPairObj) { + if (utils.isArray(keyPairObj.value) && keyPairObj.value.length > 0 && keyPairObj.value[0] === '') { + delete keyPairObj.value; + } + }); + } + Object.keys(params).forEach(paramKey => { let convertedKey = utils.convertCamelToUnderscore(paramKey); if (convertedKey !== paramKey) { @@ -345,7 +353,16 @@ function bidToTag(bid) { tag.external_imp_id = bid.params.externalImpId; } if (!utils.isEmpty(bid.params.keywords)) { - tag.keywords = utils.transformBidderParamKeywords(bid.params.keywords); + let keywords = utils.transformBidderParamKeywords(bid.params.keywords); + + if (keywords.length > 0) { + keywords.forEach(function(keyPairObj) { + if (utils.isArray(keyPairObj.value) && keyPairObj.value.length > 0 && keyPairObj.value[0] === '') { + delete keyPairObj.value; + } + }); + } + tag.keywords = keywords; } if (bid.mediaType === NATIVE || utils.deepAccess(bid, `mediaTypes.${NATIVE}`)) { diff --git a/src/utils.js b/src/utils.js index 93b19485dfe..1cf42fe6538 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1086,7 +1086,7 @@ export function transformBidderParamKeywords(keywords, paramName = 'keywords') { let values = []; exports._each(v, (val) => { val = exports.getValueString(paramName + '.' + k, val); - if (val) { values.push(val); } + if (val || val === '') { values.push(val); } }); v = values; } else { diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js index 5e41c1c9544..e6afc8561b6 100644 --- a/test/spec/modules/appnexusBidAdapter_spec.js +++ b/test/spec/modules/appnexusBidAdapter_spec.js @@ -261,6 +261,8 @@ describe('AppNexusAdapter', function () { singleArrNum: [5], multiValMixed: ['value1', 2, 'value3'], singleValNum: 123, + emptyStr: '', + emptyArr: [''], badValue: {'foo': 'bar'} // should be dropped } } @@ -285,6 +287,10 @@ describe('AppNexusAdapter', function () { }, { 'key': 'singleValNum', 'value': ['123'] + }, { + 'key': 'emptyStr' + }, { + 'key': 'emptyArr' }]); }); diff --git a/test/spec/utils_spec.js b/test/spec/utils_spec.js index 952c6791056..df5d46223c0 100755 --- a/test/spec/utils_spec.js +++ b/test/spec/utils_spec.js @@ -846,4 +846,73 @@ describe('Utils', function () { expect(sizes).to.deep.equal([[300, 250], [300, 600]]); }); }); + + describe('transformBidderParamKeywords', function () { + it('returns an array of objects when keyvalue is an array', function () { + let keywords = { + genre: ['rock', 'pop'] + }; + let result = utils.transformBidderParamKeywords(keywords); + expect(result).to.deep.equal([{ + key: 'genre', + value: ['rock', 'pop'] + }]); + }); + + it('returns an array of objects when keyvalue is a string', function () { + let keywords = { + genre: 'opera' + }; + let result = utils.transformBidderParamKeywords(keywords); + expect(result).to.deep.equal([{ + key: 'genre', + value: ['opera'] + }]); + }); + + it('returns an array of objects when keyvalue is a number', function () { + let keywords = { + age: 15 + }; + let result = utils.transformBidderParamKeywords(keywords); + expect(result).to.deep.equal([{ + key: 'age', + value: ['15'] + }]); + }); + + it('returns an array of objects when using multiple keys with values of differing types', function () { + let keywords = { + genre: 'classical', + mix: ['1', 2, '3', 4], + age: 10 + }; + let result = utils.transformBidderParamKeywords(keywords); + expect(result).to.deep.equal([{ + key: 'genre', + value: ['classical'] + }, { + key: 'mix', + value: ['1', '2', '3', '4'] + }, { + key: 'age', + value: ['10'] + }]); + }); + + it('returns an array of objects when the keyvalue uses an empty string', function() { + let keywords = { + test: [''], + test2: '' + }; + let result = utils.transformBidderParamKeywords(keywords); + expect(result).to.deep.equal([{ + key: 'test', + value: [''] + }, { + key: 'test2', + value: [''] + }]); + }); + }); }); From d5bed2356220379d1c6028a897af2f6bd71218c3 Mon Sep 17 00:00:00 2001 From: Jason Snellbaker Date: Mon, 5 Nov 2018 11:16:26 -0500 Subject: [PATCH 2/3] create function to check if array is populated --- modules/appnexusBidAdapter.js | 6 +++--- src/utils.js | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index ceeee559fe1..c0e97d58647 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -178,9 +178,9 @@ export const spec = { params.use_pmt_rule = (typeof params.usePaymentRule === 'boolean') ? params.usePaymentRule : false; if (params.usePaymentRule) { delete params.usePaymentRule; } - if (utils.isArray(params.keywords) && params.keywords.length > 0) { + if (utils.isPopulatedArray(params.keywords)) { params.keywords.forEach(function(keyPairObj) { - if (utils.isArray(keyPairObj.value) && keyPairObj.value.length > 0 && keyPairObj.value[0] === '') { + if (utils.isPopulatedArray(keyPairObj.value) && keyPairObj.value[0] === '') { delete keyPairObj.value; } }); @@ -357,7 +357,7 @@ function bidToTag(bid) { if (keywords.length > 0) { keywords.forEach(function(keyPairObj) { - if (utils.isArray(keyPairObj.value) && keyPairObj.value.length > 0 && keyPairObj.value[0] === '') { + if (utils.isPopulatedArray(keyPairObj.value) && keyPairObj.value[0] === '') { delete keyPairObj.value; } }); diff --git a/src/utils.js b/src/utils.js index 1cf42fe6538..6d25be36c9f 100644 --- a/src/utils.js +++ b/src/utils.js @@ -439,6 +439,10 @@ exports.isBoolean = function(object) { return exports.isA(object, tBoolean); } +exports.isPopulatedArray = function(arr) { + return !!(exports.isArray(arr) && arr.length > 0); +} + /** * Return if the object is "empty"; * this includes falsey, no keys, or no items at indices From 0619521efcdcf48d8d807008493b870798ee48a7 Mon Sep 17 00:00:00 2001 From: Jason Snellbaker Date: Tue, 6 Nov 2018 08:54:51 -0500 Subject: [PATCH 3/3] refactor forEach functions --- modules/appnexusBidAdapter.js | 24 +++++++++++++----------- src/utils.js | 4 ---- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js index c0e97d58647..cc0cac579da 100644 --- a/modules/appnexusBidAdapter.js +++ b/modules/appnexusBidAdapter.js @@ -178,12 +178,8 @@ export const spec = { params.use_pmt_rule = (typeof params.usePaymentRule === 'boolean') ? params.usePaymentRule : false; if (params.usePaymentRule) { delete params.usePaymentRule; } - if (utils.isPopulatedArray(params.keywords)) { - params.keywords.forEach(function(keyPairObj) { - if (utils.isPopulatedArray(keyPairObj.value) && keyPairObj.value[0] === '') { - delete keyPairObj.value; - } - }); + if (isPopulatedArray(params.keywords)) { + params.keywords.forEach(deleteValues); } Object.keys(params).forEach(paramKey => { @@ -199,6 +195,16 @@ export const spec = { } } +function isPopulatedArray(arr) { + return !!(utils.isArray(arr) && arr.length > 0); +} + +function deleteValues(keyPairObj) { + if (isPopulatedArray(keyPairObj.value) && keyPairObj.value[0] === '') { + delete keyPairObj.value; + } +} + function newRenderer(adUnitCode, rtbBid, rendererOptions = {}) { const renderer = Renderer.install({ id: rtbBid.renderer_id, @@ -356,11 +362,7 @@ function bidToTag(bid) { let keywords = utils.transformBidderParamKeywords(bid.params.keywords); if (keywords.length > 0) { - keywords.forEach(function(keyPairObj) { - if (utils.isPopulatedArray(keyPairObj.value) && keyPairObj.value[0] === '') { - delete keyPairObj.value; - } - }); + keywords.forEach(deleteValues); } tag.keywords = keywords; } diff --git a/src/utils.js b/src/utils.js index 6d25be36c9f..1cf42fe6538 100644 --- a/src/utils.js +++ b/src/utils.js @@ -439,10 +439,6 @@ exports.isBoolean = function(object) { return exports.isA(object, tBoolean); } -exports.isPopulatedArray = function(arr) { - return !!(exports.isArray(arr) && arr.length > 0); -} - /** * Return if the object is "empty"; * this includes falsey, no keys, or no items at indices