UNPKG

mk9-prebid

Version:

Header Bidding Management Library

1,202 lines (1,032 loc) 39.1 kB
import { getAdServerTargeting } from 'test/fixtures/fixtures.js'; import { expect } from 'chai'; import CONSTANTS from 'src/constants.json'; import * as utils from 'src/utils.js'; var assert = require('assert'); describe('Utils', function () { var obj_string = 's', obj_number = 1, obj_object = {}, obj_array = [], obj_function = function () {}; var type_string = 'String', type_number = 'Number', type_object = 'Object', type_array = 'Array', type_function = 'Function'; describe('getBidIdParameter', function () { it('should return value of the key in input object', function () { var obj = { a: 'valueA', b: 'valueB' }; var output = utils.getBidIdParameter('a', obj); assert.equal(output, 'valueA'); }); it('should return empty string, if the key is not existsed in the object', function () { var obj = { a: 'valueA', b: 'valueB' }; var output = utils.getBidIdParameter('c', obj); assert.equal(output, ''); }); }); describe('tryAppendQueryString', function () { it('should append query string to existing url', function () { var url = 'www.a.com?'; var key = 'b'; var value = 'c'; var output = utils.tryAppendQueryString(url, key, value); var expectedResult = url + key + '=' + encodeURIComponent(value) + '&'; assert.equal(output, expectedResult); }); it('should return existing url, if the value is empty', function () { var url = 'www.a.com?'; var key = 'b'; var value = ''; var output = utils.tryAppendQueryString(url, key, value); assert.equal(output, url); }); }); describe('parseQueryStringParameters', function () { it('should append query string to existing using the input obj', function () { var obj = { a: 'http://example.com/?foo=bar&bar=foo', b: 'abc["def"]' }; var output = utils.parseQueryStringParameters(obj); var expectedResult = 'a=' + encodeURIComponent('http://example.com/?foo=bar&bar=foo') + '&b=' + encodeURIComponent('abc["def"]'); assert.equal(output, expectedResult); }); it('should return an empty string, if input obj is empty', function () { var obj = {}; var output = utils.parseQueryStringParameters(obj); assert.equal(output, ''); }); }); describe('transformAdServerTargetingObj', function () { it('should append query string to existing using the input obj', function () { var obj = getAdServerTargeting(); var output = utils.transformAdServerTargetingObj(obj[Object.keys(obj)[0]]); var expected = 'foobar=0x0%2C300x250%2C300x600&' + CONSTANTS.TARGETING_KEYS.SIZE + '=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '=233bcbee889d46d&' + CONSTANTS.TARGETING_KEYS.BIDDER + '=appnexus&' + CONSTANTS.TARGETING_KEYS.SIZE + '_triplelift=0x0&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_triplelift=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_triplelift=222bb26f9e8bd&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_triplelift=triplelift&' + CONSTANTS.TARGETING_KEYS.SIZE + '_appnexus=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_appnexus=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_appnexus=233bcbee889d46d&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_appnexus=appnexus&' + CONSTANTS.TARGETING_KEYS.SIZE + '_pagescience=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_pagescience=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_pagescience=25bedd4813632d7&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_pagescienc=pagescience&' + CONSTANTS.TARGETING_KEYS.SIZE + '_brightcom=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_brightcom=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_brightcom=26e0795ab963896&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_brightcom=brightcom&' + CONSTANTS.TARGETING_KEYS.SIZE + '_brealtime=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_brealtime=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_brealtime=275bd666f5a5a5d&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_brealtime=brealtime&' + CONSTANTS.TARGETING_KEYS.SIZE + '_pubmatic=300x250&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_pubmatic=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_pubmatic=28f4039c636b6a7&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_pubmatic=pubmatic&' + CONSTANTS.TARGETING_KEYS.SIZE + '_rubicon=300x600&' + CONSTANTS.TARGETING_KEYS.PRICE_BUCKET + '_rubicon=10.00&' + CONSTANTS.TARGETING_KEYS.AD_ID + '_rubicon=29019e2ab586a5a&' + CONSTANTS.TARGETING_KEYS.BIDDER + '_rubicon=rubicon'; assert.equal(output, expected); }); it('should return an empty string, if input obj is empty', function () { var obj = {}; var output = utils.transformAdServerTargetingObj(obj); assert.equal(output, ''); }); }); describe('extend', function () { it('should merge two input object', function () { var target = { a: '1', b: '2' }; var source = { c: '3' }; var expectedResult = { a: '1', b: '2', c: '3' }; var output = Object.assign(target, source); assert.deepEqual(output, expectedResult); }); it('should merge two input object even though target object is empty', function () { var target = {}; var source = { c: '3' }; var output = Object.assign(target, source); assert.deepEqual(output, source); }); it('just return target object, if the source object is empty', function () { var target = { a: '1', b: '2' }; var source = {}; var output = Object.assign(target, source); assert.deepEqual(output, target); }); }); describe('parseSizesInput', function () { it('should return query string using multi size array', function () { var sizes = [[728, 90], [970, 90]]; var output = utils.parseSizesInput(sizes); assert.deepEqual(output, ['728x90', '970x90']); }); it('should return query string using single size array', function () { var sizes = [728, 90]; var output = utils.parseSizesInput(sizes); assert.deepEqual(output, ['728x90']); }); it('should return query string using string input', function () { var sizes = '300x250,970x90'; var output = utils.parseSizesInput(sizes); assert.deepEqual(output, ['300x250', '970x90']); }); it('return undefined if input array is empty', function () { var sizes = []; var output = utils.parseSizesInput(sizes); assert.deepEqual(output, []); }); }); describe('parseGPTSingleSizeArray', function () { it('should return size string with input single size array', function () { var size = [300, 250]; var output = utils.parseGPTSingleSizeArray(size); assert.equal(output, '300x250'); }); it('should return size string with input single size array', function () { var size = ['300', '250']; var output = utils.parseGPTSingleSizeArray(size); assert.equal(output, '300x250'); }); it('return undefined using string input', function () { var size = '1'; var output = utils.parseGPTSingleSizeArray(size); assert.equal(output, undefined); }); it('return undefined using number input', function () { var size = 1; var output = utils.parseGPTSingleSizeArray(size); assert.equal(output, undefined); }); it('return undefined using one length single array', function () { var size = [300]; var output = utils.parseGPTSingleSizeArray(size); assert.equal(output, undefined); }); it('return undefined if the input is empty', function () { var size = ''; var output = utils.parseGPTSingleSizeArray(size); assert.equal(output, undefined); }); it('return undefined if the input is not a number', function () { var size = ['foo', 'bar']; var output = utils.parseGPTSingleSizeArray(size); assert.equal(output, undefined); }); it('return undefined if the input is not a number 2', function () { var size = ['foo', 300]; var output = utils.parseGPTSingleSizeArray(size); assert.equal(output, undefined); }); }); describe('parseGPTSingleSizeArrayToRtbSize', function () { it('should return size string with input single size array', function () { var size = [300, 250]; var output = utils.parseGPTSingleSizeArrayToRtbSize(size); assert.deepEqual(output, {w: 300, h: 250}); }); it('should return size string with input single size array', function () { var size = ['300', '250']; var output = utils.parseGPTSingleSizeArrayToRtbSize(size); assert.deepEqual(output, {w: 300, h: 250}); }); it('return undefined using string input', function () { var size = '1'; var output = utils.parseGPTSingleSizeArrayToRtbSize(size); assert.equal(output, undefined); }); it('return undefined using number input', function () { var size = 1; var output = utils.parseGPTSingleSizeArrayToRtbSize(size); assert.equal(output, undefined); }); it('return undefined using one length single array', function () { var size = [300]; var output = utils.parseGPTSingleSizeArrayToRtbSize(size); assert.equal(output, undefined); }); it('return undefined if the input is empty', function () { var size = ''; var output = utils.parseGPTSingleSizeArrayToRtbSize(size); assert.equal(output, undefined); }); it('return undefined if the input is not a number', function () { var size = ['foo', 'bar']; var output = utils.parseGPTSingleSizeArrayToRtbSize(size); assert.equal(output, undefined); }); it('return undefined if the input is not a number 2', function () { var size = [300, 'foo']; var output = utils.parseGPTSingleSizeArrayToRtbSize(size); assert.equal(output, undefined); }); }); describe('isA', function () { it('should return true with string object', function () { var output = utils.isA(obj_string, type_string); assert.deepEqual(output, true); }); it('should return false with object', function () { var output = utils.isA(obj_object, type_string); assert.deepEqual(output, false); }); it('should return true with object', function () { var output = utils.isA(obj_object, type_object); assert.deepEqual(output, true); }); it('should return false with array object', function () { var output = utils.isA(obj_array, type_object); assert.deepEqual(output, false); }); it('should return true with array object', function () { var output = utils.isA(obj_array, type_array); assert.deepEqual(output, true); }); it('should return false with array object', function () { var output = utils.isA(obj_array, type_function); assert.deepEqual(output, false); }); it('should return true with function', function () { var output = utils.isA(obj_function, type_function); assert.deepEqual(output, true); }); it('should return false with number', function () { var output = utils.isA(obj_function, type_number); assert.deepEqual(output, false); }); it('should return true with number', function () { var output = utils.isA(obj_number, type_number); assert.deepEqual(output, true); }); }); describe('isFn', function () { it('should return true with input function', function () { var output = utils.isFn(obj_function); assert.deepEqual(output, true); }); it('should return false with input string', function () { var output = utils.isFn(obj_string); assert.deepEqual(output, false); }); it('should return false with input number', function () { var output = utils.isFn(obj_number); assert.deepEqual(output, false); }); it('should return false with input Array', function () { var output = utils.isFn(obj_array); assert.deepEqual(output, false); }); it('should return false with input object', function () { var output = utils.isFn(obj_object); assert.deepEqual(output, false); }); }); describe('isStr', function () { it('should return true with input string', function () { var output = utils.isStr(obj_string); assert.deepEqual(output, true); }); it('should return false with input number', function () { var output = utils.isStr(obj_number); assert.deepEqual(output, false); }); it('should return false with input object', function () { var output = utils.isStr(obj_object); assert.deepEqual(output, false); }); it('should return false with input array', function () { var output = utils.isStr(obj_array); assert.deepEqual(output, false); }); it('should return false with input function', function () { var output = utils.isStr(obj_function); assert.deepEqual(output, false); }); }); describe('isArray', function () { it('should return false with input string', function () { var output = utils.isArray(obj_string); assert.deepEqual(output, false); }); it('should return false with input number', function () { var output = utils.isArray(obj_number); assert.deepEqual(output, false); }); it('should return false with input object', function () { var output = utils.isArray(obj_object); assert.deepEqual(output, false); }); it('should return true with input array', function () { var output = utils.isArray(obj_array); assert.deepEqual(output, true); }); it('should return false with input function', function () { var output = utils.isArray(obj_function); assert.deepEqual(output, false); }); }); describe('isPlainObject', function () { it('should return false with input string', function () { var output = utils.isPlainObject(obj_string); assert.deepEqual(output, false); }); it('should return false with input number', function () { var output = utils.isPlainObject(obj_number); assert.deepEqual(output, false); }); it('should return true with input object', function () { var output = utils.isPlainObject(obj_object); assert.deepEqual(output, true); }); it('should return false with input array', function () { var output = utils.isPlainObject(obj_array); assert.deepEqual(output, false); }); it('should return false with input function', function () { var output = utils.isPlainObject(obj_function); assert.deepEqual(output, false); }); }); describe('isEmpty', function () { it('should return true with empty object', function () { var output = utils.isEmpty(obj_object); assert.deepEqual(output, true); }); it('should return false with non-empty object', function () { var obj = { a: 'b' }; var output = utils.isEmpty(obj); assert.deepEqual(output, false); }); it('should return false with null', function () { var obj = null; var output = utils.isEmpty(obj); assert.deepEqual(output, true); }); }); describe('contains', function () { it('should return true if the input string contains in the input obj', function () { var output = utils.contains('123', '1'); assert.deepEqual(output, true); }); it('should return false if the input string do not contain in the input obj', function () { var output = utils.contains('234', '1'); assert.deepEqual(output, false); }); it('should return false if the input string is empty', function () { var output = utils.contains(); assert.ok(!output, 'an empty string returns false'); }); }); describe('_map', function () { it('return empty array when input object is empty', function () { var input = {}; var callback = function () {}; var output = utils._map(input, callback); assert.deepEqual(output, []); }); it('return value array with vaild input object', function () { var input = { a: 'A', b: 'B' }; var callback = function (v) { return v; }; var output = utils._map(input, callback); assert.deepEqual(output, ['A', 'B']); }); it('return value array with vaild input object_callback func changed 1', function () { var input = { a: 'A', b: 'B' }; var callback = function (v, k) { return v + k; }; var output = utils._map(input, callback); assert.deepEqual(output, ['Aa', 'Bb']); }); it('return value array with vaild input object_callback func changed 2', function () { var input = { a: 'A', b: 'B' }; var callback = function (v, k, o) { return o; }; var output = utils._map(input, callback); assert.deepEqual(output, [input, input]); }); }); describe('createInvisibleIframe', function () { var output = utils.createInvisibleIframe(); it('return iframe - id', function () { assert.ok(output.id); }); it('return iframe - height', function () { assert.deepEqual(output.height, 0); }); it('return iframe - width', function () { assert.deepEqual(output.width, 0); }); it('return iframe - hspace', function () { assert.deepEqual(output.hspace, '0'); }); it('return iframe - vspace', function () { assert.deepEqual(output.vspace, '0'); }); it('return iframe - marginWidth', function () { assert.deepEqual(output.marginWidth, '0'); }); it('return iframe - marginHeight', function () { assert.deepEqual(output.marginHeight, '0'); }); it('return iframe - scrolling', function () { assert.deepEqual(output.scrolling, 'no'); }); it('return iframe - frameBorder', function () { assert.deepEqual(output.frameBorder, '0'); }); it('return iframe - src', function () { assert.deepEqual(output.src, 'about:blank'); }); it('return iframe - style', function () { assert.ok(output.style); }); }); describe('getHighestCpm', function () { it('should pick the existing highest cpm', function () { let previous = { cpm: 2, timeToRespond: 100 }; let current = { cpm: 1, timeToRespond: 100 }; assert.equal(utils.getHighestCpm(previous, current), previous); }); it('should pick the new highest cpm', function () { let previous = { cpm: 1, timeToRespond: 100 }; let current = { cpm: 2, timeToRespond: 100 }; assert.equal(utils.getHighestCpm(previous, current), current); }); it('should pick the fastest cpm in case of tie', function () { let previous = { cpm: 1, timeToRespond: 100 }; let current = { cpm: 1, timeToRespond: 50 }; assert.equal(utils.getHighestCpm(previous, current), current); }); it('should pick the oldest in case of tie using responseTimeStamp', function () { let previous = { cpm: 1, timeToRespond: 100, responseTimestamp: 1000 }; let current = { cpm: 1, timeToRespond: 50, responseTimestamp: 2000 }; assert.equal(utils.getOldestHighestCpmBid(previous, current), previous); }); it('should pick the latest in case of tie using responseTimeStamp', function () { let previous = { cpm: 1, timeToRespond: 100, responseTimestamp: 1000 }; let current = { cpm: 1, timeToRespond: 50, responseTimestamp: 2000 }; assert.equal(utils.getLatestHighestCpmBid(previous, current), current); }); }); describe('polyfill test', function () { it('should not add polyfill to array', function() { var arr = ['hello', 'world']; var count = 0; for (var key in arr) { count++; } assert.equal(arr.length, count, 'Polyfill test fails'); }); }); describe('delayExecution', function () { it('should execute the core function after the correct number of calls', function () { const callback = sinon.spy(); const delayed = utils.delayExecution(callback, 5); for (let i = 0; i < 4; i++) { delayed(); } assert(callback.notCalled); delayed(3); assert(callback.called) assert.equal(callback.firstCall.args[0], 3); }); }); describe('deepAccess', function() { var obj = { 1: 2, test: { first: 11 } }; it('should allow deep access of object properties', function() { var value1 = utils.deepAccess(obj, 'test'); assert.deepEqual(value1, obj.test); var value2 = utils.deepAccess(obj, 'test.first'); assert.equal(value2, 11); var value3 = utils.deepAccess(obj, '1'); assert.equal(value3, 2); }); it('should allow safe access (returning undefined for missing properties and not throwing exceptions)', function() { var value; assert.doesNotThrow(function() { value = utils.deepAccess(obj, 'test.second.third'); }); assert.equal(value, undefined); }); }); describe('deepSetValue', function() { it('should set existing properties at various depths', function() { const testObj = { prop: 'value', nestedObj: { nestedProp: 'nestedValue' } }; utils.deepSetValue(testObj, 'prop', 'newValue'); assert.equal(testObj.prop, 'newValue'); utils.deepSetValue(testObj, 'nestedObj.nestedProp', 'newNestedValue'); assert.equal(testObj.nestedObj.nestedProp, 'newNestedValue'); }); it('should create object levels between top and bottom of given path if they do not exist', function() { const testObj = {}; utils.deepSetValue(testObj, 'level1.level2', 'value'); assert.notEqual(testObj.level1, undefined); assert.notEqual(testObj.level1.level2, undefined); assert.equal(testObj.level1.level2, 'value'); }); }); describe('getDefinedParams', function () { it('builds an object consisting of defined params', function () { const adUnit = { mediaType: 'video', comeWithMe: 'ifuwant2live', notNeeded: 'do not include', }; const builtObject = utils.getDefinedParams(adUnit, [ 'mediaType', 'comeWithMe' ]); assert.deepEqual(builtObject, { mediaType: 'video', comeWithMe: 'ifuwant2live', }); }); }); describe('deepClone', function () { it('deep copies objects', function () { const adUnit = [{ code: 'swan', mediaTypes: {video: {context: 'outstream'}}, renderer: { render: bid => player.render(bid), url: '/video/renderer.js' }, bids: [{ bidder: 'dharmaInitiative', params: { placementId: '481516', } }], }]; const adUnitCopy = utils.deepClone(adUnit); expect(adUnitCopy[0].renderer.url).to.be.a('string'); expect(adUnitCopy[0].renderer.render).to.be.a('function'); }); }); describe('getUserConfiguredParams', function () { const adUnits = [{ code: 'adUnit1', bids: [{ bidder: 'bidder1', params: { key1: 'value1' } }, { bidder: 'bidder2' }] }]; it('should return params configured', function () { const output = utils.getUserConfiguredParams(adUnits, 'adUnit1', 'bidder1'); const expected = [{ key1: 'value1' }]; assert.deepEqual(output, expected); }); it('should return array containting empty object, if bidder present and no params are configured', function () { const output = utils.getUserConfiguredParams(adUnits, 'adUnit1', 'bidder2'); const expected = [{}]; assert.deepEqual(output, expected); }); it('should return empty array, if bidder is not present', function () { const output = utils.getUserConfiguredParams(adUnits, 'adUnit1', 'bidder3'); const expected = []; assert.deepEqual(output, expected); }); it('should return empty array, if adUnit is not present', function () { const output = utils.getUserConfiguredParams(adUnits, 'adUnit2', 'bidder3'); const expected = []; assert.deepEqual(output, expected); }); }); describe('convertCamelToUnderscore', function () { it('returns converted string value using underscore syntax instead of camelCase', function () { let var1 = 'placementIdTest'; let test1 = utils.convertCamelToUnderscore(var1); expect(test1).to.equal('placement_id_test'); let var2 = 'my_test_value'; let test2 = utils.convertCamelToUnderscore(var2); expect(test2).to.equal(var2); }); }); describe('getAdUnitSizes', function () { it('returns an empty response when adUnits is undefined', function () { let sizes = utils.getAdUnitSizes(); expect(sizes).to.be.undefined; }); it('returns an empty array when invalid data is present in adUnit object', function () { let sizes = utils.getAdUnitSizes({ sizes: 300 }); expect(sizes).to.deep.equal([]); }); it('retuns an array of arrays when reading from adUnit.sizes', function () { let sizes = utils.getAdUnitSizes({ sizes: [300, 250] }); expect(sizes).to.deep.equal([[300, 250]]); sizes = utils.getAdUnitSizes({ sizes: [[300, 250], [300, 600]] }); expect(sizes).to.deep.equal([[300, 250], [300, 600]]); }); it('returns an array of arrays when reading from adUnit.mediaTypes.banner.sizes', function () { let sizes = utils.getAdUnitSizes({ mediaTypes: { banner: { sizes: [300, 250] } } }); expect(sizes).to.deep.equal([[300, 250]]); sizes = utils.getAdUnitSizes({ mediaTypes: { banner: { sizes: [[300, 250], [300, 600]] } } }); expect(sizes).to.deep.equal([[300, 250], [300, 600]]); }); }); describe('URL helpers', function () { describe('parseUrl()', function () { let parsed; beforeEach(function () { parsed = utils.parseUrl('http://example.com:3000/pathname/?search=test&foo=bar&bar=foo%26foo%3Dxxx#hash'); }); it('extracts the protocol', function () { expect(parsed).to.have.property('protocol', 'http'); }); it('extracts the hostname', function () { expect(parsed).to.have.property('hostname', 'example.com'); }); it('extracts the port', function () { expect(parsed).to.have.property('port', 3000); }); it('extracts the pathname', function () { expect(parsed).to.have.property('pathname', '/pathname/'); }); it('extracts the search query', function () { expect(parsed).to.have.property('search'); expect(parsed.search).to.eql({ foo: 'xxx', search: 'test', bar: 'foo', }); }); it('extracts the hash', function () { expect(parsed).to.have.property('hash', 'hash'); }); it('extracts the host', function () { expect(parsed).to.have.property('host', 'example.com:3000'); }); }); describe('parseUrl(url, {noDecodeWholeURL: true})', function () { let parsed; beforeEach(function () { parsed = utils.parseUrl('http://example.com:3000/pathname/?search=test&foo=bar&bar=foo%26foo%3Dxxx#hash', {noDecodeWholeURL: true}); }); it('extracts the search query', function () { expect(parsed).to.have.property('search'); expect(parsed.search).to.eql({ foo: 'bar', search: 'test', bar: 'foo%26foo%3Dxxx', }); }); }); describe('buildUrl()', function () { it('formats an object in to a URL', function () { expect(utils.buildUrl({ protocol: 'http', hostname: 'example.com', port: 3000, pathname: '/pathname/', search: {foo: 'bar', search: 'test', bar: 'foo%26foo%3Dxxx'}, hash: 'hash' })).to.equal('http://example.com:3000/pathname/?foo=bar&search=test&bar=foo%26foo%3Dxxx#hash'); }); it('will use defaults for missing properties', function () { expect(utils.buildUrl({ hostname: 'example.com' })).to.equal('http://example.com'); }); }); describe('parseUrl(url, {decodeSearchAsString: true})', function () { let parsed; beforeEach(function () { parsed = utils.parseUrl('http://example.com:3000/pathname/?search=test&foo=bar&bar=foo%26foo%3Dxxx#hash', {decodeSearchAsString: true}); }); it('extracts the search query', function () { expect(parsed).to.have.property('search'); expect(parsed.search).to.equal('?search=test&foo=bar&bar=foo&foo=xxx'); }); }); }); 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: [''] }]); }); describe('insertElement', function () { it('returns a node at the top of the target by default', function () { const toInsert = document.createElement('div'); const target = document.getElementsByTagName('body')[0]; const inserted = utils.insertElement(toInsert, document, 'body'); expect(inserted).to.equal(target.firstChild); }); it('returns a node at bottom of target if 4th argument is true', function () { const toInsert = document.createElement('div'); const target = document.getElementsByTagName('html')[0]; const inserted = utils.insertElement(toInsert, document, 'html', true); expect(inserted).to.equal(target.lastChild); }); it('returns a node at top of the head if no target is given', function () { const toInsert = document.createElement('div'); const target = document.getElementsByTagName('head')[0]; const inserted = utils.insertElement(toInsert); expect(inserted).to.equal(target.firstChild); }); }); }); describe('isSafariBrowser', function () { let userAgentStub; let userAgent; before(function () { userAgentStub = sinon.stub(navigator, 'userAgent').get(function () { return userAgent; }); }); after(function () { userAgentStub.restore(); }); it('properly detects safari', function () { userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25'; expect(utils.isSafariBrowser()).to.equal(true); }); it('does not flag Chrome on MacOS', function () { userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'; expect(utils.isSafariBrowser()).to.equal(false); }); it('does not flag Chrome iOS', function () { userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/80.0.3987.95 Mobile/15E148 Safari/604.1'; expect(utils.isSafariBrowser()).to.equal(false); }); it('does not flag Firefox iOS', function () { userAgent = 'Mozilla/5.0 (iPhone; CPU OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/23.0 Mobile/15E148 Safari/605.1.15'; expect(utils.isSafariBrowser()).to.equal(false); }); it('does not flag Windows Edge', function () { userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.74 Safari/537.36 Edg/79.0.309.43'; expect(utils.isSafariBrowser()).to.equal(false); }); }); describe('mergeDeep', function() { it('properly merge objects that share same property names', function() { const object1 = { propA: { subPropA: 'abc' } }; const object2 = { propA: { subPropB: 'def' } }; const resultWithoutMergeDeep = Object.assign({}, object1, object2); expect(resultWithoutMergeDeep).to.deep.equal({ propA: { subPropB: 'def' } }); const resultWithMergeDeep = utils.mergeDeep({}, object1, object2); expect(resultWithMergeDeep).to.deep.equal({ propA: { subPropA: 'abc', subPropB: 'def' } }); }); it('properly merge objects that have different depths', function() { const object1 = { depth0_A: { depth1_A: { depth2_A: 123 } } }; const object2 = { depth0_A: { depth1_A: { depth2_B: { depth3_A: { depth4_A: 'def' } } }, depth1_B: 'abc' } }; const object3 = { depth0_B: 456 }; const result = utils.mergeDeep({}, object1, object2, object3); expect(result).to.deep.equal({ depth0_A: { depth1_A: { depth2_A: 123, depth2_B: { depth3_A: { depth4_A: 'def' } } }, depth1_B: 'abc' }, depth0_B: 456 }); }); it('properly merge objects with various property types', function() { const object1 = { depth0_A: { depth1_A: ['a', 'b', 'c'], depth1_B: 'abc', depth1_C: 123 } }; const object2 = { depth0_A: { depth1_A: ['d', 'e', 'f'], depth1_D: true, } }; const result = utils.mergeDeep({}, object1, object2); expect(result).to.deep.equal({ depth0_A: { depth1_A: ['a', 'b', 'c', 'd', 'e', 'f'], depth1_B: 'abc', depth1_C: 123, depth1_D: true, } }); }); }); describe('deepEqual', function() { it('should return "true" if comparing the same object', function() { const obj1 = { banner: { sizeConfig: [ { minViewPort: [0, 0], sizes: [] }, { minViewPort: [1000, 0], sizes: [[1000, 300], [1000, 90], [970, 250], [970, 90], [728, 90]] }, ], }, }; const obj2 = obj1; expect(utils.deepEqual(obj1, obj2)).to.equal(true); }); it('should return "true" if two deeply nested objects are equal', function() { const obj1 = { banner: { sizeConfig: [ { minViewPort: [0, 0], sizes: [] }, { minViewPort: [1000, 0], sizes: [[1000, 300], [1000, 90], [970, 250], [970, 90], [728, 90]] }, ], }, }; const obj2 = { banner: { sizeConfig: [ { minViewPort: [0, 0], sizes: [] }, { minViewPort: [1000, 0], sizes: [[1000, 300], [1000, 90], [970, 250], [970, 90], [728, 90]] }, ], }, }; expect(utils.deepEqual(obj1, obj2)).to.equal(true); }); it('should return "true" if comparting the same primitive values', function() { const primitive1 = 'Prebid.js'; const primitive2 = 'Prebid.js'; expect(utils.deepEqual(primitive1, primitive2)).to.equal(true); }); it('should return "false" if comparing two different primitive values', function() { const primitive1 = 12; const primitive2 = 123; expect(utils.deepEqual(primitive1, primitive2)).to.equal(false); }); it('should return "false" if comparing two different deeply nested objects', function() { const obj1 = { banner: { sizeConfig: [ { minViewPort: [0, 0], sizes: [] }, { minViewPort: [1000, 0], sizes: [[1000, 300], [1000, 90], [970, 250], [970, 90], [728, 90]] }, ], }, }; const obj2 = { banner: { sizeConfig: [ { minViewPort: [0, 0], sizes: [] }, { minViewPort: [1000, 0], sizes: [[1000, 300], [728, 90]] }, ], }, } expect(utils.deepEqual(obj1, obj2)).to.equal(false); }); describe('cyrb53Hash', function() { it('should return the same hash for the same string', function() { const stringOne = 'string1'; expect(utils.cyrb53Hash(stringOne)).to.equal(utils.cyrb53Hash(stringOne)); }); it('should return a different hash for the same string with different seeds', function() { const stringOne = 'string1'; expect(utils.cyrb53Hash(stringOne, 1)).to.not.equal(utils.cyrb53Hash(stringOne, 2)); }); it('should return a different hash for different strings with the same seed', function() { const stringOne = 'string1'; const stringTwo = 'string2'; expect(utils.cyrb53Hash(stringOne)).to.not.equal(utils.cyrb53Hash(stringTwo)); }); it('should return a string value, not a number', function() { const stringOne = 'string1'; expect(typeof utils.cyrb53Hash(stringOne)).to.equal('string'); }); }); }); });