Skip to content

Commit

Permalink
Overload ElementError to allow either a message or options
Browse files Browse the repository at this point in the history
In cases where we want a very different error message, we can now just pass that directly.

Co-authored by: Brett Kyle <[email protected]>
Co authored by: Colin Rotherham <[email protected]>
  • Loading branch information
domoscargin committed Oct 19, 2023
1 parent 4f17a54 commit e898384
Show file tree
Hide file tree
Showing 15 changed files with 136 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,10 @@ export class Accordion extends GOVUKFrontendComponent {
super()

if (!($module instanceof HTMLElement)) {
throw new ElementError('Root element (`$module`)', {
throw new ElementError({
componentName: 'Accordion',
element: $module
element: $module,
identifier: 'Root element (`$module`)'
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ export class Button extends GOVUKFrontendComponent {
super()

if (!($module instanceof HTMLElement)) {
throw new ElementError('Root element (`$module`)', {
throw new ElementError({
componentName: 'Button',
element: $module
element: $module,
identifier: 'Root element (`$module`)'
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,10 @@ export class CharacterCount extends GOVUKFrontendComponent {
super()

if (!($module instanceof HTMLElement)) {
throw new ElementError('Root element (`$module`)', {
throw new ElementError({
componentName: 'Character count',
element: $module
element: $module,
identifier: 'Root element (`$module`)'
})
}

Expand All @@ -88,10 +89,11 @@ export class CharacterCount extends GOVUKFrontendComponent {
$textarea instanceof HTMLInputElement
)
) {
throw new ElementError('.govuk-js-character-count', {
throw new ElementError({
componentName: 'Character count',
element: $textarea,
expectedType: 'HTMLTextareaElement or HTMLInputElement'
expectedType: 'HTMLTextareaElement or HTMLInputElement',
identifier: 'Form field (`.govuk-js-character-count`)'
})
}

Expand Down Expand Up @@ -140,9 +142,10 @@ export class CharacterCount extends GOVUKFrontendComponent {
const textareaDescriptionId = `${this.$textarea.id}-info`
const $textareaDescription = document.getElementById(textareaDescriptionId)
if (!$textareaDescription) {
throw new ElementError(`#${textareaDescriptionId}`, {
throw new ElementError({
componentName: 'Character count',
element: $textareaDescription
element: $textareaDescription,
identifier: `#${textareaDescriptionId}`
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,8 @@ describe('Character count', () => {
})
).rejects.toEqual({
name: 'ElementError',
message: 'Character count: .govuk-js-character-count not found'
message:
'Character count: Form field (`.govuk-js-character-count`) not found'
})
})

Expand All @@ -884,7 +885,7 @@ describe('Character count', () => {
).rejects.toEqual({
name: 'ElementError',
message:
'Character count: .govuk-js-character-count is not of type HTMLTextareaElement or HTMLInputElement'
'Character count: Form field (`.govuk-js-character-count`) is not of type HTMLTextareaElement or HTMLInputElement'
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,18 @@ export class Checkboxes extends GOVUKFrontendComponent {
super()

if (!($module instanceof HTMLElement)) {
throw new ElementError(`[data-module="${Checkboxes.moduleName}"]`, {
throw new ElementError({
componentName: 'Checkboxes',
element: $module
element: $module,
identifier: `[data-module="${Checkboxes.moduleName}"]`
})
}

const $inputs = $module.querySelectorAll('input[type="checkbox"]')
if (!$inputs.length) {
throw new ElementError('input[type="checkbox"]', {
componentName: 'Checkboxes'
throw new ElementError({
componentName: 'Checkboxes',
identifier: 'input[type="checkbox"]'
})
}

Expand All @@ -57,8 +59,9 @@ export class Checkboxes extends GOVUKFrontendComponent {

// Throw if target conditional element does not exist.
if (!document.getElementById(targetId)) {
throw new ElementError(`#${targetId}`, {
componentName: 'Checkboxes'
throw new ElementError({
componentName: 'Checkboxes',
identifier: `#${targetId}`
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ export class ErrorSummary extends GOVUKFrontendComponent {
super()

if (!($module instanceof HTMLElement)) {
throw new ElementError('Root element (`$module`)', {
throw new ElementError({
componentName: 'Error summary',
element: $module
element: $module,
identifier: 'Root element (`$module`)'
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,20 @@ export class ExitThisPage extends GOVUKFrontendComponent {
super()

if (!($module instanceof HTMLElement)) {
throw new ElementError('Root element (`$module`)', {
throw new ElementError({
componentName: 'Exit this page',
element: $module
element: $module,
identifier: 'Root element (`$module`)'
})
}

const $button = $module.querySelector('.govuk-exit-this-page__button')
if (!($button instanceof HTMLAnchorElement)) {
throw new ElementError('Button', {
throw new ElementError({
componentName: 'Exit this page',
element: $button,
expectedType: 'HTMLAnchorElement'
expectedType: 'HTMLAnchorElement',
identifier: 'Button'
})
}

Expand Down
15 changes: 9 additions & 6 deletions packages/govuk-frontend/src/govuk/components/header/header.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ export class Header extends GOVUKFrontendComponent {
super()

if (!$module) {
throw new ElementError('Root element (`$module`)', {
throw new ElementError({
componentName: 'Header',
element: $module
element: $module,
identifier: 'Root element (`$module`)'
})
}

Expand All @@ -63,16 +64,18 @@ export class Header extends GOVUKFrontendComponent {

const menuId = $menuButton.getAttribute('aria-controls')
if (!menuId) {
throw new ElementError('.govuk-js-header-toggle[aria-controls]', {
componentName: 'Header'
throw new ElementError({
componentName: 'Header',
identifier: '.govuk-js-header-toggle[aria-controls]'
})
}

const $menu = document.getElementById(menuId)
if (!$menu) {
throw new ElementError(`#${menuId}`, {
throw new ElementError({
componentName: 'Header',
element: $menu
element: $menu,
identifier: `#${menuId}`
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ export class NotificationBanner extends GOVUKFrontendComponent {
super()

if (!($module instanceof HTMLElement)) {
throw new ElementError('Root element (`$module`)', {
throw new ElementError({
componentName: 'Notification banner',
element: $module
element: $module,
identifier: 'Root element (`$module`)'
})
}

Expand Down
15 changes: 9 additions & 6 deletions packages/govuk-frontend/src/govuk/components/radios/radios.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,18 @@ export class Radios extends GOVUKFrontendComponent {
super()

if (!($module instanceof HTMLElement)) {
throw new ElementError(`[data-module="${Radios.moduleName}"]`, {
throw new ElementError({
componentName: 'Radios',
element: $module
element: $module,
identifier: `[data-module="${Radios.moduleName}"]`
})
}

const $inputs = $module.querySelectorAll('input[type="radio"]')
if (!$inputs.length) {
throw new ElementError('input[type="radio"]', {
componentName: 'Radios'
throw new ElementError({
componentName: 'Radios',
identifier: 'input[type="radio"]'
})
}

Expand All @@ -57,8 +59,9 @@ export class Radios extends GOVUKFrontendComponent {

// Throw if target conditional element does not exist.
if (!document.getElementById(targetId)) {
throw new ElementError(`#${targetId}`, {
componentName: 'Radios'
throw new ElementError({
componentName: 'Radios',
identifier: `#${targetId}`
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ export class SkipLink extends GOVUKFrontendComponent {
super()

if (!($module instanceof HTMLAnchorElement)) {
throw new ElementError('Root element (`$module`)', {
throw new ElementError({
componentName: 'Skip link',
element: $module,
expectedType: 'HTMLAnchorElement'
expectedType: 'HTMLAnchorElement',
identifier: 'Root element (`$module`)'
})
}

Expand All @@ -51,20 +52,19 @@ export class SkipLink extends GOVUKFrontendComponent {

// Check for link hash fragment
if (!linkedElementId) {
throw new ElementError('$module.hash', {
componentName: 'Skip link',
element: this.$module,
expectedType: 'string'
})
throw new ElementError(
'Skip link: Root element (`$module`) attribute (`href`) has no URL fragment'
)
}

const $linkedElement = document.getElementById(linkedElementId)

// Check for link target element
if (!$linkedElement) {
throw new ElementError(`$module.hash target #${linkedElementId}`, {
throw new ElementError({
componentName: 'Skip link',
element: $linkedElement
element: $linkedElement,
identifier: `Linked element #${linkedElementId}`
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ describe('Skip Link', () => {
).rejects.toEqual({
name: 'ElementError',
message:
'Skip link: $module.hash target #this-element-does-not-exist not found'
'Skip link: Linked element #this-element-does-not-exist not found'
})
})

Expand All @@ -130,7 +130,8 @@ describe('Skip Link', () => {
})
).rejects.toEqual({
name: 'ElementError',
message: 'Skip link: $module.hash is not of type string'
message:
'Skip link: Root element (`$module`) attribute (`href`) has no URL fragment'
})
})
})
Expand Down
20 changes: 12 additions & 8 deletions packages/govuk-frontend/src/govuk/components/tabs/tabs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,18 @@ export class Tabs extends GOVUKFrontendComponent {
super()

if (!$module) {
throw new ElementError('Root element (`$module`)', {
throw new ElementError({
componentName: 'Tabs',
element: $module
element: $module,
identifier: 'Root element (`$module`)'
})
}

const $tabs = $module.querySelectorAll('a.govuk-tabs__tab')
if (!$tabs.length) {
throw new ElementError(`a.govuk-tabs__tab`, {
componentName: 'Tabs'
throw new ElementError({
componentName: 'Tabs',
identifier: `a.govuk-tabs__tab`
})
}

Expand All @@ -78,14 +80,16 @@ export class Tabs extends GOVUKFrontendComponent {
)

if (!$tabList) {
throw new ElementError(`.govuk-tabs__list`, {
componentName: 'Tabs'
throw new ElementError({
componentName: 'Tabs',
identifier: `.govuk-tabs__list`
})
}

if (!$tabListItems.length) {
throw new ElementError(`.govuk-tabs__list-item`, {
componentName: 'Tabs'
throw new ElementError({
componentName: 'Tabs',
identifier: `.govuk-tabs__list-item`
})
}

Expand Down
25 changes: 17 additions & 8 deletions packages/govuk-frontend/src/govuk/errors/index.jsdom.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,42 @@ describe('errors', () => {
describe('ElementError', () => {
it('is an instance of GOVUKFrontendError', () => {
expect(
new ElementError('variableName', {
componentName: 'Component name'
new ElementError({
componentName: 'Component name',
identifier: 'variableName'
})
).toBeInstanceOf(GOVUKFrontendError)
})
it('has its own name set', () => {
expect(
new ElementError('variableName', {
componentName: 'Component name'
new ElementError({
componentName: 'Component name',
identifier: 'variableName'
}).name
).toBe('ElementError')
})
it('accepts a string and does not process it in any way', () => {
expect(new ElementError('Complex custom error message').message).toBe(
'Complex custom error message'
)
})
it('formats the message when the element is not found', () => {
expect(
new ElementError('variableName', {
componentName: 'Component name'
new ElementError({
componentName: 'Component name',
identifier: 'variableName'
}).message
).toBe('Component name: variableName not found')
})
it('formats the message when the element is not the right type', () => {
const element = document.createElement('div')

expect(
new ElementError('variableName', {
new ElementError({
componentName: 'Component name',
element,
expectedType: 'HTMLAnchorElement'
expectedType: 'HTMLAnchorElement',
identifier: 'variableName'
}).message
).toBe('Component name: variableName is not of type HTMLAnchorElement')
})
Expand Down
Loading

0 comments on commit e898384

Please sign in to comment.