From 462146aa6add369b92527a264a8f8ff27517a1d0 Mon Sep 17 00:00:00 2001 From: Brett Kyle Date: Tue, 5 Sep 2023 14:22:08 +0100 Subject: [PATCH 1/4] Add MissingElementError --- packages/govuk-frontend/src/govuk/errors/index.mjs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/govuk-frontend/src/govuk/errors/index.mjs b/packages/govuk-frontend/src/govuk/errors/index.mjs index 52636188a4..583d073d59 100644 --- a/packages/govuk-frontend/src/govuk/errors/index.mjs +++ b/packages/govuk-frontend/src/govuk/errors/index.mjs @@ -22,6 +22,13 @@ export class GOVUKFrontendError extends Error { name = 'GOVUKFrontendError' } +/** + * Indicates that a Component's required HTML element is missing + */ +export class MissingElementError extends GOVUKFrontendError { + name = 'MissingElementError' +} + /** * Indicates that GOV.UK Frontend is not supported */ From b56cebf6fbea96532abc4ebb2f3a635422c415df Mon Sep 17 00:00:00 2001 From: Brett Kyle Date: Tue, 5 Sep 2023 14:22:42 +0100 Subject: [PATCH 2/4] Throw MissingElementError if key HTML missing --- .../src/govuk/components/skip-link/skip-link.mjs | 3 ++- .../govuk/components/skip-link/skip-link.test.js | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.mjs b/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.mjs index 4c15ca2669..cae167bc0f 100644 --- a/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.mjs +++ b/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.mjs @@ -1,3 +1,4 @@ +import { MissingElementError } from '../../errors/index.mjs' import { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs' /** @@ -33,7 +34,7 @@ export class SkipLink extends GOVUKFrontendComponent { // Check for linked element const $linkedElement = this.getLinkedElement() if (!$linkedElement) { - return + throw new MissingElementError('The linked HTML element does not exist') } this.$linkedElement = $linkedElement diff --git a/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.test.js b/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.test.js index ad065b1a65..14f708f74b 100644 --- a/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.test.js +++ b/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.test.js @@ -81,5 +81,19 @@ describe('Skip Link', () => { message: 'GOV.UK Frontend is not supported in this browser' }) }) + + it('throws when the linked element is missing', async () => { + await expect( + renderAndInitialise(page, 'skip-link', { + params: { + text: 'Skip to main content', + href: '#this-element-does-not-exist' + } + }) + ).rejects.toEqual({ + name: 'MissingElementError', + message: 'The linked HTML element does not exist' + }) + }) }) }) From c61fb5ac400eee69e95d5818d0cb369394b100f4 Mon Sep 17 00:00:00 2001 From: Brett Kyle Date: Tue, 5 Sep 2023 17:38:05 +0100 Subject: [PATCH 3/4] Throw more useful errors --- .../govuk/components/skip-link/skip-link.mjs | 32 +++++++++++++++---- .../components/skip-link/skip-link.test.js | 2 +- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.mjs b/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.mjs index cae167bc0f..d477a25b4a 100644 --- a/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.mjs +++ b/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.mjs @@ -32,12 +32,18 @@ export class SkipLink extends GOVUKFrontendComponent { this.$module = $module // Check for linked element - const $linkedElement = this.getLinkedElement() - if (!$linkedElement) { - throw new MissingElementError('The linked HTML element does not exist') + try { + const $linkedElement = this.getLinkedElement() + this.$linkedElement = $linkedElement + } catch (cause) { + throw new MissingElementError( + 'Skip link: the linked HTML element does not exist', + { + cause: cause instanceof Error ? cause : undefined + } + ) } - this.$linkedElement = $linkedElement this.$module.addEventListener('click', () => this.focusLinkedElement()) } @@ -45,15 +51,27 @@ export class SkipLink extends GOVUKFrontendComponent { * Get linked element * * @private - * @returns {HTMLElement | null} $linkedElement - DOM element linked to from the skip link + * @throws {Error} If the "href" attribute does not contain a hash + * @throws {Error} If the element with the specified ID does not exist + * @returns {HTMLElement} $linkedElement - DOM element linked to from the skip link */ getLinkedElement() { const linkedElementId = this.getFragmentFromUrl() if (!linkedElementId) { - return null + throw new Error( + `Skip link: $module "href" attribute does not contain a hash` + ) } - return document.getElementById(linkedElementId) + const linkedElement = document.getElementById(linkedElementId) + + if (!linkedElement) { + throw new Error( + `Skip link: Target selector "#${linkedElementId}" not found` + ) + } + + return linkedElement } /** diff --git a/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.test.js b/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.test.js index 14f708f74b..b3e3cf1e56 100644 --- a/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.test.js +++ b/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.test.js @@ -92,7 +92,7 @@ describe('Skip Link', () => { }) ).rejects.toEqual({ name: 'MissingElementError', - message: 'The linked HTML element does not exist' + message: 'Skip link: the linked HTML element does not exist' }) }) }) From e1eff1451d70921e7659cfec41c35d430920e83f Mon Sep 17 00:00:00 2001 From: Brett Kyle Date: Thu, 7 Sep 2023 14:50:20 +0100 Subject: [PATCH 4/4] Use error message strings instead of cause --- .../govuk/components/skip-link/skip-link.mjs | 20 +++++++++---------- .../components/skip-link/skip-link.test.js | 17 +++++++++++++++- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.mjs b/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.mjs index d477a25b4a..60e429b427 100644 --- a/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.mjs +++ b/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.mjs @@ -21,6 +21,7 @@ export class SkipLink extends GOVUKFrontendComponent { /** * @param {Element} $module - HTML element to use for skip link + * @throws {MissingElementError} If the element with the specified ID is not found */ constructor($module) { super() @@ -35,12 +36,11 @@ export class SkipLink extends GOVUKFrontendComponent { try { const $linkedElement = this.getLinkedElement() this.$linkedElement = $linkedElement - } catch (cause) { + } catch (error) { throw new MissingElementError( - 'Skip link: the linked HTML element does not exist', - { - cause: cause instanceof Error ? cause : undefined - } + `Skip link: ${ + error instanceof Error ? error.message : 'Linked element not found' + }` ) } @@ -52,22 +52,20 @@ export class SkipLink extends GOVUKFrontendComponent { * * @private * @throws {Error} If the "href" attribute does not contain a hash - * @throws {Error} If the element with the specified ID does not exist + * @throws {TypeError} If the element with the specified ID is not found * @returns {HTMLElement} $linkedElement - DOM element linked to from the skip link */ getLinkedElement() { const linkedElementId = this.getFragmentFromUrl() if (!linkedElementId) { - throw new Error( - `Skip link: $module "href" attribute does not contain a hash` - ) + throw new Error(`$module "href" attribute does not contain a hash`) } const linkedElement = document.getElementById(linkedElementId) if (!linkedElement) { - throw new Error( - `Skip link: Target selector "#${linkedElementId}" not found` + throw new TypeError( + `Linked element selector "#${linkedElementId}" not found` ) } diff --git a/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.test.js b/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.test.js index b3e3cf1e56..d808ccaaf9 100644 --- a/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.test.js +++ b/packages/govuk-frontend/src/govuk/components/skip-link/skip-link.test.js @@ -92,7 +92,22 @@ describe('Skip Link', () => { }) ).rejects.toEqual({ name: 'MissingElementError', - message: 'Skip link: the linked HTML element does not exist' + message: + 'Skip link: Linked element selector "#this-element-does-not-exist" not found' + }) + }) + + it('throws when the href does not contain a hash', async () => { + await expect( + renderAndInitialise(page, 'skip-link', { + params: { + text: 'Skip to main content', + href: 'this-element-does-not-exist' + } + }) + ).rejects.toEqual({ + name: 'MissingElementError', + message: 'Skip link: $module "href" attribute does not contain a hash' }) }) })