Skip to content

Commit

Permalink
Implement check for type of $module
Browse files Browse the repository at this point in the history
request-checks: true
  • Loading branch information
romaricpascal committed Aug 18, 2023
1 parent 7b3d69a commit 893d9f5
Show file tree
Hide file tree
Showing 23 changed files with 229 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -113,18 +113,12 @@ export class Accordion extends GOVUKFrontendComponent {
* @param {AccordionConfig} [config] - Accordion config
*/
constructor($module, config) {
super()

if (!($module instanceof HTMLElement)) {
return this
}

this.$module = $module
super($module)

this.config = mergeConfigs(
Accordion.defaults,
config || {},
normaliseDataset($module.dataset)
normaliseDataset(this.$module.dataset)
)

this.i18n = new I18n(extractConfigByNamespace(this.config, 'i18n'))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,22 @@ describe('/components/accordion', () => {
message: 'GOV.UK Frontend is not supported in this browser'
})
})

it('throws when receiving the wrong type for $module', async () => {
await expect(
renderAndInitialise(page, 'accordion', {
params: examples.default,
beforeInitialisation() {
// Remove the root of the components as a way
// for the constructor to receive the wrong type for `$module`
document.querySelector('[data-module]').remove()
}
})
).rejects.toEqual({
name: 'TypeError',
message: 'Expected `$module` to be an instance of `HTMLElement`'
})
})
})
})
})
Expand Down
10 changes: 2 additions & 8 deletions packages/govuk-frontend/src/govuk/components/button/button.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,12 @@ export class Button extends GOVUKFrontendComponent {
* @param {ButtonConfig} [config] - Button config
*/
constructor($module, config) {
super()

if (!($module instanceof HTMLElement)) {
return this
}

this.$module = $module
super($module)

this.config = mergeConfigs(
Button.defaults,
config || {},
normaliseDataset($module.dataset)
normaliseDataset(this.$module.dataset)
)

this.$module.addEventListener('keydown', (event) =>
Expand Down
37 changes: 16 additions & 21 deletions packages/govuk-frontend/src/govuk/components/button/button.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const {
goTo,
goToComponent,
renderAndInitialise
} = require('@govuk-frontend/helpers/puppeteer')
Expand All @@ -18,26 +17,6 @@ describe('/components/button', () => {
examples = await getExamples('button')
})

describe('mis-instantiation', () => {
it('does not prevent further JavaScript from running', async () => {
await goTo(page, '/tests/boilerplate')

const result = await page.evaluate(async (exportName) => {
const namespace = await import('govuk-frontend')

// `undefined` simulates the element being missing,
// from an unchecked `document.querySelector` for example
/* eslint-disable-next-line no-new */
new namespace[exportName](undefined)

// If our component initialisation breaks, this won't run
return true
}, 'Button')

expect(result).toBe(true)
})
})

describe('/components/button/link', () => {
beforeAll(async () => {
await goToComponent(page, 'button', {
Expand Down Expand Up @@ -359,6 +338,22 @@ describe('/components/button', () => {
message: 'GOV.UK Frontend is not supported in this browser'
})
})

it('throws when receiving the wrong type for $module', async () => {
await expect(
renderAndInitialise(page, 'button', {
params: examples.default,
beforeInitialisation() {
// Remove the root of the components as a way
// for the constructor to receive the wrong type for `$module`
document.querySelector('[data-module]').remove()
}
})
).rejects.toEqual({
name: 'TypeError',
message: 'Expected `$module` to be an instance of `HTMLElement`'
})
})
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,7 @@ export class CharacterCount extends GOVUKFrontendComponent {
* @param {CharacterCountConfig} [config] - Character count config
*/
constructor($module, config) {
super()

if (!($module instanceof HTMLElement)) {
return this
}
super($module)

const $textarea = $module.querySelector('.govuk-js-character-count')
if (
Expand All @@ -81,7 +77,7 @@ export class CharacterCount extends GOVUKFrontendComponent {
}

// Read config set using dataset ('data-' values)
const datasetConfig = normaliseDataset($module.dataset)
const datasetConfig = normaliseDataset(this.$module.dataset)

// To ensure data-attributes take complete precedence, even if they change the
// type of count, we need to reset the `maxlength` and `maxwords` from the
Expand Down Expand Up @@ -119,7 +115,6 @@ export class CharacterCount extends GOVUKFrontendComponent {
return this
}

this.$module = $module
this.$textarea = $textarea

const $textareaDescription = document.getElementById(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,22 @@ describe('Character count', () => {
message: 'GOV.UK Frontend is not supported in this browser'
})
})

it('throws when receiving the wrong type for $module', async () => {
await expect(
renderAndInitialise(page, 'character-count', {
params: examples.default,
beforeInitialisation() {
// Remove the root of the components as a way
// for the constructor to receive the wrong type for `$module`
document.querySelector('[data-module]').remove()
}
})
).rejects.toEqual({
name: 'TypeError',
message: 'Expected `$module` to be an instance of `HTMLElement`'
})
})
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,14 @@ export class Checkboxes extends GOVUKFrontendComponent {
* @param {Element} $module - HTML element to use for checkboxes
*/
constructor($module) {
super()

if (!($module instanceof HTMLElement)) {
return this
}
super($module)

/** @satisfies {NodeListOf<HTMLInputElement>} */
const $inputs = $module.querySelectorAll('input[type="checkbox"]')
if (!$inputs.length) {
return this
}

this.$module = $module
this.$inputs = $inputs

this.$inputs.forEach(($input) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,22 @@ describe('Checkboxes with multiple groups and a "None" checkbox and conditional
message: 'GOV.UK Frontend is not supported in this browser'
})
})

it('throws when receiving the wrong type for $module', async () => {
await expect(
renderAndInitialise(page, 'checkboxes', {
params: examples.default,
beforeInitialisation() {
// Remove the root of the components as a way
// for the constructor to receive the wrong type for `$module`
document.querySelector('[data-module]').remove()
}
})
).rejects.toEqual({
name: 'TypeError',
message: 'Expected `$module` to be an instance of `HTMLElement`'
})
})
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,12 @@ export class ErrorSummary extends GOVUKFrontendComponent {
* @param {ErrorSummaryConfig} [config] - Error summary config
*/
constructor($module, config) {
super()

if (!($module instanceof HTMLElement)) {
return this
}

this.$module = $module
super($module)

this.config = mergeConfigs(
ErrorSummary.defaults,
config || {},
normaliseDataset($module.dataset)
normaliseDataset(this.$module.dataset)
)

this.setFocus()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
const {
goToComponent,
goToExample,
renderAndInitialise,
goTo
renderAndInitialise
} = require('@govuk-frontend/helpers/puppeteer')
const { getExamples } = require('@govuk-frontend/lib/components')

Expand Down Expand Up @@ -94,26 +93,6 @@ describe('Error Summary', () => {
})
})

describe('using JavaScript configuration, with no elements on the page', () => {
it('does not prevent further JavaScript from running', async () => {
await goTo(page, '/tests/boilerplate')

const result = await page.evaluate(async (exportName) => {
const namespace = await import('govuk-frontend')

// `undefined` simulates the element being missing,
// from an unchecked `document.querySelector` for example
/* eslint-disable-next-line no-new */
new namespace[exportName](undefined)

// If our component initialisation breaks, this won't run
return true
}, 'ErrorSummary')

expect(result).toBe(true)
})
})

describe('using JavaScript configuration, but enabled via data-attributes', () => {
beforeAll(async () => {
await renderAndInitialise(page, 'error-summary', {
Expand Down Expand Up @@ -251,5 +230,21 @@ describe('Error Summary', () => {
message: 'GOV.UK Frontend is not supported in this browser'
})
})

it('throws when receiving the wrong type for $module', async () => {
await expect(
renderAndInitialise(page, 'error-summary', {
params: examples.default,
beforeInitialisation() {
// Remove the root of the components as a way
// for the constructor to receive the wrong type for `$module`
document.querySelector('[data-module]').remove()
}
})
).rejects.toEqual({
name: 'TypeError',
message: 'Expected `$module` to be an instance of `HTMLElement`'
})
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,7 @@ export class ExitThisPage extends GOVUKFrontendComponent {
* @param {ExitThisPageConfig} [config] - Exit This Page config
*/
constructor($module, config) {
super()

if (!($module instanceof HTMLElement)) {
return this
}
super($module)

const $button = $module.querySelector('.govuk-exit-this-page__button')
if (!($button instanceof HTMLElement)) {
Expand All @@ -89,11 +85,10 @@ export class ExitThisPage extends GOVUKFrontendComponent {
this.config = mergeConfigs(
ExitThisPage.defaults,
config || {},
normaliseDataset($module.dataset)
normaliseDataset(this.$module.dataset)
)

this.i18n = new I18n(extractConfigByNamespace(this.config, 'i18n'))
this.$module = $module
this.$button = $button

const $skiplinkButton = document.querySelector(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,22 @@ describe('/components/exit-this-page', () => {
message: 'GOV.UK Frontend is not supported in this browser'
})
})

it('throws when receiving the wrong type for $module', async () => {
await expect(
renderAndInitialise(page, 'exit-this-page', {
params: examples.default,
beforeInitialisation() {
// Remove the root of the components as a way
// for the constructor to receive the wrong type for `$module`
document.querySelector('[data-module]').remove()
}
})
).rejects.toEqual({
name: 'TypeError',
message: 'Expected `$module` to be an instance of `HTMLElement`'
})
})
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,8 @@ export class Header extends GOVUKFrontendComponent {
* @param {Element} $module - HTML element to use for header
*/
constructor($module) {
super()
super($module)

if (!($module instanceof HTMLElement)) {
return this
}

this.$module = $module
this.$menuButton = $module.querySelector('.govuk-js-header-toggle')
this.$menu =
this.$menuButton &&
Expand Down
16 changes: 16 additions & 0 deletions packages/govuk-frontend/src/govuk/components/header/header.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,22 @@ describe('Header navigation', () => {
message: 'GOV.UK Frontend is not supported in this browser'
})
})

it('throws when receiving the wrong type for $module', async () => {
await expect(
renderAndInitialise(page, 'header', {
params: examples.default,
beforeInitialisation() {
// Remove the root of the components as a way
// for the constructor to receive the wrong type for `$module`
document.querySelector('[data-module]').remove()
}
})
).rejects.toEqual({
name: 'TypeError',
message: 'Expected `$module` to be an instance of `HTMLElement`'
})
})
})
})
})
Loading

0 comments on commit 893d9f5

Please sign in to comment.