From 7c52c5586323a591e8a29b5c0739aa0b29ec1ffb Mon Sep 17 00:00:00 2001 From: Konrad Dzwinel Date: Mon, 11 Oct 2021 16:55:29 +0200 Subject: [PATCH] Test Automation - clean up (#61) * result->value for consistency * Flatten test results, separate value from error message. * result -> value for consistency * Referrer trimming - flatten results object. * Expose click-to-play results in a global variable. Move JS from HTML to a JS file. --- privacy-protections/click-to-load/index.html | 83 +-------------- privacy-protections/click-to-load/main.js | 100 ++++++++++++++++++ privacy-protections/referrer-trimming/main.js | 47 ++++---- .../storage-blocking/iframe.js | 18 ++-- privacy-protections/storage-blocking/main.js | 33 +++--- 5 files changed, 160 insertions(+), 121 deletions(-) create mode 100644 privacy-protections/click-to-load/main.js diff --git a/privacy-protections/click-to-load/index.html b/privacy-protections/click-to-load/index.html index f3a694e..0c6d253 100644 --- a/privacy-protections/click-to-load/index.html +++ b/privacy-protections/click-to-load/index.html @@ -56,88 +56,7 @@

Objects in iFrames

Groups don't currently allow iFrame displays, but the documentation still shows this as a valid method of showing groups, so it's included here in case it changes again in the future


- + diff --git a/privacy-protections/click-to-load/main.js b/privacy-protections/click-to-load/main.js new file mode 100644 index 0000000..6ec0789 --- /dev/null +++ b/privacy-protections/click-to-load/main.js @@ -0,0 +1,100 @@ +let facebookCalls = 0; +let fbIFrames = 0; + +// object that contains results of all tests +const results = { + page: 'facebook-click-to-load', + date: (new Date()).toUTCString(), + results: [] +}; + +function updateResults () { + results.results = [ + { + id: 'facebookCalls', + value: facebookCalls + }, + { + id: 'fbIFrames', + value: fbIFrames + } + ]; + + document.getElementById('facebook_iFrames').innerHTML = fbIFrames; + document.getElementById('facebook_call_count').innerHTML = facebookCalls; +} + +// Find all the iFrames currently on page. +const frameNodes = document.querySelectorAll('iFrame'); +fbIFrames = frameNodes.length; +updateResults(); + +// This initializes the facebook SDK. +window.fbAsyncInit = function () { + // eslint-disable-next-line no-undef + FB.init({ + appId: '', + autoLogAppEvents: true, + xfbml: true, + version: 'v9.0' + }); + + function fbLogin () { + const displayArea = document.getElementById('loginResponse'); + displayArea.innerHTML = 'Calling FB SDK... '; + // eslint-disable-next-line no-undef + FB.login(function (response) { + if (response.authResponse) { + displayArea.innerHTML = 'Starting FB login... '; + // eslint-disable-next-line no-undef + FB.api('/me', function (response) { + displayArea.innerHTML = `Logged in as ${response.name}`; + }); + } else { + displayArea.innerHTML = 'User cancelled login or did not fully authorize.'; + } + }); + } + + const loginButton = document.getElementById('custom-fb-login-button'); + loginButton.addEventListener('click', fbLogin); +}; + +function facebookObserver (list, observer) { + const resourceLoads = list.getEntriesByType('resource'); + for (const resource of resourceLoads) { + if (resource.name.match(/facebook.com|facebook.net/)) { + /* Observer still counts calls that fail, but the duration is less. In testing, + * failed iFrames always returned in around 100 or less, with success generally being + * above 200. Occasionally, a loaded resource comes in around 150. If Facebook requests + * are allowed, there will also be other resources that load - scripts and content + * which will always be counted. + */ + if (resource.initiatorType !== 'iframe' || resource.duration > 150) { + facebookCalls += 1; + } + } + } + + updateResults(); +} + +const observer = new PerformanceObserver(facebookObserver); +observer.observe({ entryTypes: ['resource'] }); + +function downloadTheResults () { + const data = JSON.stringify(results); + const a = document.createElement('a'); + const url = window.URL.createObjectURL(new Blob([data], { type: 'application/json' })); + a.href = url; + a.download = 'facebook-click-to-load-results.json'; + + document.body.appendChild(a); + a.click(); + + window.URL.revokeObjectURL(url); + a.remove(); +} + +const downloadButton = document.querySelector('#download'); +downloadButton.addEventListener('click', () => downloadTheResults()); diff --git a/privacy-protections/referrer-trimming/main.js b/privacy-protections/referrer-trimming/main.js index ea4eed6..0ecde34 100644 --- a/privacy-protections/referrer-trimming/main.js +++ b/privacy-protections/referrer-trimming/main.js @@ -26,11 +26,11 @@ function generateNavigationTest (url) { const result = [ { test: 'js', - result: currentURL.searchParams.get('js') + value: currentURL.searchParams.get('js') }, { test: 'header', - result: currentURL.searchParams.get('header') + value: currentURL.searchParams.get('header') } ]; localStorage.setItem(key, JSON.stringify(result)); @@ -148,13 +148,14 @@ function runTests () { testsSummaryDiv.innerText = `Performed ${all} tests${failed > 0 ? ` (${failed} failed)` : ''}. Click for details.`; } - for (const test of tests) { - const resultObj = { - id: test.id, - value: null - }; - results.results.push(resultObj); + function addTestResult (testId, value) { + results.results.push({ + id: testId, + value: value + }); + } + for (const test of tests) { const li = document.createElement('li'); li.id = `test-${test.id.replace(' ', '-')}`; li.innerHTML = `${test.id} - `; @@ -172,30 +173,40 @@ function runTests () { result .then(data => { if (Array.isArray(data)) { - valueSpan.innerHTML = ``; - } else if (data) { - valueSpan.innerHTML = JSON.stringify(data, null, 2); - } + valueSpan.innerHTML = ``; + + data.forEach(item => addTestResult(`${test.id} - ${item.test}`, item.result)); + } else { + if (data) { + valueSpan.innerHTML = JSON.stringify(data, null, 2); + } - resultObj.value = data; + addTestResult(test.id, data); + } }) .catch(e => { failed++; valueSpan.innerHTML = `❌ error thrown ("${e.message ? e.message : e}")`; + addTestResult(test.id, null); updateSummary(); }); } else { if (Array.isArray(result)) { - valueSpan.innerHTML = ``; - } else if (result) { - valueSpan.innerHTML = JSON.stringify(result, null, 2); - } + valueSpan.innerHTML = ``; - resultObj.value = result || null; + result.forEach(item => addTestResult(`${test.id} - ${item.test}`, item.value)); + } else { + if (result) { + valueSpan.innerHTML = JSON.stringify(result, null, 2); + } + + addTestResult(test.id, result || null); + } } } catch (e) { failed++; valueSpan.innerHTML = `❌ error thrown ("${e.message ? e.message : e}")`; + addTestResult(test.id, null); } all++; diff --git a/privacy-protections/storage-blocking/iframe.js b/privacy-protections/storage-blocking/iframe.js index a27044e..4c5ad4d 100644 --- a/privacy-protections/storage-blocking/iframe.js +++ b/privacy-protections/storage-blocking/iframe.js @@ -9,22 +9,22 @@ function storeData (randomNumber) { return result .then(() => ({ test: test.id, - result: 'OK' + value: 'OK' })) .catch(e => ({ test: test.id, - result: e.message + value: e.message })); } else { return Promise.resolve({ test: test.id, - result: 'OK' + value: 'OK' }); } } catch (e) { return Promise.resolve({ test: test.id, - result: e.message ? e.message : e + value: e.message ? e.message : e }); } })); @@ -39,22 +39,24 @@ function retrieveData () { return result .then(value => ({ test: test.id, - result: value + value: value })) .catch(e => ({ test: test.id, - result: e.message + value: null, + error: e.message })); } else { return Promise.resolve({ test: test.id, - result: result + value: result }); } } catch (e) { return Promise.resolve({ test: test.id, - result: e.message ? e.message : e + value: null, + error: e.message ? e.message : e }); } })); diff --git a/privacy-protections/storage-blocking/main.js b/privacy-protections/storage-blocking/main.js index 64a59c4..1661bc6 100644 --- a/privacy-protections/storage-blocking/main.js +++ b/privacy-protections/storage-blocking/main.js @@ -231,7 +231,7 @@ function storeData () { result .then(result => { if (Array.isArray(result)) { - valueSpan.innerHTML = ``; + valueSpan.innerHTML = ``; } else if (result && result !== 'OK') { valueSpan.innerHTML = JSON.stringify(result, null, 2); } else { @@ -271,15 +271,16 @@ function retrieveData () { testsSummaryDiv.innerText = `Retrieved data from ${all} storage mechanisms${failed > 0 ? ` (${failed} failed)` : ''}. Click for details.`; } + function addTestResult (testId, value) { + results.results.push({ + id: testId, + value: value + }); + } + tests.concat(commonTests).forEach(test => { all++; - const resultObj = { - id: test.id, - value: null - }; - results.results.push(resultObj); - const li = document.createElement('li'); li.id = `test-${test.id.replace(' ', '-')}`; li.innerHTML = `${test.id} - `; @@ -294,25 +295,31 @@ function retrieveData () { result .then(data => { if (Array.isArray(data)) { - valueSpan.innerHTML = ``; - } else if (data) { - valueSpan.innerHTML = JSON.stringify(data, null, 2); - } + valueSpan.innerHTML = ``; + + data.forEach(item => addTestResult(`${test.id} - ${item.test}`, item.value)); + } else { + if (data) { + valueSpan.innerHTML = JSON.stringify(data, null, 2); + } - resultObj.value = data; + addTestResult(test.id, data); + } }) .catch(e => { failed++; valueSpan.innerHTML = `❌ error thrown ("${e.message ? e.message : e}")`; + addTestResult(test.id, null); updateSummary(); }); } else { valueSpan.innerText = JSON.stringify(result, null, 2) || undefined; - resultObj.value = result || null; + addTestResult(test.id, result || null); } } catch (e) { failed++; valueSpan.innerHTML = `❌ error thrown ("${e.message ? e.message : e}")`; + addTestResult(test.id, null); } });