diff --git a/.circleci/config.yml b/.circleci/config.yml index be9e4bbe..fa67cb33 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,8 +7,8 @@ jobs: build: docker: # specify the version you desire here - - image: circleci/node:8.9.0 - + - image: circleci/node:14.18.2-browsers + # Specify service dependencies here if necessary # CircleCI maintains a library of pre-built images # documented at https://circleci.com/docs/2.0/circleci-images/ @@ -45,6 +45,6 @@ jobs: # Run the file with user's access key ./BrowserStackLocal ${BROWSERSTACK_ACCESS_KEY} & # run tests! - - run: + - run: name: BrowserStack testing command: gulp test --browserstack diff --git a/browsers.json b/browsers.json index c34d4a66..1d58c0d1 100644 --- a/browsers.json +++ b/browsers.json @@ -1,66 +1,50 @@ { - "bs_edge_16_windows_10": { + "bs_edge_latest_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "edge", - "browser_version": "16.0", + "browser_version": "latest", "device": null, "os": "Windows" }, - "bs_edge_17_windows_10": { - "base": "BrowserStack", - "os_version": "10", - "browser": "edge", - "browser_version": "17.0", - "device": null, - "os": "Windows" - }, - "bs_ie_11_windows_10": { - "base": "BrowserStack", - "os_version": "10", - "browser": "ie", - "browser_version": "11.0", - "device": null, - "os": "Windows" - }, - "bs_chrome_76_windows_10": { + "bs_chrome_latest_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "chrome", - "browser_version": "76.0", + "browser_version": "latest", "device": null, "os": "Windows" }, - "bs_chrome_77_windows_10": { + "bs_chrome_87_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "chrome", - "browser_version": "77.0", + "browser_version": "87.0", "device": null, "os": "Windows" }, - "bs_firefox_68_windows_10": { + "bs_firefox_latest_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "firefox", - "browser_version": "68.0", + "browser_version": "latest", "device": null, "os": "Windows" }, - "bs_firefox_69_windows_10": { + "bs_safari_latest_mac_bigsur": { "base": "BrowserStack", - "os_version": "10", - "browser": "firefox", - "browser_version": "69.0", + "os_version": "Big Sur", + "browser": "safari", + "browser_version": "latest", "device": null, - "os": "Windows" + "os": "OS X" }, - "bs_safari_12.1_mac_mojave": { + "bs_safari_15_catalina": { "base": "BrowserStack", - "os_version": "Mojave", + "os_version": "Catalina", "browser": "safari", - "browser_version": "12.1", + "browser_version": "13.1", "device": null, "os": "OS X" } -} \ No newline at end of file +} diff --git a/src/nativeAssetManager.js b/src/nativeAssetManager.js index 3a0d9f7c..d878a791 100644 --- a/src/nativeAssetManager.js +++ b/src/nativeAssetManager.js @@ -161,14 +161,14 @@ export function newNativeAssetManager(win, pubUrl) { } function loadMobileAssets(tagData, cb) { - const placeholders = scanForPlaceholders(); + const placeholders = scanDOMForPlaceHolders(); if (placeholders.length > 0) { callback = cb; requestAssetsFromCache(tagData); } } - function pbNativeDataHasValidType() { + function hasPbNativeData() { return typeof win.pbNativeData !== 'undefined' } @@ -180,16 +180,16 @@ export function newNativeAssetManager(win, pubUrl) { * to retrieve native assets that have a value on the corresponding bid */ function loadAssets(adId, cb) { - const placeholders = scanForPlaceholders(adId); + const placeholders = scanDOMForPlaceHolders(adId); - if (pbNativeDataHasValidType() && win.pbNativeData.hasOwnProperty('assetsToReplace')) { + if (hasPbNativeData() && win.pbNativeData.hasOwnProperty('assetsToReplace')) { win.pbNativeData.assetsToReplace.forEach((asset) => { const key = (asset.match(/hb_native_/i)) ? asset : NATIVE_KEYS[asset]; if (key) {placeholders.push(key);} }); } - if (pbNativeDataHasValidType() && win.pbNativeData.hasOwnProperty('requestAllAssets') && win.pbNativeData.requestAllAssets) { + if (hasPbNativeData() && win.pbNativeData.hasOwnProperty('requestAllAssets') && win.pbNativeData.requestAllAssets) { callback = cb; cancelMessageListener = requestAllAssets(adId); } else if (placeholders.length > 0) { @@ -198,24 +198,29 @@ export function newNativeAssetManager(win, pubUrl) { } } + function placeholderFor(key, adId) { + return (adId && !hasPbNativeData()) ? `${key}:${adId}` : ((hasPbNativeData()) ? `##${key}##` : key) + } + + function scanForPlaceHolders(adId, ...markupFragments) { + return Object.values(NATIVE_KEYS) + .reduce((found, key) => { + const placeholder = placeholderFor(key, adId); + for (const mkup of markupFragments.filter(Boolean)) { + if (mkup.indexOf(placeholder) >= 0) { + found.push(key); + break; + } + } + return found; + }, []); + } + /* * Searches the DOM for placeholder values sent in by Prebid Native */ - function scanForPlaceholders(adId) { - let placeholders = []; - const doc = win.document; - - Object.keys(NATIVE_KEYS).forEach(key => { - const placeholderKey = NATIVE_KEYS[key]; - const placeholder = (adId && !pbNativeDataHasValidType()) ? `${placeholderKey}:${adId}` : `${placeholderKey}`; - const placeholderIndex = (~doc.body.innerHTML.indexOf(placeholder)) ? doc.body.innerHTML.indexOf(placeholder) : (doc.head.innerHTML && doc.head.innerHTML.indexOf(placeholder)); - - if (~placeholderIndex) { - placeholders.push(placeholderKey); - } - }); - - return placeholders; + function scanDOMForPlaceHolders(adId) { + return scanForPlaceHolders(adId, win.document.body.innerHTML, win.document.head.innerHTML); } /* @@ -281,13 +286,12 @@ export function newNativeAssetManager(win, pubUrl) { if (data.message === 'assetResponse') { const body = win.document.body.innerHTML; const head = win.document.head.innerHTML; - const flag = pbNativeDataHasValidType(); - if (flag && data.adId !== win.pbNativeData.adId) return; + if (hasPbNativeData() && data.adId !== win.pbNativeData.adId) return; if (head) win.document.head.innerHTML = replace(head, data); - if ((data.hasOwnProperty('rendererUrl') && data.rendererUrl) || (flag && win.pbNativeData.hasOwnProperty('rendererUrl'))) { + if ((data.hasOwnProperty('rendererUrl') && data.rendererUrl) || (hasPbNativeData() && win.pbNativeData.hasOwnProperty('rendererUrl'))) { if (win.renderAd) { const newHtml = (win.renderAd && win.renderAd(data.assets)) || ''; @@ -305,7 +309,7 @@ export function newNativeAssetManager(win, pubUrl) { requestHeightResize(data.adId, (document.body.clientHeight || document.body.offsetHeight)); }); } else { - loadScript(win, ((flag && win.pbNativeData.hasOwnProperty('rendererUrl') && win.pbNativeData.rendererUrl) || data.rendererUrl), function() { + loadScript(win, ((hasPbNativeData() && win.pbNativeData.hasOwnProperty('rendererUrl') && win.pbNativeData.rendererUrl) || data.rendererUrl), function() { const newHtml = (win.renderAd && win.renderAd(data.assets)) || ''; win.document.body.innerHTML = body + newHtml; @@ -314,8 +318,8 @@ export function newNativeAssetManager(win, pubUrl) { requestHeightResize(data.adId, (document.body.clientHeight || document.body.offsetHeight)); }) } - } else if ((data.hasOwnProperty('adTemplate') && data.adTemplate)||(flag && win.pbNativeData.hasOwnProperty('adTemplate'))) { - const template = (flag && win.pbNativeData.hasOwnProperty('adTemplate') && win.pbNativeData.adTemplate) || data.adTemplate; + } else if ((data.hasOwnProperty('adTemplate') && data.adTemplate)||(hasPbNativeData() && win.pbNativeData.hasOwnProperty('adTemplate'))) { + const template = (hasPbNativeData() && win.pbNativeData.hasOwnProperty('adTemplate') && win.pbNativeData.adTemplate) || data.adTemplate; const newHtml = replace(template, data); win.document.body.innerHTML = body + newHtml; callback && callback(); @@ -336,12 +340,11 @@ export function newNativeAssetManager(win, pubUrl) { * in the given document. * If there's no actual value, the placeholder gets replaced by an empty string. */ - function replace(document, { assets, adId }) { - let html = document; + function replace(html, { assets, adId }) { + assets = assets || []; - scanForPlaceholders().forEach(placeholder => { - const flag = pbNativeDataHasValidType(); - const searchString = (adId && !flag) ? `${placeholder}:${adId}` : ((flag) ? '##'+`${placeholder}`+'##' : `${placeholder}`); + scanForPlaceHolders(adId, html).forEach(placeholder => { + const searchString = placeholderFor(placeholder, adId); const searchStringRegex = new RegExp(searchString, 'g'); const fittingAsset = assets.find(asset => placeholder === NATIVE_KEYS[asset.key]); html = html.replace(searchStringRegex, fittingAsset ? fittingAsset.value : ''); diff --git a/test/spec/nativeAssetManager_spec.js b/test/spec/nativeAssetManager_spec.js index e3e1a88f..5e78c694 100644 --- a/test/spec/nativeAssetManager_spec.js +++ b/test/spec/nativeAssetManager_spec.js @@ -437,8 +437,8 @@ describe('nativeAssetManager', () => { expect(win.document.body.innerHTML).to.include(` Click Here `); - // cta was not a requested asset so this should stay as is - expect(win.document.body.innerHTML).to.include('