From 33150d49974b614a60cdaa2a41fa085d0f411379 Mon Sep 17 00:00:00 2001 From: Robert Bogos <146744221+robert-bogos@users.noreply.github.com> Date: Mon, 4 Dec 2023 11:26:28 +0200 Subject: [PATCH] MWPW-138577: Global footer logging (#1514) * feat: footer unit tests * feat: unit tests for mobile, tablet, and wide screen layouts * hotfix * optimizing * feat: added lana logging to the global-footer * hotfix * hotfix * feat: added unit tests for footer logging * Improving Code Readability * hotfix * hotfix: added link for favicon * hotfix * hotfix * increased branches code coverage * hotfixes * increased branches code coverage for global footer * unit tests for global footer logs * fixed rebase error * fixed sinon sub error on global footer tests * mocked ims for gnav.js unit tests * hotfix * optimizing * added unit test for logs when footer cannot be instantiated * optimizing --------- Co-authored-by: Narcis Radu Co-authored-by: Blaine Gunn --- libs/blocks/global-footer/global-footer.js | 26 +++++-- .../global-footer/global-footer.test.js | 70 ++++++++++++++++++- 2 files changed, 87 insertions(+), 9 deletions(-) diff --git a/libs/blocks/global-footer/global-footer.js b/libs/blocks/global-footer/global-footer.js index 1757c5aaae..ad3012684b 100644 --- a/libs/blocks/global-footer/global-footer.js +++ b/libs/blocks/global-footer/global-footer.js @@ -15,6 +15,8 @@ import { getAnalyticsValue, loadBaseStyles, yieldToMain, + lanaLog, + logErrorFor, } from '../global-navigation/utilities/utilities.js'; import { replaceKey, replaceText } from '../../features/placeholders.js'; @@ -36,7 +38,7 @@ class Footer { this.init(); } - init = async () => { + init = () => logErrorFor(async () => { // We initialize the footer decoration logic when either 3s have passed // OR when the footer element is close to coming into view let decorationTimeout; @@ -61,14 +63,14 @@ class Footer { observer.disconnect(); this.decorateContent(); }, CONFIG.delays.decoration); - }; + }, 'Error in global footer init', 'errorType=error,module=global-footer'); - decorateContent = async () => { + decorateContent = () => logErrorFor(async () => { // Fetch footer content this.body = await this.fetchContent(); - // TODO: log to LANA if Footer content could not be found if (!this.body) return; + // TODO: revisit region picker and social links decoration logic const regionAnchor = this.body.querySelector('.region-selector a'); if (regionAnchor?.href) { @@ -101,10 +103,18 @@ class Footer { this.footerEl.setAttribute('daa-lh', `gnav|${getExperienceName()}|footer|${document.body.dataset.mep}`); this.footerEl.append(this.elements.footer); - }; + }, 'Failed to decorate footer content', 'errorType=error,module=global-footer'); fetchContent = async () => { const resp = await fetch(`${this.contentUrl}.plain.html`); + + if (!resp.ok) { + lanaLog({ + message: `Failed to fetch footer content; content url: ${this.contentUrl}, status: ${resp.statusText}`, + tags: 'errorType=warn,module=global-footer', + }); + } + const html = await resp.text(); if (!html) return null; @@ -114,7 +124,7 @@ class Footer { try { return new DOMParser().parseFromString(parsedHTML, 'text/html').body; } catch (e) { - // TODO: log to LANA if Footer could not be instantiated + lanaLog({ message: 'Footer could not be instantiated', tags: 'errorType=error,module=global-footer' }); return null; } }; @@ -153,6 +163,7 @@ class Footer { loadIcons = async () => { const file = await fetch(`${base}/blocks/global-footer/icons.svg`); + const content = await file.text(); const elem = toFragment``; this.footerEl.append(elem); @@ -195,7 +206,8 @@ class Footer { try { url = new URL(regionSelector.href); } catch (e) { - // TODO: Log to Lana if URL could not be created + lanaLog({ message: `Could not create URL for region picker; href: ${regionSelector.href}`, tags: 'errorType=error,module=global-footer' }); + throw e; } if (!url) return this.elements.regionPicker; diff --git a/test/blocks/global-footer/global-footer.test.js b/test/blocks/global-footer/global-footer.test.js index 6296161082..be0b0442f7 100644 --- a/test/blocks/global-footer/global-footer.test.js +++ b/test/blocks/global-footer/global-footer.test.js @@ -15,6 +15,7 @@ import fetchedFooter from './mocks/fetched-footer.js'; import icons from './mocks/icons.js'; import { isElementVisible, mockRes } from '../global-navigation/test-utilities.js'; import placeholders from '../global-navigation/mocks/placeholders.js'; +import { logErrorFor } from '../../../libs/blocks/global-navigation/utilities/utilities.js'; describe('global footer', () => { let clock = null; @@ -41,8 +42,7 @@ describe('global footer', () => { }); afterEach(() => { - clock.restore(); - window.fetch.restore(); + sinon.restore(); document.body.innerHTML = ''; }); @@ -272,4 +272,70 @@ describe('global footer', () => { } }); }); + + describe('LANA logging tests', () => { + beforeEach(async () => { + window.lana.log = sinon.spy(); + }); + + it('should send log on error', async () => { + const erroneousFunction = async () => { + throw new Error('error'); + }; + + const logMessage = 'test message'; + const logTags = 'errorType=error,module=global-footer'; + await logErrorFor(erroneousFunction, logMessage, logTags); + + expect(window.lana.log.calledOnce).to.be.true; + + const firstCallArguments = window.lana.log.getCall(0).args; + + expect(firstCallArguments[0].includes(logMessage)).to.equal(true); + expect(firstCallArguments[1].tags === logTags).to.equal(true); + }); + + it('should send log when footer cannot be fetched', async () => { + window.fetch.restore(); + stub(window, 'fetch').callsFake((url) => { + if (url.includes('/footer')) { + return mockRes({ + payload: null, + ok: false, + status: 400, + }); + } + if (url.includes('/placeholders')) return mockRes({ payload: placeholders }); + if (url.includes('icons.svg')) return mockRes({ payload: icons }); + return null; + }); + await createFullGlobalFooter({ waitForDecoration: false }); + await clock.runAllAsync(); + expect(window.lana.log.getCalls().find((c) => c.args[0].includes('Failed to fetch footer content'))); + expect(window.lana.log.getCalls().find((c) => c.args[1].tags.includes('errorType=warn,module=global-footer'))); + }); + + it('should send log when could not create URL for region picker', async () => { + const globalFooter = await createFullGlobalFooter({ waitForDecoration: true }); + sinon.restore(); + stub(window, 'URL').callsFake(() => { + throw new Error('mocked error'); + }); + try { + await globalFooter.decorateRegionPicker(); + } catch (e) { + // should throw error + } + expect(window.lana.log.getCalls().find((c) => c.args[0].includes('Could not create URL for region picker'))); + expect(window.lana.log.getCalls().find((c) => c.args[1].tags.includes('errorType=error,module=global-footer'))); + }); + + it('should send log when footer cannot be instantiated ', async () => { + sinon.stub(window, 'DOMParser').callsFake(() => ({ parseFromString: sinon.stub().throws(new Error('Parsing error')) })); + await createFullGlobalFooter({ waitForDecoration: false }); + await clock.runAllAsync(); + expect(window.lana.log.getCalls().find((c) => c.args[0].includes('Footer could not be instantiated'))); + expect(window.lana.log.getCalls().find((c) => c.args[1].tags.includes('errorType=error,module=global-footer'))); + }); + }); });