From 76891d30683f0068edadba7a6ca82862a5cfa3a5 Mon Sep 17 00:00:00 2001 From: Okan Sahin Date: Thu, 8 Aug 2024 15:32:05 +0200 Subject: [PATCH 01/10] Require consent --- libs/utils/utils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/utils/utils.js b/libs/utils/utils.js index 2cd929eb77..6349fda3a0 100644 --- a/libs/utils/utils.js +++ b/libs/utils/utils.js @@ -1000,7 +1000,8 @@ export function scrollToHashedElement(hash) { } function logPagePerf() { - if (getMetadata('pageperf') !== 'on') return; + const performanceConsent = document.cookie.split('OptanonConsent')[1]?.includes(encodeURIComponent('C0002:1')); + if (getMetadata('pageperf') !== 'on' || !performanceConsent) return; const isChrome = () => { const nav = window.navigator; return nav.userAgent.includes('Chrome') && nav.vendor.includes('Google'); From a08e327004f9199ab978d43e0667b7d6d3a97ac9 Mon Sep 17 00:00:00 2001 From: Okan Sahin Date: Thu, 8 Aug 2024 15:34:20 +0200 Subject: [PATCH 02/10] Improve the check --- libs/utils/utils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/utils/utils.js b/libs/utils/utils.js index 6349fda3a0..72867b5f81 100644 --- a/libs/utils/utils.js +++ b/libs/utils/utils.js @@ -1000,7 +1000,8 @@ export function scrollToHashedElement(hash) { } function logPagePerf() { - const performanceConsent = document.cookie.split('OptanonConsent')[1]?.includes(encodeURIComponent('C0002:1')); + const consent = document.cookie.split('OptanonConsent')[1]; + const performanceConsent = consent?.includes(encodeURIComponent('C0002:1')) || consent?.includes('C0002:1'); if (getMetadata('pageperf') !== 'on' || !performanceConsent) return; const isChrome = () => { const nav = window.navigator; From 24984b2e301ef55533fd6d44b7e12d80fa394920 Mon Sep 17 00:00:00 2001 From: Okan Sahin <39759830+mokimo@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:39:20 +0200 Subject: [PATCH 03/10] Apply suggestions from code review Co-authored-by: Narcis Radu --- libs/utils/utils.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/utils/utils.js b/libs/utils/utils.js index 72867b5f81..e66480eb01 100644 --- a/libs/utils/utils.js +++ b/libs/utils/utils.js @@ -1000,8 +1000,9 @@ export function scrollToHashedElement(hash) { } function logPagePerf() { - const consent = document.cookie.split('OptanonConsent')[1]; - const performanceConsent = consent?.includes(encodeURIComponent('C0002:1')) || consent?.includes('C0002:1'); + const consent = document.cookie.split('OptanonConsent=')[1]; + const performanceGroup = 'C0002:1'; + const performanceConsent = consent?.includes(encodeURIComponent(performanceGroup)) || consent?.includes(performanceGroup); if (getMetadata('pageperf') !== 'on' || !performanceConsent) return; const isChrome = () => { const nav = window.navigator; From ed4ae2dea118f72c7c6197243ae2a7a9b960eb35 Mon Sep 17 00:00:00 2001 From: Okan Sahin Date: Thu, 8 Aug 2024 15:41:34 +0200 Subject: [PATCH 04/10] Fix linting issues --- libs/utils/utils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/utils/utils.js b/libs/utils/utils.js index e66480eb01..e5846b26a2 100644 --- a/libs/utils/utils.js +++ b/libs/utils/utils.js @@ -1002,7 +1002,8 @@ export function scrollToHashedElement(hash) { function logPagePerf() { const consent = document.cookie.split('OptanonConsent=')[1]; const performanceGroup = 'C0002:1'; - const performanceConsent = consent?.includes(encodeURIComponent(performanceGroup)) || consent?.includes(performanceGroup); + const performanceConsent = consent?.includes(encodeURIComponent(performanceGroup)) + || consent?.includes(performanceGroup); if (getMetadata('pageperf') !== 'on' || !performanceConsent) return; const isChrome = () => { const nav = window.navigator; From b2164c90a3765509734ffe0e493e77f756b9a45b Mon Sep 17 00:00:00 2001 From: Okan Sahin Date: Thu, 8 Aug 2024 15:48:06 +0200 Subject: [PATCH 05/10] Fix linting and unit tests --- test/utils/logWebVitals.test.js | 12 ++++++++++++ test/utils/logWebVitalsUtils.test.js | 14 +++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/test/utils/logWebVitals.test.js b/test/utils/logWebVitals.test.js index 01414945b7..23abab3efb 100644 --- a/test/utils/logWebVitals.test.js +++ b/test/utils/logWebVitals.test.js @@ -6,6 +6,18 @@ import logWebVitals from '../../libs/utils/logWebVitals.js'; document.body.innerHTML = await readFile({ path: './mocks/body.html' }); describe('Log Web Vitals', () => { + before(() => { + let expires = ''; + const date = new Date(); + date.setTime(date.getTime() + (1 * 24 * 60 * 60 * 1000)); + expires = `; expires=${date.toUTCString()}`; + document.cookie = `${'OptanonConsent'}=${encodeURIComponent('C0002:1')}${expires}; path=/`; + }); + + after(() => { + document.cookie = `${'OptanonConsent'}=; Max-Age=-99999999;`; + }); + it('Logs data to lana', (done) => { window.lana = { log: (logStr, logOpts) => { diff --git a/test/utils/logWebVitalsUtils.test.js b/test/utils/logWebVitalsUtils.test.js index 82afe1eb73..7e0fa3e801 100644 --- a/test/utils/logWebVitalsUtils.test.js +++ b/test/utils/logWebVitalsUtils.test.js @@ -11,7 +11,19 @@ document.head.innerHTML = ` document.body.innerHTML = await readFile({ path: './mocks/body.html' }); -describe('Log Web Vitals', () => { +describe('Log Web Vitals Utils', () => { + before(() => { + let expires = ''; + const date = new Date(); + date.setTime(date.getTime() + (1 * 24 * 60 * 60 * 1000)); + expires = `; expires=${date.toUTCString()}`; + document.cookie = `${'OptanonConsent'}=${encodeURIComponent('C0002:1')}${expires}; path=/`; + }); + + after(() => { + document.cookie = `${'OptanonConsent'}=; Max-Age=-99999999;`; + }); + it('Logs data to lana', (done) => { window.lana = { log: (logStr, logOpts) => { From 82a6461e4f4e363b0e79aa277f3c40a4143c4ecf Mon Sep 17 00:00:00 2001 From: Okan Sahin Date: Thu, 8 Aug 2024 15:49:54 +0200 Subject: [PATCH 06/10] Return faster --- libs/utils/utils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/utils/utils.js b/libs/utils/utils.js index e5846b26a2..1f4816c19d 100644 --- a/libs/utils/utils.js +++ b/libs/utils/utils.js @@ -1000,11 +1000,12 @@ export function scrollToHashedElement(hash) { } function logPagePerf() { + if (getMetadata('pageperf') !== 'on') return; const consent = document.cookie.split('OptanonConsent=')[1]; const performanceGroup = 'C0002:1'; const performanceConsent = consent?.includes(encodeURIComponent(performanceGroup)) || consent?.includes(performanceGroup); - if (getMetadata('pageperf') !== 'on' || !performanceConsent) return; + if (!performanceConsent) return; const isChrome = () => { const nav = window.navigator; return nav.userAgent.includes('Chrome') && nav.vendor.includes('Google'); From b9d8f7c173849b8da5b87ac0eb97e4bb798a2eb5 Mon Sep 17 00:00:00 2001 From: Okan Sahin Date: Fri, 9 Aug 2024 12:08:52 +0200 Subject: [PATCH 07/10] Track once consent is given --- libs/utils/logWebVitals.js | 22 +++++++++++++++++----- libs/utils/utils.js | 16 ++++------------ test/utils/logWebVitals.test.js | 11 ++++------- test/utils/logWebVitalsUtils.test.js | 9 +++------ 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/libs/utils/logWebVitals.js b/libs/utils/logWebVitals.js index 8c092fb5e4..f6d39961c2 100644 --- a/libs/utils/logWebVitals.js +++ b/libs/utils/logWebVitals.js @@ -87,9 +87,21 @@ function logMepExperiments(lanaData, mep) { }); } -export default function webVitals(mep, { delay = 1000 } = {}) { - const lanaData = {}; - logMepExperiments(lanaData, mep); - observeCLS(lanaData); - observeLCP(lanaData, delay); +export default function webVitals(mep, { delay = 1000, sampleRate = 50 } = {}) { + const isChrome = () => { + const nav = window.navigator; + return nav.userAgent.includes('Chrome') && nav.vendor.includes('Google'); + }; + if (!isChrome() || Math.random() * 100 > sampleRate) return; + + function handleEvent() { + const performanceConsent = window.adobePrivacy.activeCookieGroups().indexOf('C0002') !== -1; + if (!performanceConsent) return; + const lanaData = {}; + logMepExperiments(lanaData, mep); + observeCLS(lanaData); + observeLCP(lanaData, delay); + } + window.addEventListener('adobePrivacy:PrivacyConsent', handleEvent); + window.addEventListener('adobePrivacy:PrivacyCustom', handleEvent); } diff --git a/libs/utils/utils.js b/libs/utils/utils.js index 1f4816c19d..9b8320377f 100644 --- a/libs/utils/utils.js +++ b/libs/utils/utils.js @@ -1001,19 +1001,11 @@ export function scrollToHashedElement(hash) { function logPagePerf() { if (getMetadata('pageperf') !== 'on') return; - const consent = document.cookie.split('OptanonConsent=')[1]; - const performanceGroup = 'C0002:1'; - const performanceConsent = consent?.includes(encodeURIComponent(performanceGroup)) - || consent?.includes(performanceGroup); - if (!performanceConsent) return; - const isChrome = () => { - const nav = window.navigator; - return nav.userAgent.includes('Chrome') && nav.vendor.includes('Google'); - }; - const sampleRate = parseInt(getMetadata('pageperf-rate'), 10) || 50; - if (!isChrome() || Math.random() * 100 > sampleRate) return; import('./logWebVitals.js') - .then((mod) => mod.default(getConfig().mep, getMetadata('pageperf-delay') || 1000)); + .then((mod) => mod.default(getConfig().mep, { + delay: getMetadata('pageperf-delay') || 1000, + sampleRate: parseInt(getMetadata('pageperf-rate'), 10) || 50, + })); } export async function loadDeferred(area, blocks, config) { diff --git a/test/utils/logWebVitals.test.js b/test/utils/logWebVitals.test.js index 23abab3efb..e04db9805a 100644 --- a/test/utils/logWebVitals.test.js +++ b/test/utils/logWebVitals.test.js @@ -7,15 +7,11 @@ document.body.innerHTML = await readFile({ path: './mocks/body.html' }); describe('Log Web Vitals', () => { before(() => { - let expires = ''; - const date = new Date(); - date.setTime(date.getTime() + (1 * 24 * 60 * 60 * 1000)); - expires = `; expires=${date.toUTCString()}`; - document.cookie = `${'OptanonConsent'}=${encodeURIComponent('C0002:1')}${expires}; path=/`; + window.adobePrivacy = { activeCookieGroups: () => ['C0002'] }; }); after(() => { - document.cookie = `${'OptanonConsent'}=; Max-Age=-99999999;`; + delete window.adobePrivacy; }); it('Logs data to lana', (done) => { @@ -52,7 +48,8 @@ describe('Log Web Vitals', () => { done(); }, }; - logWebVitals(mepObject, { delay: 0 }); + logWebVitals(mepObject, { delay: 0, sampleRate: 100 }); + window.dispatchEvent(new Event('adobePrivacy:PrivacyCustom')); }); }); diff --git a/test/utils/logWebVitalsUtils.test.js b/test/utils/logWebVitalsUtils.test.js index 7e0fa3e801..39f0c1ca98 100644 --- a/test/utils/logWebVitalsUtils.test.js +++ b/test/utils/logWebVitalsUtils.test.js @@ -13,15 +13,11 @@ document.body.innerHTML = await readFile({ path: './mocks/body.html' }); describe('Log Web Vitals Utils', () => { before(() => { - let expires = ''; - const date = new Date(); - date.setTime(date.getTime() + (1 * 24 * 60 * 60 * 1000)); - expires = `; expires=${date.toUTCString()}`; - document.cookie = `${'OptanonConsent'}=${encodeURIComponent('C0002:1')}${expires}; path=/`; + window.adobePrivacy = { activeCookieGroups: () => ['C0002'] }; }); after(() => { - document.cookie = `${'OptanonConsent'}=; Max-Age=-99999999;`; + delete window.adobePrivacy; }); it('Logs data to lana', (done) => { @@ -55,6 +51,7 @@ describe('Log Web Vitals Utils', () => { }, }; loadDeferred(document, undefined, getConfig()); + window.dispatchEvent(new Event('adobePrivacy:PrivacyCustom')); }).timeout(5000); }); From bb712050911d270b62090f69191349ced18ef045 Mon Sep 17 00:00:00 2001 From: Okan Sahin Date: Fri, 9 Aug 2024 12:20:53 +0200 Subject: [PATCH 08/10] Fix unit tests --- libs/utils/utils.js | 17 +++++++---------- test/utils/logWebVitalsUtils.test.js | 6 +++++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/libs/utils/utils.js b/libs/utils/utils.js index 9b8320377f..dc960aaddf 100644 --- a/libs/utils/utils.js +++ b/libs/utils/utils.js @@ -999,15 +999,6 @@ export function scrollToHashedElement(hash) { }); } -function logPagePerf() { - if (getMetadata('pageperf') !== 'on') return; - import('./logWebVitals.js') - .then((mod) => mod.default(getConfig().mep, { - delay: getMetadata('pageperf-delay') || 1000, - sampleRate: parseInt(getMetadata('pageperf-rate'), 10) || 50, - })); -} - export async function loadDeferred(area, blocks, config) { const event = new Event(MILO_EVENTS.DEFERRED); area.dispatchEvent(event); @@ -1036,7 +1027,13 @@ export async function loadDeferred(area, blocks, config) { sampleRUM.observe(area.querySelectorAll('picture > img')); }); - logPagePerf(); + if (getMetadata('pageperf') === 'on') { + import('./logWebVitals.js') + .then((mod) => mod.default(getConfig().mep, { + delay: getMetadata('pageperf-delay') || 1000, + sampleRate: parseInt(getMetadata('pageperf-rate'), 10) || 50, + })); + } } function initSidekick() { diff --git a/test/utils/logWebVitalsUtils.test.js b/test/utils/logWebVitalsUtils.test.js index 39f0c1ca98..3028a4b89b 100644 --- a/test/utils/logWebVitalsUtils.test.js +++ b/test/utils/logWebVitalsUtils.test.js @@ -12,12 +12,17 @@ document.head.innerHTML = ` document.body.innerHTML = await readFile({ path: './mocks/body.html' }); describe('Log Web Vitals Utils', () => { + let intervalId; before(() => { window.adobePrivacy = { activeCookieGroups: () => ['C0002'] }; + intervalId = setInterval(() => { + window.dispatchEvent(new Event('adobePrivacy:PrivacyCustom')); + }, 100); }); after(() => { delete window.adobePrivacy; + clearInterval(intervalId); }); it('Logs data to lana', (done) => { @@ -51,7 +56,6 @@ describe('Log Web Vitals Utils', () => { }, }; loadDeferred(document, undefined, getConfig()); - window.dispatchEvent(new Event('adobePrivacy:PrivacyCustom')); }).timeout(5000); }); From a776a93076fef6124f5455c329e0bc43be6de787 Mon Sep 17 00:00:00 2001 From: Okan Sahin Date: Fri, 9 Aug 2024 12:55:32 +0200 Subject: [PATCH 09/10] Remove defaults --- libs/utils/logWebVitals.js | 9 ++++++--- libs/utils/utils.js | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/libs/utils/logWebVitals.js b/libs/utils/logWebVitals.js index f6d39961c2..d988f55ae9 100644 --- a/libs/utils/logWebVitals.js +++ b/libs/utils/logWebVitals.js @@ -93,15 +93,18 @@ export default function webVitals(mep, { delay = 1000, sampleRate = 50 } = {}) { return nav.userAgent.includes('Chrome') && nav.vendor.includes('Google'); }; if (!isChrome() || Math.random() * 100 > sampleRate) return; - + const getConsent = () => window.adobePrivacy?.activeCookieGroups().indexOf('C0002') !== -1; function handleEvent() { - const performanceConsent = window.adobePrivacy.activeCookieGroups().indexOf('C0002') !== -1; - if (!performanceConsent) return; + if (!getConsent()) return; const lanaData = {}; logMepExperiments(lanaData, mep); observeCLS(lanaData); observeLCP(lanaData, delay); } + if (getConsent()) { + handleEvent(); + return; + } window.addEventListener('adobePrivacy:PrivacyConsent', handleEvent); window.addEventListener('adobePrivacy:PrivacyCustom', handleEvent); } diff --git a/libs/utils/utils.js b/libs/utils/utils.js index dc960aaddf..e7cacd9dff 100644 --- a/libs/utils/utils.js +++ b/libs/utils/utils.js @@ -1030,8 +1030,8 @@ export async function loadDeferred(area, blocks, config) { if (getMetadata('pageperf') === 'on') { import('./logWebVitals.js') .then((mod) => mod.default(getConfig().mep, { - delay: getMetadata('pageperf-delay') || 1000, - sampleRate: parseInt(getMetadata('pageperf-rate'), 10) || 50, + delay: getMetadata('pageperf-delay'), + sampleRate: parseInt(getMetadata('pageperf-rate'), 10), })); } } From 3407dd4ea164b1d1d5608967ef6057d1e4f153d6 Mon Sep 17 00:00:00 2001 From: Okan Sahin Date: Fri, 9 Aug 2024 12:58:54 +0200 Subject: [PATCH 10/10] Only listen to privacy once. --- libs/utils/logWebVitals.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/utils/logWebVitals.js b/libs/utils/logWebVitals.js index d988f55ae9..a7e4bc39a5 100644 --- a/libs/utils/logWebVitals.js +++ b/libs/utils/logWebVitals.js @@ -105,6 +105,6 @@ export default function webVitals(mep, { delay = 1000, sampleRate = 50 } = {}) { handleEvent(); return; } - window.addEventListener('adobePrivacy:PrivacyConsent', handleEvent); - window.addEventListener('adobePrivacy:PrivacyCustom', handleEvent); + window.addEventListener('adobePrivacy:PrivacyConsent', handleEvent, { once: true }); + window.addEventListener('adobePrivacy:PrivacyCustom', handleEvent, { once: true }); }