Skip to content

Commit

Permalink
Add canInitialise to GOVUKFrontendComponent
Browse files Browse the repository at this point in the history
If `canInitialise` defined in class that extends GOVUKFrontendComponent
then `canInitialise` will be executed in `super()` before initialisation
routine and prevent child component from initialising.
  • Loading branch information
patrickpatrickpatrick committed Sep 18, 2024
1 parent 5987b57 commit b791a0a
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 4 deletions.
7 changes: 7 additions & 0 deletions packages/govuk-frontend/src/govuk/errors/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ export class ConfigError extends GOVUKFrontendError {
name = 'ConfigError'
}

/**
* Indicates that a component encountered a false `canInitialise` function call result
*/
export class CanInitError extends GOVUKFrontendError {
name = 'CanInitError'
}

/**
* Indicates an issue with an element (possibly `null` or `undefined`)
*/
Expand Down
17 changes: 14 additions & 3 deletions packages/govuk-frontend/src/govuk/govuk-frontend-component.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isInitialised, isSupported } from './common/index.mjs'
import { InitError, SupportError } from './errors/index.mjs'
import { InitError, SupportError, CanInitError } from './errors/index.mjs'

/**
* Base Component class
Expand All @@ -20,8 +20,18 @@ export class GOVUKFrontendComponent {
this.checkSupport()
this.checkInitialised($module)

const moduleName = /** @type {ChildClassConstructor} */ (this.constructor)
.moduleName
const childClassConstructor = /** @type {ChildClassConstructor} */ (
this.constructor
)

const moduleName = childClassConstructor.moduleName
const canInitialise = childClassConstructor.canInitialise

if (typeof canInitialise === 'function') {
if (!canInitialise()) {
throw new CanInitError('`canInitialise` returned `false`')
}
}

if (typeof moduleName === 'string') {
moduleName && $module?.setAttribute(`data-${moduleName}-init`, '')
Expand Down Expand Up @@ -62,6 +72,7 @@ export class GOVUKFrontendComponent {
/**
* @typedef ChildClass
* @property {string} [moduleName] - The module name that'll be looked for in the DOM when initialising the component
* @property {() => boolean} [canInitialise] - The module name that'll be looked for in the DOM when initialising the component
*/

/**
Expand Down
28 changes: 27 additions & 1 deletion packages/govuk-frontend/src/govuk/init.jsdom.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
} from '@govuk-frontend/lib/names'

import * as GOVUKFrontend from './all.mjs'
import { GOVUKFrontendComponent } from './govuk-frontend-component.mjs'
import { initAll, createAll } from './init.mjs'

// Annoyingly these don't get hoisted if done in a loop
Expand Down Expand Up @@ -226,8 +227,9 @@ describe('createAll', () => {
document.body.outerHTML = '<body></body>'
})

class MockComponent {
class MockComponent extends GOVUKFrontendComponent {
constructor(...args) {
super()
this.args = args
}

Expand Down Expand Up @@ -321,6 +323,30 @@ describe('createAll', () => {
expect(result[1].args).toStrictEqual([document.getElementById('b')])
})

describe('when a component defines canInitialise', () => {
class MockComponentWithCanInitialise extends MockComponent {
static canInitialise = () => {
return false
}
}

it('prints error and returns empty array if canInitialise returns false', () => {
document.body.innerHTML = `<div data-module="mock-component"></div>`

jest.spyOn(global.console, 'log').mockImplementation()

const result = createAll(MockComponentWithCanInitialise)

expect(global.console.log).toHaveBeenCalledWith(
expect.objectContaining({
message: '`canInitialise` returned `false`'
})
)

expect(result).toStrictEqual([])
})
})

describe('when a component accepts config', () => {
class MockComponentWithConfig extends MockComponent {
static defaults = {
Expand Down

0 comments on commit b791a0a

Please sign in to comment.