it('should return false with input object', function () { var output = utils.isFn(obj_object); 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 number', function () { var output = utils.isFn(obj_number); assert.deepEqual(output, false); });
it('should return false with input string', function () { var output = utils.isFn(obj_string); assert.deepEqual(output, false); });
it('should return true with input function', function () { var output = utils.isFn(obj_function); assert.deepEqual(output, true); });
/** * This function handles interacting with an IAB compliant CMP to obtain the consent information of the user. * Given the async nature of the CMP's API, we pass in acting success/error callback functions to exit this function * based on the appropriate result. * @param {function(string)} cmpSuccess acts as a success callback when CMP returns a value; pass along consentObject (string) from CMP * @param {function(string)} cmpError acts as an error callback while interacting with CMP; pass along an error message (string) * @param {object} hookConfig contains module related variables (see comment in requestBidsHook function) */ function lookupIabConsent(cmpSuccess, cmpError, hookConfig) { function handleCmpResponseCallbacks() { const cmpResponse = {}; function afterEach() { if (cmpResponse.getConsentData && cmpResponse.getVendorConsents) { cmpSuccess(cmpResponse, hookConfig); } } return { consentDataCallback: function(consentResponse) { cmpResponse.getConsentData = consentResponse; afterEach(); }, vendorConsentsCallback: function(consentResponse) { cmpResponse.getVendorConsents = consentResponse; afterEach(); } } } let callbackHandler = handleCmpResponseCallbacks(); let cmpCallbacks = {}; let cmpFunction; // to collect the consent information from the user, we perform two calls to the CMP in parallel: // first to collect the user's consent choices represented in an encoded string (via getConsentData) // second to collect the user's full unparsed consent information (via getVendorConsents) // the following code also determines where the CMP is located and uses the proper workflow to communicate with it: // check to see if CMP is found on the same window level as prebid and call it directly if so // check to see if prebid is in a safeframe (with CMP support) // else assume prebid may be inside an iframe and use the IAB CMP locator code to see if CMP's located in a higher parent window. this works in cross domain iframes // if the CMP is not found, the iframe function will call the cmpError exit callback to abort the rest of the CMP workflow try { cmpFunction = window.__cmp || utils.getWindowTop().__cmp; } catch (e) {} if (utils.isFn(cmpFunction)) { cmpFunction('getConsentData', null, callbackHandler.consentDataCallback); cmpFunction('getVendorConsents', null, callbackHandler.vendorConsentsCallback); } else if (inASafeFrame() && typeof window.$sf.ext.cmp === 'function') { callCmpWhileInSafeFrame('getConsentData', callbackHandler.consentDataCallback); callCmpWhileInSafeFrame('getVendorConsents', callbackHandler.vendorConsentsCallback); } else { // find the CMP frame let f = window; let cmpFrame; while (!cmpFrame) { try { if (f.frames['__cmpLocator']) cmpFrame = f; } catch (e) {} if (f === window.top) break; f = f.parent; } if (!cmpFrame) { return cmpError('CMP not found.', hookConfig); } callCmpWhileInIframe('getConsentData', cmpFrame, callbackHandler.consentDataCallback); callCmpWhileInIframe('getVendorConsents', cmpFrame, callbackHandler.vendorConsentsCallback); } function inASafeFrame() { return !!(window.$sf && window.$sf.ext); } function callCmpWhileInSafeFrame(commandName, callback) { function sfCallback(msgName, data) { if (msgName === 'cmpReturn') { let responseObj = (commandName === 'getConsentData') ? data.vendorConsentData : data.vendorConsents; callback(responseObj); } } // find sizes from adUnits object let adUnits = hookConfig.adUnits; let width = 1; let height = 1; if (Array.isArray(adUnits) && adUnits.length > 0) { let sizes = utils.getAdUnitSizes(adUnits[0]); width = sizes[0][0]; height = sizes[0][1]; } window.$sf.ext.register(width, height, sfCallback); window.$sf.ext.cmp(commandName); } function callCmpWhileInIframe(commandName, cmpFrame, moduleCallback) { /* Setup up a __cmp function to do the postMessage and stash the callback. This function behaves (from the caller's perspective identicially to the in-frame __cmp call */ window.__cmp = function(cmd, arg, callback) { let callId = Math.random() + ''; let msg = {__cmpCall: { command: cmd, parameter: arg, callId: callId }}; cmpCallbacks[callId] = callback; cmpFrame.postMessage(msg, '*'); } /** when we get the return message, call the stashed callback */ window.addEventListener('message', readPostMessageResponse, false); // call CMP window.__cmp(commandName, null, cmpIframeCallback); function readPostMessageResponse(event) { let json = (typeof event.data === 'string' && strIncludes(event.data, 'cmpReturn')) ? JSON.parse(event.data) : event.data; if (json.__cmpReturn && json.__cmpReturn.callId) { let i = json.__cmpReturn; // TODO - clean up this logic (move listeners?); we have duplicate messages responses because 2 eventlisteners are active from the 2 cmp requests running in parallel if (typeof cmpCallbacks[i.callId] !== 'undefined') { cmpCallbacks[i.callId](i.returnValue, i.success); delete cmpCallbacks[i.callId]; } } } function removePostMessageListener() { window.removeEventListener('message', readPostMessageResponse, false); } function cmpIframeCallback(consentObject) { removePostMessageListener(); moduleCallback(consentObject); } } }