Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw errors during accordion initialisation #4266

Merged
merged 7 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,10 @@ export class Accordion extends GOVUKFrontendComponent {

const $sections = this.$module.querySelectorAll(`.${this.sectionClass}`)
if (!$sections.length) {
return this
throw new ElementError({
componentName: 'Accordion',
identifier: `Sections (\`<div class="${this.sectionClass}">\`)`
})
}

this.$sections = $sections
Expand Down Expand Up @@ -203,7 +206,10 @@ export class Accordion extends GOVUKFrontendComponent {
this.$sections.forEach(($section, i) => {
const $header = $section.querySelector(`.${this.sectionHeaderClass}`)
if (!$header) {
return
throw new ElementError({
componentName: 'Accordion',
identifier: `Section headers (\`<div class="${this.sectionHeaderClass}">\`)`
})
}

// Set header attributes
Expand Down Expand Up @@ -231,8 +237,18 @@ export class Accordion extends GOVUKFrontendComponent {
const $heading = $header.querySelector(`.${this.sectionHeadingClass}`)
const $summary = $header.querySelector(`.${this.sectionSummaryClass}`)

if (!$span || !$heading) {
return
if (!$heading) {
throw new ElementError({
componentName: 'Accordion',
identifier: `Section heading (\`.${this.sectionHeadingClass}\`)`
})
}

if (!$span) {
throw new ElementError({
componentName: 'Accordion',
identifier: `Section button placeholder (\`<span class="${this.sectionButtonClass}">\`)`
})
}

// Create a button element that will replace the
Expand Down Expand Up @@ -395,7 +411,15 @@ export class Accordion extends GOVUKFrontendComponent {
const $button = $section.querySelector(`.${this.sectionButtonClass}`)
const $content = $section.querySelector(`.${this.sectionContentClass}`)

if (!$showHideIcon || !$showHideText || !$button || !$content) {
if (!$content) {
throw new ElementError({
componentName: 'Accordion',
identifier: `Section content (\`<div class="${this.sectionContentClass}">\`)`
})
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -711,59 +711,158 @@ describe('/components/accordion', () => {
)
})
})
})

describe('errors at instantiation', () => {
let examples
describe('errors at instantiation', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noticed we accidentally had our errors at instantiation wrapped within the localisation block.

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(
render(page, 'accordion', examples.default, {
beforeInitialisation() {
document.body.classList.remove('govuk-frontend-supported')
}
})
).rejects.toMatchObject({
cause: {
name: 'SupportError',
message: 'GOV.UK Frontend is not supported in this browser'
}
})
})

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

it('throws when $module is not set', async () => {
await expect(
render(page, 'accordion', examples.default, {
beforeInitialisation($module) {
$module.remove()
}
})
).rejects.toMatchObject({
cause: {
name: 'ElementError',
message: 'Accordion: Root element (`$module`) not found'
it('throws when receiving the wrong type for $module', async () => {
await expect(
render(page, 'accordion', 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.toMatchObject({
cause: {
name: 'ElementError',
message:
'Accordion: Root element (`$module`) is not of type HTMLElement'
}
})
})

it('throws when receiving the wrong type for $module', async () => {
await expect(
render(page, 'accordion', 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.toMatchObject({
cause: {
name: 'ElementError',
message:
'Accordion: Root element (`$module`) is not of type HTMLElement'
it('throws when the accordion sections are missing', async () => {
await expect(
render(page, 'accordion', examples.default, {
beforeInitialisation($module, { selector }) {
$module
.querySelectorAll(selector)
.forEach((item) => item.remove())
},
context: {
selector: '.govuk-accordion__section'
}
})
).rejects.toMatchObject({
cause: {
name: 'ElementError',
message:
'Accordion: Sections (`<div class="govuk-accordion__section">`) not found'
}
})
})

it('throws when section header is missing', async () => {
await expect(
render(page, 'accordion', examples.default, {
beforeInitialisation($module, { selector }) {
$module
.querySelectorAll(selector)
.forEach((item) => item.remove())
},
context: {
selector: '.govuk-accordion__section-header'
}
})
).rejects.toMatchObject({
cause: {
name: 'ElementError',
message:
'Accordion: Section headers (`<div class="govuk-accordion__section-header">`) not found'
}
})
})

it('throws when any section heading is missing', async () => {
await expect(
render(page, 'accordion', examples.default, {
beforeInitialisation($module, { selector }) {
$module.querySelector(selector).remove()
},
context: {
selector: '.govuk-accordion__section-heading'
}
})
).rejects.toMatchObject({
cause: {
name: 'ElementError',
message:
'Accordion: Section heading (`.govuk-accordion__section-heading`) not found'
}
})
})

it('throws when any section button placeholder span is missing', async () => {
await expect(
render(page, 'accordion', examples.default, {
beforeInitialisation($module, { selector }) {
$module.querySelector(selector).remove()
},
context: {
selector: '.govuk-accordion__section-button'
}
})
).rejects.toMatchObject({
cause: {
name: 'ElementError',
message:
'Accordion: Section button placeholder (`<span class="govuk-accordion__section-button">`) not found'
}
})
})

it('throws when any section content is missing', async () => {
await expect(
render(page, 'accordion', examples.default, {
beforeInitialisation($module, { selector }) {
$module.querySelector(selector).remove()
},
context: {
selector: '.govuk-accordion__section-content'
}
})
).rejects.toMatchObject({
cause: {
name: 'ElementError',
message:
'Accordion: Section content (`<div class="govuk-accordion__section-content">`) not found'
}
})
})
})
Expand Down