Skip to content

Commit

Permalink
Split section errors
Browse files Browse the repository at this point in the history
Actually ends up being a similar amount of code as before, but easier to parse. And separates the Things Wot Throw from the Things Wot We Ignore.

Also noticed we'd popped our error tests within the i18n `describe`, so pulled them out into their own block.

And finally, tried to edit all error messages so that they match what we're aiming for with our content review.
  • Loading branch information
domoscargin authored and colinrotherham committed Oct 13, 2023
1 parent efb826b commit 7bb2dc7
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export class Accordion extends GOVUKFrontendComponent {
if (!($module instanceof HTMLElement)) {
throw new ElementError($module, {
componentName: 'Accordion',
identifier: '$module'
identifier: 'Root element (`[data-module=govuk-accordion]`)'
})
}

Expand All @@ -140,7 +140,7 @@ export class Accordion extends GOVUKFrontendComponent {
if (!$sections.length) {
throw new ElementError(null, {
componentName: 'Accordion',
identifier: `.${this.sectionClass}`
identifier: `Element (\`.${this.sectionClass}\`)`
})
}

Expand Down Expand Up @@ -207,7 +207,7 @@ export class Accordion extends GOVUKFrontendComponent {
if (!$header) {
throw new ElementError(null, {
componentName: 'Accordion',
identifier: `.${this.sectionHeaderClass}`
identifier: `Element (\`.${this.sectionHeaderClass}\`)`
})
}

Expand Down Expand Up @@ -239,14 +239,14 @@ export class Accordion extends GOVUKFrontendComponent {
if (!$heading) {
throw new ElementError(null, {
componentName: 'Accordion',
identifier: `.${this.sectionHeadingClass}`
identifier: `Heading element (\`.${this.sectionHeadingClass}\`)`
})
}

if (!$span) {
throw new ElementError(null, {
componentName: 'Accordion',
identifier: `.${this.sectionButtonClass}`
identifier: `Span element (\`.${this.sectionButtonClass}\`)`
})
}

Expand Down Expand Up @@ -411,26 +411,25 @@ export class Accordion extends GOVUKFrontendComponent {
const $button = $section.querySelector(`.${this.sectionButtonClass}`)
const $content = $section.querySelector(`.${this.sectionContentClass}`)

// Return early for elements created during set up
if (!$showHideIcon || !$showHideText) {
return
if (!$button) {
throw new ElementError(null, {
componentName: 'Accordion',
identifier: `Span element (\`.${this.sectionButtonClass}\`)`
})
}

if (!$button || !$content) {
const [check] = /** @type {const} */ ([
[$button, this.sectionButtonClass],
[$content, this.sectionContentClass]
])
// Filter the list by which checks failed
.filter(([$element]) => !($element instanceof HTMLElement))

throw new ElementError(check[0], {
if (!$content) {
throw new ElementError(null, {
componentName: 'Accordion',
identifier: `.${check[1]}`,
expectedType: 'HTMLElement'
identifier: `Element (\`.${this.sectionContentClass}\`)`
})
}

if (!$showHideIcon || !$showHideText) {
// Return early for elements we create
return
}

const newButtonText = expanded
? this.i18n.t('hideSection')
: this.i18n.t('showSection')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -712,148 +712,160 @@ describe('/components/accordion', () => {
)
})
})
})

describe('errors at instantiation', () => {
let examples
describe('errors at instantiation', () => {
let examples

beforeAll(async () => {
examples = await getExamples('accordion')
beforeAll(async () => {
examples = await getExamples('accordion')
})

it('throws when GOV.UK Frontend is not supported', async () => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation() {
document.body.classList.remove('govuk-frontend-supported')
}
})
).rejects.toEqual({
name: 'SupportError',
message: 'GOV.UK Frontend is not supported in this browser'
})
})

it('throws when GOV.UK Frontend is not supported', async () => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation() {
document.body.classList.remove('govuk-frontend-supported')
}
})
).rejects.toEqual({
name: 'SupportError',
message: 'GOV.UK Frontend is not supported in this browser'
it('throws when $module is not set', async () => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation($module) {
$module.remove()
}
})
).rejects.toEqual({
name: 'ElementError',
message:
'Accordion: Root element (`[data-module=govuk-accordion]`) not found'
})
})

it('throws when $module is not set', async () => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation($module) {
$module.remove()
}
})
).rejects.toEqual({
name: 'ElementError',
message: 'Accordion: $module not found'
it('throws when receiving the wrong type for $module', async () => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation($module) {
// Replace with an `<svg>` element which is not an `HTMLElement` in the DOM (but an `SVGElement`)
$module.outerHTML = `<svg data-module="govuk-accordion"></svg>`
}
})
).rejects.toEqual({
name: 'ElementError',
message:
'Accordion: Root element (`[data-module=govuk-accordion]`) is not an instance of HTMLElement'
})
})

