From 886b940796b3595a03b44230ca8b78197c5ee1c5 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Fri, 10 Dec 2021 18:18:18 +0200 Subject: [PATCH] Extract Component config functionality to a separate class (#33872) Co-authored-by: XhmikosR --- js/src/base-component.js | 26 ++++++----- js/src/carousel.js | 20 +++----- js/src/collapse.js | 19 +++----- js/src/dropdown.js | 14 ++---- js/src/modal.js | 27 +++-------- js/src/offcanvas.js | 29 ++++-------- js/src/popover.js | 8 ++-- js/src/scrollspy.js | 19 +++----- js/src/toast.js | 25 +++------- js/src/tooltip.js | 19 ++++---- js/src/util/backdrop.js | 27 +++++++---- js/src/util/config.js | 63 +++++++++++++++++++++++++ js/src/util/focustrap.js | 27 ++++++----- js/src/util/index.js | 16 +------ js/src/util/swipe.js | 28 ++++++----- js/src/util/template-factory.js | 31 ++++++------ js/tests/unit/util/config.spec.js | 78 +++++++++++++++++++++++++++++++ js/tests/unit/util/index.spec.js | 47 ------------------- 18 files changed, 283 insertions(+), 240 deletions(-) create mode 100644 js/src/util/config.js create mode 100644 js/tests/unit/util/config.spec.js diff --git a/js/src/base-component.js b/js/src/base-component.js index 3c5eb460ab..4140bf1947 100644 --- a/js/src/base-component.js +++ b/js/src/base-component.js @@ -6,11 +6,9 @@ */ import Data from './dom/data' -import { - executeAfterTransition, - getElement -} from './util/index' +import { executeAfterTransition, getElement } from './util/index' import EventHandler from './dom/event-handler' +import Config from './util/config' /** * Constants @@ -22,15 +20,18 @@ const VERSION = '5.1.3' * Class definition */ -class BaseComponent { - constructor(element) { - element = getElement(element) +class BaseComponent extends Config { + constructor(element, config) { + super() + element = getElement(element) if (!element) { return } this._element = element + this._config = this._getConfig(config) + Data.set(this._element, this.constructor.DATA_KEY, this) } @@ -48,6 +49,13 @@ class BaseComponent { executeAfterTransition(callback, element, isAnimated) } + _getConfig(config) { + config = this._mergeConfigObj(config, this._element) + config = this._configAfterMerge(config) + this._typeCheckConfig(config) + return config + } + // Static static getInstance(element) { return Data.get(getElement(element), this.DATA_KEY) @@ -61,10 +69,6 @@ class BaseComponent { return VERSION } - static get NAME() { - throw new Error('You have to implement the static method "NAME" for each component!') - } - static get DATA_KEY() { return `bs.${this.NAME}` } diff --git a/js/src/carousel.js b/js/src/carousel.js index 3589f22067..e50894aa81 100644 --- a/js/src/carousel.js +++ b/js/src/carousel.js @@ -12,8 +12,7 @@ import { isRTL, isVisible, reflow, - triggerTransitionEnd, - typeCheckConfig + triggerTransitionEnd } from './util/index' import EventHandler from './dom/event-handler' import Manipulator from './dom/manipulator' @@ -95,7 +94,7 @@ const DefaultType = { class Carousel extends BaseComponent { constructor(element, config) { - super(element) + super(element, config) this._items = null this._interval = null @@ -105,7 +104,6 @@ class Carousel extends BaseComponent { this.touchTimeout = null this._swipeHelper = null - this._config = this._getConfig(config) this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element) this._addEventListeners() } @@ -115,6 +113,10 @@ class Carousel extends BaseComponent { return Default } + static get DefaultType() { + return DefaultType + } + static get NAME() { return NAME } @@ -205,16 +207,6 @@ class Carousel extends BaseComponent { } // Private - _getConfig(config) { - config = { - ...Default, - ...Manipulator.getDataAttributes(this._element), - ...(typeof config === 'object' ? config : {}) - } - typeCheckConfig(NAME, config, DefaultType) - return config - } - _addEventListeners() { if (this._config.keyboard) { EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event)) diff --git a/js/src/collapse.js b/js/src/collapse.js index 642f7e840b..56d4f51c2d 100644 --- a/js/src/collapse.js +++ b/js/src/collapse.js @@ -10,11 +10,9 @@ import { getElement, getElementFromSelector, getSelectorFromElement, - reflow, - typeCheckConfig + reflow } from './util/index' import EventHandler from './dom/event-handler' -import Manipulator from './dom/manipulator' import SelectorEngine from './dom/selector-engine' import BaseComponent from './base-component' @@ -62,10 +60,9 @@ const DefaultType = { class Collapse extends BaseComponent { constructor(element, config) { - super(element) + super(element, config) this._isTransitioning = false - this._config = this._getConfig(config) this._triggerArray = [] const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE) @@ -96,6 +93,10 @@ class Collapse extends BaseComponent { return Default } + static get DefaultType() { + return DefaultType + } + static get NAME() { return NAME } @@ -210,15 +211,9 @@ class Collapse extends BaseComponent { } // Private - _getConfig(config) { - config = { - ...Default, - ...Manipulator.getDataAttributes(this._element), - ...config - } + _configAfterMerge(config) { config.toggle = Boolean(config.toggle) // Coerce string values config.parent = getElement(config.parent) - typeCheckConfig(NAME, config, DefaultType) return config } diff --git a/js/src/dropdown.js b/js/src/dropdown.js index c4e7baf295..674150e016 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -15,8 +15,7 @@ import { isElement, isRTL, isVisible, - noop, - typeCheckConfig + noop } from './util/index' import EventHandler from './dom/event-handler' import Manipulator from './dom/manipulator' @@ -88,10 +87,9 @@ const DefaultType = { class Dropdown extends BaseComponent { constructor(element, config) { - super(element) + super(element, config) this._popper = null - this._config = this._getConfig(config) this._menu = this._getMenuElement() this._inNavbar = this._detectNavbar() } @@ -205,13 +203,7 @@ class Dropdown extends BaseComponent { } _getConfig(config) { - config = { - ...this.constructor.Default, - ...Manipulator.getDataAttributes(this._element), - ...config - } - - typeCheckConfig(NAME, config, this.constructor.DefaultType) + config = super._getConfig(config) if (typeof config.reference === 'object' && !isElement(config.reference) && typeof config.reference.getBoundingClientRect !== 'function' diff --git a/js/src/modal.js b/js/src/modal.js index b8b1447746..569e6e5902 100644 --- a/js/src/modal.js +++ b/js/src/modal.js @@ -5,16 +5,8 @@ * -------------------------------------------------------------------------- */ -import { - defineJQueryPlugin, - getElementFromSelector, - isRTL, - isVisible, - reflow, - typeCheckConfig -} from './util/index' +import { defineJQueryPlugin, getElementFromSelector, isRTL, isVisible, reflow } from './util/index' import EventHandler from './dom/event-handler' -import Manipulator from './dom/manipulator' import SelectorEngine from './dom/selector-engine' import ScrollBarHelper from './util/scrollbar' import BaseComponent from './base-component' @@ -70,9 +62,8 @@ const DefaultType = { class Modal extends BaseComponent { constructor(element, config) { - super(element) + super(element, config) - this._config = this._getConfig(config) this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element) this._backdrop = this._initializeBackDrop() this._focustrap = this._initializeFocusTrap() @@ -86,6 +77,10 @@ class Modal extends BaseComponent { return Default } + static get DefaultType() { + return DefaultType + } + static get NAME() { return NAME } @@ -175,16 +170,6 @@ class Modal extends BaseComponent { }) } - _getConfig(config) { - config = { - ...Default, - ...Manipulator.getDataAttributes(this._element), - ...(typeof config === 'object' ? config : {}) - } - typeCheckConfig(NAME, config, DefaultType) - return config - } - _showElement(relatedTarget) { // try to append dynamic modal if (!document.body.contains(this._element)) { diff --git a/js/src/offcanvas.js b/js/src/offcanvas.js index 6878b1f628..acc0971fa2 100644 --- a/js/src/offcanvas.js +++ b/js/src/offcanvas.js @@ -9,14 +9,12 @@ import { defineJQueryPlugin, getElementFromSelector, isDisabled, - isVisible, - typeCheckConfig + isVisible } from './util/index' import ScrollBarHelper from './util/scrollbar' import EventHandler from './dom/event-handler' import BaseComponent from './base-component' import SelectorEngine from './dom/selector-engine' -import Manipulator from './dom/manipulator' import Backdrop from './util/backdrop' import FocusTrap from './util/focustrap' import { enableDismissTrigger } from './util/component-functions' @@ -63,9 +61,8 @@ const DefaultType = { class Offcanvas extends BaseComponent { constructor(element, config) { - super(element) + super(element, config) - this._config = this._getConfig(config) this._isShown = false this._backdrop = this._initializeBackDrop() this._focustrap = this._initializeFocusTrap() @@ -73,14 +70,18 @@ class Offcanvas extends BaseComponent { } // Getters - static get NAME() { - return NAME - } - static get Default() { return Default } + static get DefaultType() { + return DefaultType + } + + static get NAME() { + return NAME + } + // Public toggle(relatedTarget) { return this._isShown ? this.hide() : this.show(relatedTarget) @@ -162,16 +163,6 @@ class Offcanvas extends BaseComponent { } // Private - _getConfig(config) { - config = { - ...Default, - ...Manipulator.getDataAttributes(this._element), - ...(typeof config === 'object' ? config : {}) - } - typeCheckConfig(NAME, config, DefaultType) - return config - } - _initializeBackDrop() { return new Backdrop({ className: CLASS_NAME_BACKDROP, diff --git a/js/src/popover.js b/js/src/popover.js index 77f847110c..375eb8b0ab 100644 --- a/js/src/popover.js +++ b/js/src/popover.js @@ -60,6 +60,10 @@ class Popover extends Tooltip { return Default } + static get DefaultType() { + return DefaultType + } + static get NAME() { return NAME } @@ -68,10 +72,6 @@ class Popover extends Tooltip { return Event } - static get DefaultType() { - return DefaultType - } - // Overrides _isWithContent() { return this._getTitle() || this._getContent() diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js index 27bc0cd877..dc082a1b3a 100644 --- a/js/src/scrollspy.js +++ b/js/src/scrollspy.js @@ -8,8 +8,7 @@ import { defineJQueryPlugin, getElement, - getSelectorFromElement, - typeCheckConfig + getSelectorFromElement } from './util/index' import EventHandler from './dom/event-handler' import Manipulator from './dom/manipulator' @@ -62,9 +61,8 @@ const DefaultType = { class ScrollSpy extends BaseComponent { constructor(element, config) { - super(element) + super(element, config) this._scrollElement = this._element.tagName === 'BODY' ? window : this._element - this._config = this._getConfig(config) this._offsets = [] this._targets = [] this._activeTarget = null @@ -81,6 +79,10 @@ class ScrollSpy extends BaseComponent { return Default } + static get DefaultType() { + return DefaultType + } + static get NAME() { return NAME } @@ -135,17 +137,10 @@ class ScrollSpy extends BaseComponent { } // Private - _getConfig(config) { - config = { - ...Default, - ...Manipulator.getDataAttributes(this._element), - ...(typeof config === 'object' && config ? config : {}) - } + _configAfterMerge(config) { config.target = getElement(config.target) || document.documentElement - typeCheckConfig(NAME, config, DefaultType) - return config } diff --git a/js/src/toast.js b/js/src/toast.js index ba376d05ed..b85e20b605 100644 --- a/js/src/toast.js +++ b/js/src/toast.js @@ -5,9 +5,8 @@ * -------------------------------------------------------------------------- */ -import { defineJQueryPlugin, reflow, typeCheckConfig } from './util/index' +import { defineJQueryPlugin, reflow } from './util/index' import EventHandler from './dom/event-handler' -import Manipulator from './dom/manipulator' import BaseComponent from './base-component' import { enableDismissTrigger } from './util/component-functions' @@ -51,9 +50,8 @@ const Default = { class Toast extends BaseComponent { constructor(element, config) { - super(element) + super(element, config) - this._config = this._getConfig(config) this._timeout = null this._hasMouseInteraction = false this._hasKeyboardInteraction = false @@ -61,14 +59,14 @@ class Toast extends BaseComponent { } // Getters - static get DefaultType() { - return DefaultType - } - static get Default() { return Default } + static get DefaultType() { + return DefaultType + } + static get NAME() { return NAME } @@ -133,17 +131,6 @@ class Toast extends BaseComponent { } // Private - _getConfig(config) { - config = { - ...Default, - ...Manipulator.getDataAttributes(this._element), - ...(typeof config === 'object' && config ? config : {}) - } - - typeCheckConfig(NAME, config, this.constructor.DefaultType) - - return config - } _maybeScheduleHide() { if (!this._config.autohide) { diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 19a9b31685..9c8e54c66b 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -12,8 +12,7 @@ import { getElement, getUID, isRTL, - noop, - typeCheckConfig + noop } from './util/index' import { DefaultAllowlist } from './util/sanitizer' import EventHandler from './dom/event-handler' @@ -140,6 +139,10 @@ class Tooltip extends BaseComponent { return Default } + static get DefaultType() { + return DefaultType + } + static get NAME() { return NAME } @@ -148,10 +151,6 @@ class Tooltip extends BaseComponent { return Event } - static get DefaultType() { - return DefaultType - } - // Public enable() { this._isEnabled = true @@ -571,11 +570,16 @@ class Tooltip extends BaseComponent { } config = { - ...this.constructor.Default, ...dataAttributes, ...(typeof config === 'object' && config ? config : {}) } + config = this._mergeConfigObj(config) + config = this._configAfterMerge(config) + this._typeCheckConfig(config) + return config + } + _configAfterMerge(config) { config.container = config.container === false ? document.body : getElement(config.container) if (typeof config.delay === 'number') { @@ -595,7 +599,6 @@ class Tooltip extends BaseComponent { config.content = config.content.toString() } - typeCheckConfig(NAME, config, this.constructor.DefaultType) return config } diff --git a/js/src/util/backdrop.js b/js/src/util/backdrop.js index fb1b2776bc..63f2b581c6 100644 --- a/js/src/util/backdrop.js +++ b/js/src/util/backdrop.js @@ -6,7 +6,8 @@ */ import EventHandler from '../dom/event-handler' -import { execute, executeAfterTransition, getElement, reflow, typeCheckConfig } from './index' +import { execute, executeAfterTransition, getElement, reflow } from './index' +import Config from './config' /** * Constants @@ -37,13 +38,27 @@ const DefaultType = { * Class definition */ -class Backdrop { +class Backdrop extends Config { constructor(config) { + super() this._config = this._getConfig(config) this._isAppended = false this._element = null } + // Getters + static get Default() { + return Default + } + + static get DefaultType() { + return DefaultType + } + + static get NAME() { + return NAME + } + // Public show(callback) { if (!this._config.isVisible) { @@ -104,15 +119,9 @@ class Backdrop { return this._element } - _getConfig(config) { - config = { - ...Default, - ...(typeof config === 'object' ? config : {}) - } - + _configAfterMerge(config) { // use getElement() with the default "body" to get a fresh Element on each instantiation config.rootElement = getElement(config.rootElement) - typeCheckConfig(NAME, config, DefaultType) return config } diff --git a/js/src/util/config.js b/js/src/util/config.js new file mode 100644 index 0000000000..19d02955dd --- /dev/null +++ b/js/src/util/config.js @@ -0,0 +1,63 @@ +/** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): util/config.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + +import { isElement, toType } from './index' +import Manipulator from '../dom/manipulator' + +/** + * Class definition + */ + +class Config { + // Getters + static get Default() { + return {} + } + + static get DefaultType() { + return {} + } + + static get NAME() { + throw new Error('You have to implement the static method "NAME", for each component!') + } + + _getConfig(config) { + config = this._mergeConfigObj(config) + config = this._configAfterMerge(config) + this._typeCheckConfig(config) + return config + } + + _configAfterMerge(config) { + return config + } + + _mergeConfigObj(config, element) { + return { + ...this.constructor.Default, + ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}), + ...(typeof config === 'object' ? config : {}) + } + } + + _typeCheckConfig(config, configTypes = this.constructor.DefaultType) { + for (const property of Object.keys(configTypes)) { + const expectedTypes = configTypes[property] + const value = config[property] + const valueType = isElement(value) ? 'element' : toType(value) + + if (!new RegExp(expectedTypes).test(valueType)) { + throw new TypeError( + `${this.constructor.NAME.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".` + ) + } + } + } +} + +export default Config diff --git a/js/src/util/focustrap.js b/js/src/util/focustrap.js index a1975f4899..46727ecf8a 100644 --- a/js/src/util/focustrap.js +++ b/js/src/util/focustrap.js @@ -7,7 +7,7 @@ import EventHandler from '../dom/event-handler' import SelectorEngine from '../dom/selector-engine' -import { typeCheckConfig } from './index' +import Config from './config' /** * Constants @@ -37,13 +37,27 @@ const DefaultType = { * Class definition */ -class FocusTrap { +class FocusTrap extends Config { constructor(config) { + super() this._config = this._getConfig(config) this._isActive = false this._lastTabNavDirection = null } + // Getters + static get Default() { + return Default + } + + static get DefaultType() { + return DefaultType + } + + static get NAME() { + return NAME + } + // Public activate() { const { trapElement, autofocus } = this._config @@ -99,15 +113,6 @@ class FocusTrap { this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD } - - _getConfig(config) { - config = { - ...Default, - ...(typeof config === 'object' ? config : {}) - } - typeCheckConfig(NAME, config, DefaultType) - return config - } } export default FocusTrap diff --git a/js/src/util/index.js b/js/src/util/index.js index 0407100d8b..8bd614d40c 100644 --- a/js/src/util/index.js +++ b/js/src/util/index.js @@ -123,20 +123,6 @@ const getElement = object => { return null } -const typeCheckConfig = (componentName, config, configTypes) => { - for (const property of Object.keys(configTypes)) { - const expectedTypes = configTypes[property] - const value = config[property] - const valueType = value && isElement(value) ? 'element' : toType(value) - - if (!new RegExp(expectedTypes).test(valueType)) { - throw new TypeError( - `${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".` - ) - } - } -} - const isVisible = element => { if (!isElement(element) || element.getClientRects().length === 0) { return false @@ -327,5 +313,5 @@ export { onDOMContentLoaded, reflow, triggerTransitionEnd, - typeCheckConfig + toType } diff --git a/js/src/util/swipe.js b/js/src/util/swipe.js index 87a5f7f5ae..ac09b6fa13 100644 --- a/js/src/util/swipe.js +++ b/js/src/util/swipe.js @@ -5,8 +5,9 @@ * -------------------------------------------------------------------------- */ +import Config from './config' import EventHandler from '../dom/event-handler' -import { execute, typeCheckConfig } from './index' +import { execute } from './index' /** * Constants @@ -40,8 +41,9 @@ const DefaultType = { * Class definition */ -class Swipe { +class Swipe extends Config { constructor(element, config) { + super() this._element = element if (!element || !Swipe.isSupported()) { @@ -54,6 +56,19 @@ class Swipe { this._initEvents() } + // Getters + static get Default() { + return Default + } + + static get DefaultType() { + return DefaultType + } + + static get NAME() { + return NAME + } + // Public dispose() { EventHandler.off(this._element, EVENT_KEY) @@ -118,15 +133,6 @@ class Swipe { } } - _getConfig(config) { - config = { - ...Default, - ...(typeof config === 'object' ? config : {}) - } - typeCheckConfig(NAME, config, DefaultType) - return config - } - _eventIsPointerPenTouch(event) { return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH) } diff --git a/js/src/util/template-factory.js b/js/src/util/template-factory.js index a9cee1086c..8a8d4da798 100644 --- a/js/src/util/template-factory.js +++ b/js/src/util/template-factory.js @@ -6,8 +6,9 @@ */ import { DefaultAllowlist, sanitizeHtml } from './sanitizer' -import { getElement, isElement, typeCheckConfig } from '../util/index' +import { getElement, isElement } from '../util/index' import SelectorEngine from '../dom/selector-engine' +import Config from './config' /** * Constants @@ -44,20 +45,25 @@ const DefaultContentType = { * Class definition */ -class TemplateFactory { +class TemplateFactory extends Config { constructor(config) { + super() this._config = this._getConfig(config) } // Getters - static get NAME() { - return NAME - } - static get Default() { return Default } + static get DefaultType() { + return DefaultType + } + + static get NAME() { + return NAME + } + // Public getContent() { return Object.values(this._config.content) @@ -94,21 +100,14 @@ class TemplateFactory { } // Private - _getConfig(config) { - config = { - ...Default, - ...(typeof config === 'object' ? config : {}) - } - - typeCheckConfig(NAME, config, DefaultType) + _typeCheckConfig(config) { + super._typeCheckConfig(config) this._checkContent(config.content) - - return config } _checkContent(arg) { for (const [selector, content] of Object.entries(arg)) { - typeCheckConfig(NAME, { selector, entry: content }, DefaultContentType) + super._typeCheckConfig({ selector, entry: content }, DefaultContentType) } } diff --git a/js/tests/unit/util/config.spec.js b/js/tests/unit/util/config.spec.js new file mode 100644 index 0000000000..a8f8962ee3 --- /dev/null +++ b/js/tests/unit/util/config.spec.js @@ -0,0 +1,78 @@ +import Config from '../../../src/util/config' + +class DummyConfigClass extends Config { + static get NAME() { + return 'dummy' + } +} + +describe('Config', () => { + const name = 'dummy' + describe('NAME', () => { + it('should return plugin NAME', () => { + expect(DummyConfigClass.NAME).toEqual(name) + }) + }) + + describe('DefaultType', () => { + it('should return plugin default type', () => { + expect(DummyConfigClass.DefaultType).toEqual(jasmine.any(Object)) + }) + }) + + describe('Default', () => { + it('should return plugin defaults', () => { + expect(DummyConfigClass.Default).toEqual(jasmine.any(Object)) + }) + }) + + describe('typeCheckConfig', () => { + it('should check type of the config object', () => { + spyOnProperty(DummyConfigClass, 'DefaultType', 'get').and.returnValue({ + toggle: 'boolean', + parent: '(string|element)' + }) + const config = { + toggle: true, + parent: 777 + } + + const obj = new DummyConfigClass() + expect(() => { + obj._typeCheckConfig(config) + }).toThrowError(TypeError, obj.constructor.NAME.toUpperCase() + ': Option "parent" provided type "number" but expected type "(string|element)".') + }) + + it('should return null stringified when null is passed', () => { + spyOnProperty(DummyConfigClass, 'DefaultType', 'get').and.returnValue({ + toggle: 'boolean', + parent: '(null|element)' + }) + + const obj = new DummyConfigClass() + const config = { + toggle: true, + parent: null + } + + obj._typeCheckConfig(config) + expect().nothing() + }) + + it('should return undefined stringified when undefined is passed', () => { + spyOnProperty(DummyConfigClass, 'DefaultType', 'get').and.returnValue({ + toggle: 'boolean', + parent: '(undefined|element)' + }) + + const obj = new DummyConfigClass() + const config = { + toggle: true, + parent: undefined + } + + obj._typeCheckConfig(config) + expect().nothing() + }) + }) +}) diff --git a/js/tests/unit/util/index.spec.js b/js/tests/unit/util/index.spec.js index ef6647e921..52e64faa91 100644 --- a/js/tests/unit/util/index.spec.js +++ b/js/tests/unit/util/index.spec.js @@ -223,53 +223,6 @@ describe('Util', () => { }) }) - describe('typeCheckConfig', () => { - const namePlugin = 'collapse' - - it('should check type of the config object', () => { - const defaultType = { - toggle: 'boolean', - parent: '(string|element)' - } - const config = { - toggle: true, - parent: 777 - } - - expect(() => { - Util.typeCheckConfig(namePlugin, config, defaultType) - }).toThrowError(TypeError, 'COLLAPSE: Option "parent" provided type "number" but expected type "(string|element)".') - }) - - it('should return null stringified when null is passed', () => { - const defaultType = { - toggle: 'boolean', - parent: '(null|element)' - } - const config = { - toggle: true, - parent: null - } - - Util.typeCheckConfig(namePlugin, config, defaultType) - expect().nothing() - }) - - it('should return undefined stringified when undefined is passed', () => { - const defaultType = { - toggle: 'boolean', - parent: '(undefined|element)' - } - const config = { - toggle: true, - parent: undefined - } - - Util.typeCheckConfig(namePlugin, config, defaultType) - expect().nothing() - }) - }) - describe('isVisible', () => { it('should return false if the element is not defined', () => { expect(Util.isVisible(null)).toBeFalse()