it('throws when receiving the wrong type for $module', async () => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation($module) {
// Replace with an `<svg>` element which is not an `HTMLElement` in the DOM (but an `SVGElement`)
$module.outerHTML = `<svg data-module="govuk-accordion"></svg>`
}
})
).rejects.toEqual({
name: 'ElementError',
message: 'Accordion: $module is not an instance of HTMLElement'
it('throws when the accordion sections are missing', async () => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation($module) {
$module
.querySelectorAll('.govuk-accordion__section')
.forEach((item) => {
item.remove()
})
}
})
).rejects.toEqual({
name: 'ElementError',
message:
'Accordion: Element (`.govuk-accordion__section`) not found'
})
})

it('throws when the accordion sections are missing', async () => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation($module) {
$module
.querySelectorAll('.govuk-accordion__section')
.forEach((item) => {
item.remove()
})
}
})
).rejects.toEqual({
name: 'ElementError',
message: 'Accordion: .govuk-accordion__section not found'
it('throws when any section header is missing', async () => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation($module) {
$module
.querySelector('.govuk-accordion__section-header')
.remove()
}
})
).rejects.toEqual({
name: 'ElementError',
message:
'Accordion: Element (`.govuk-accordion__section-header`) not found'
})
})

it('throws when any section header is missing', async () => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation($module) {
$module
.querySelector('.govuk-accordion__section-header')
.remove()
}
})
).rejects.toEqual({
name: 'ElementError',
message: 'Accordion: .govuk-accordion__section-header not found'
it('throws when any section button span is missing', async () => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation($module) {
$module
.querySelector('.govuk-accordion__section-button')
.remove()
}
})
).rejects.toEqual({
name: 'ElementError',
message:
'Accordion: Span element (`.govuk-accordion__section-button`) not found'
})
})

it('throws when any section button span is missing', async () => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation($module) {
$module
.querySelector('.govuk-accordion__section-button')
.remove()
}
})
).rejects.toEqual({
name: 'ElementError',
message: 'Accordion: .govuk-accordion__section-button not found'
it('throws when any section heading is missing', async () => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation($module) {
$module
.querySelector('.govuk-accordion__section-heading')
.remove()
}
})
).rejects.toEqual({
name: 'ElementError',
message:
'Accordion: Heading element (`.govuk-accordion__section-heading`) not found'
})
})

it('throws when any section heading is missing', async () => {
const sectionElements = [
{
elementName: 'Span element',
selector: '.govuk-accordion__section-button'
},
{
elementName: 'Element',
selector: '.govuk-accordion__section-content'
}
]

it.each(sectionElements)(
'throws when any section button or section content element is missing',
async ({ elementName, selector }) => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation($module) {
$module
.querySelector('.govuk-accordion__section-heading')
.remove()
beforeInitialisation($module, { selector }) {
$module.querySelector(selector).remove()
},
beforeInitialisationOptions: {
selector
}
})
).rejects.toEqual({
name: 'ElementError',
message: 'Accordion: .govuk-accordion__section-heading not found'
message: `Accordion: ${elementName} (\`${selector}\`) not found`
})
})

const toggleButtonElements = [
'.govuk-accordion__section-button',
'.govuk-accordion__section-content'
]

it.each(toggleButtonElements)(
'throws when any section toggle button-related element is missing',
async (selector) => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation($module, { selector }) {
$module.querySelector(selector).remove()
},
beforeInitialisationOptions: {
selector
}
})
).rejects.toEqual({
name: 'ElementError',
message: `Accordion: ${selector} not found`
})
}
)
})
}
)
})
})
})
Expand Down

0 comments on commit 7bb2dc7

Please sign in to comment.