aboutsummaryrefslogtreecommitdiff
path: root/js/tests/unit/util/index.spec.js
diff options
context:
space:
mode:
authorXhmikosR <[email protected]>2021-08-18 07:29:56 +0300
committerGitHub <[email protected]>2021-08-18 07:29:56 +0300
commit433a148c9e61aa942801fd8101dfa5c4045fdaed (patch)
treef41db59fd06019169df5ea0338213ec0e298f226 /js/tests/unit/util/index.spec.js
parentb97cfa163b5098db70e03b27c91fca5dde9c267e (diff)
parent18b3e1ac71f73d006756684a285c5a818e2d1454 (diff)
downloadbootstrap-global-focus-vars.tar.xz
bootstrap-global-focus-vars.zip
Merge branch 'main' into global-focus-varsglobal-focus-vars
Diffstat (limited to 'js/tests/unit/util/index.spec.js')
-rw-r--r--js/tests/unit/util/index.spec.js434
1 files changed, 394 insertions, 40 deletions
diff --git a/js/tests/unit/util/index.spec.js b/js/tests/unit/util/index.spec.js
index 935e021dd..38e94dc6b 100644
--- a/js/tests/unit/util/index.spec.js
+++ b/js/tests/unit/util/index.spec.js
@@ -1,7 +1,7 @@
import * as Util from '../../../src/util/index'
/** Test helpers */
-import { getFixture, clearFixture } from '../../helpers/fixture'
+import { clearFixture, getFixture } from '../../helpers/fixture'
describe('Util', () => {
let fixtureEl
@@ -157,12 +157,13 @@ describe('Util', () => {
describe('triggerTransitionEnd', () => {
it('should trigger transitionend event', done => {
- fixtureEl.innerHTML = '<div style="transition: all 300ms ease-out;"></div>'
+ fixtureEl.innerHTML = '<div></div>'
const el = fixtureEl.querySelector('div')
+ const spy = spyOn(el, 'dispatchEvent').and.callThrough()
el.addEventListener('transitionend', () => {
- expect().nothing()
+ expect(spy).toHaveBeenCalled()
done()
})
@@ -171,51 +172,58 @@ describe('Util', () => {
})
describe('isElement', () => {
- it('should detect if the parameter is an element or not', () => {
- fixtureEl.innerHTML = '<div></div>'
+ it('should detect if the parameter is an element or not and return Boolean', () => {
+ fixtureEl.innerHTML =
+ [
+ '<div id="foo" class="test"></div>',
+ '<div id="bar" class="test"></div>'
+ ].join('')
- const el = document.querySelector('div')
+ const el = fixtureEl.querySelector('#foo')
- expect(Util.isElement(el)).toEqual(el.nodeType)
- expect(Util.isElement({})).toEqual(undefined)
+ expect(Util.isElement(el)).toEqual(true)
+ expect(Util.isElement({})).toEqual(false)
+ expect(Util.isElement(fixtureEl.querySelectorAll('.test'))).toEqual(false)
})
it('should detect jQuery element', () => {
fixtureEl.innerHTML = '<div></div>'
- const el = document.querySelector('div')
+ const el = fixtureEl.querySelector('div')
const fakejQuery = {
- 0: el
+ 0: el,
+ jquery: 'foo'
}
- expect(Util.isElement(fakejQuery)).toEqual(el.nodeType)
+ expect(Util.isElement(fakejQuery)).toEqual(true)
})
})
- describe('emulateTransitionEnd', () => {
- it('should emulate transition end', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const el = document.querySelector('div')
- const spy = spyOn(window, 'setTimeout')
-
- Util.emulateTransitionEnd(el, 10)
- expect(spy).toHaveBeenCalled()
- })
-
- it('should not emulate transition end if already triggered', done => {
- fixtureEl.innerHTML = '<div></div>'
+ describe('getElement', () => {
+ it('should try to parse element', () => {
+ fixtureEl.innerHTML =
+ [
+ '<div id="foo" class="test"></div>',
+ '<div id="bar" class="test"></div>'
+ ].join('')
const el = fixtureEl.querySelector('div')
- const spy = spyOn(el, 'removeEventListener')
- Util.emulateTransitionEnd(el, 10)
- Util.triggerTransitionEnd(el)
+ expect(Util.getElement(el)).toEqual(el)
+ expect(Util.getElement('#foo')).toEqual(el)
+ expect(Util.getElement('#fail')).toBeNull()
+ expect(Util.getElement({})).toBeNull()
+ expect(Util.getElement([])).toBeNull()
+ expect(Util.getElement()).toBeNull()
+ expect(Util.getElement(null)).toBeNull()
+ expect(Util.getElement(fixtureEl.querySelectorAll('.test'))).toBeNull()
+
+ const fakejQueryObject = {
+ 0: el,
+ jquery: 'foo'
+ }
- setTimeout(() => {
- expect(spy).toHaveBeenCalled()
- done()
- }, 20)
+ expect(Util.getElement(fakejQueryObject)).toEqual(el)
})
})
@@ -292,10 +300,14 @@ describe('Util', () => {
expect(Util.isVisible(div)).toEqual(false)
})
- it('should return false if the parent element is not visible', () => {
+ it('should return false if an ancestor element is display none', () => {
fixtureEl.innerHTML = [
'<div style="display: none;">',
- ' <div class="content"></div>',
+ ' <div>',
+ ' <div>',
+ ' <div class="content"></div>',
+ ' </div>',
+ ' </div>',
'</div>'
].join('')
@@ -304,6 +316,38 @@ describe('Util', () => {
expect(Util.isVisible(div)).toEqual(false)
})
+ it('should return false if an ancestor element is visibility hidden', () => {
+ fixtureEl.innerHTML = [
+ '<div style="visibility: hidden;">',
+ ' <div>',
+ ' <div>',
+ ' <div class="content"></div>',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const div = fixtureEl.querySelector('.content')
+
+ expect(Util.isVisible(div)).toEqual(false)
+ })
+
+ it('should return true if an ancestor element is visibility hidden, but reverted', () => {
+ fixtureEl.innerHTML = [
+ '<div style="visibility: hidden;">',
+ ' <div style="visibility: visible;">',
+ ' <div>',
+ ' <div class="content"></div>',
+ ' </div>',
+ ' </div>',
+ '</div>'
+ ].join('')
+
+ const div = fixtureEl.querySelector('.content')
+
+ expect(Util.isVisible(div)).toEqual(true)
+ })
+
it('should return true if the element is visible', () => {
fixtureEl.innerHTML = [
'<div>',
@@ -315,6 +359,126 @@ describe('Util', () => {
expect(Util.isVisible(div)).toEqual(true)
})
+
+ it('should return false if the element is hidden, but not via display or visibility', () => {
+ fixtureEl.innerHTML = [
+ '<details>',
+ ' <div id="element"></div>',
+ '</details>'
+ ].join('')
+
+ const div = fixtureEl.querySelector('#element')
+
+ expect(Util.isVisible(div)).toEqual(false)
+ })
+ })
+
+ describe('isDisabled', () => {
+ it('should return true if the element is not defined', () => {
+ expect(Util.isDisabled(null)).toEqual(true)
+ expect(Util.isDisabled(undefined)).toEqual(true)
+ expect(Util.isDisabled()).toEqual(true)
+ })
+
+ it('should return true if the element provided is not a dom element', () => {
+ expect(Util.isDisabled({})).toEqual(true)
+ expect(Util.isDisabled('test')).toEqual(true)
+ })
+
+ it('should return true if the element has disabled attribute', () => {
+ fixtureEl.innerHTML = [
+ '<div>',
+ ' <div id="element" disabled="disabled"></div>',
+ ' <div id="element1" disabled="true"></div>',
+ ' <div id="element2" disabled></div>',
+ '</div>'
+ ].join('')
+
+ const div = fixtureEl.querySelector('#element')
+ const div1 = fixtureEl.querySelector('#element1')
+ const div2 = fixtureEl.querySelector('#element2')
+
+ expect(Util.isDisabled(div)).toEqual(true)
+ expect(Util.isDisabled(div1)).toEqual(true)
+ expect(Util.isDisabled(div2)).toEqual(true)
+ })
+
+ it('should return false if the element has disabled attribute with "false" value, or doesn\'t have attribute', () => {
+ fixtureEl.innerHTML = [
+ '<div>',
+ ' <div id="element" disabled="false"></div>',
+ ' <div id="element1" ></div>',
+ '</div>'
+ ].join('')
+
+ const div = fixtureEl.querySelector('#element')
+ const div1 = fixtureEl.querySelector('#element1')
+
+ expect(Util.isDisabled(div)).toEqual(false)
+ expect(Util.isDisabled(div1)).toEqual(false)
+ })
+
+ it('should return false if the element is not disabled ', () => {
+ fixtureEl.innerHTML = [
+ '<div>',
+ ' <button id="button"></button>',
+ ' <select id="select"></select>',
+ ' <select id="input"></select>',
+ '</div>'
+ ].join('')
+
+ const el = selector => fixtureEl.querySelector(selector)
+
+ expect(Util.isDisabled(el('#button'))).toEqual(false)
+ expect(Util.isDisabled(el('#select'))).toEqual(false)
+ expect(Util.isDisabled(el('#input'))).toEqual(false)
+ })
+ it('should return true if the element has disabled attribute', () => {
+ fixtureEl.innerHTML = [
+ '<div>',
+ ' <input id="input" disabled="disabled"/>',
+ ' <input id="input1" disabled="disabled"/>',
+ ' <button id="button" disabled="true"></button>',
+ ' <button id="button1" disabled="disabled"></button>',
+ ' <button id="button2" disabled></button>',
+ ' <select id="select" disabled></select>',
+ ' <select id="input" disabled></select>',
+ '</div>'
+ ].join('')
+
+ const el = selector => fixtureEl.querySelector(selector)
+
+ expect(Util.isDisabled(el('#input'))).toEqual(true)
+ expect(Util.isDisabled(el('#input1'))).toEqual(true)
+ expect(Util.isDisabled(el('#button'))).toEqual(true)
+ expect(Util.isDisabled(el('#button1'))).toEqual(true)
+ expect(Util.isDisabled(el('#button2'))).toEqual(true)
+ expect(Util.isDisabled(el('#input'))).toEqual(true)
+ })
+
+ it('should return true if the element has class "disabled"', () => {
+ fixtureEl.innerHTML = [
+ '<div>',
+ ' <div id="element" class="disabled"></div>',
+ '</div>'
+ ].join('')
+
+ const div = fixtureEl.querySelector('#element')
+
+ expect(Util.isDisabled(div)).toEqual(true)
+ })
+
+ it('should return true if the element has class "disabled" but disabled attribute is false', () => {
+ fixtureEl.innerHTML = [
+ '<div>',
+ ' <input id="input" class="disabled" disabled="false"/>',
+ '</div>'
+ ].join('')
+
+ const div = fixtureEl.querySelector('#input')
+
+ expect(Util.isDisabled(div)).toEqual(true)
+ })
})
describe('findShadowRoot', () => {
@@ -369,8 +533,8 @@ describe('Util', () => {
})
describe('noop', () => {
- it('should return a function', () => {
- expect(typeof Util.noop()).toEqual('function')
+ it('should be a function', () => {
+ expect(typeof Util.noop).toEqual('function')
})
})
@@ -379,8 +543,9 @@ describe('Util', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
-
- expect(Util.reflow(div)).toEqual(0)
+ const spy = spyOnProperty(div, 'offsetHeight')
+ Util.reflow(div)
+ expect(spy).toHaveBeenCalled()
})
})
@@ -418,15 +583,24 @@ describe('Util', () => {
})
describe('onDOMContentLoaded', () => {
- it('should execute callback when DOMContentLoaded is fired', () => {
+ it('should execute callbacks when DOMContentLoaded is fired and should not add more than one listener', () => {
const spy = jasmine.createSpy()
+ const spy2 = jasmine.createSpy()
+
+ spyOn(document, 'addEventListener').and.callThrough()
spyOnProperty(document, 'readyState').and.returnValue('loading')
+
Util.onDOMContentLoaded(spy)
- window.document.dispatchEvent(new Event('DOMContentLoaded', {
+ Util.onDOMContentLoaded(spy2)
+
+ document.dispatchEvent(new Event('DOMContentLoaded', {
bubbles: true,
cancelable: true
}))
+
expect(spy).toHaveBeenCalled()
+ expect(spy2).toHaveBeenCalled()
+ expect(document.addEventListener).toHaveBeenCalledTimes(1)
})
it('should execute callback if readyState is not "loading"', () => {
@@ -452,12 +626,192 @@ describe('Util', () => {
it('should define a plugin on the jQuery instance', () => {
const pluginMock = function () {}
+ pluginMock.NAME = 'test'
pluginMock.jQueryInterface = function () {}
- Util.defineJQueryPlugin('test', pluginMock)
+ Util.defineJQueryPlugin(pluginMock)
expect(fakejQuery.fn.test).toBe(pluginMock.jQueryInterface)
expect(fakejQuery.fn.test.Constructor).toBe(pluginMock)
expect(typeof fakejQuery.fn.test.noConflict).toEqual('function')
})
})
+
+ describe('execute', () => {
+ it('should execute if arg is function', () => {
+ const spy = jasmine.createSpy('spy')
+ Util.execute(spy)
+ expect(spy).toHaveBeenCalled()
+ })
+ })
+
+ describe('executeAfterTransition', () => {
+ it('should immediately execute a function when waitForTransition parameter is false', () => {
+ const el = document.createElement('div')
+ const callbackSpy = jasmine.createSpy('callback spy')
+ const eventListenerSpy = spyOn(el, 'addEventListener')
+
+ Util.executeAfterTransition(callbackSpy, el, false)
+
+ expect(callbackSpy).toHaveBeenCalled()
+ expect(eventListenerSpy).not.toHaveBeenCalled()
+ })
+
+ it('should execute a function when a transitionend event is dispatched', () => {
+ const el = document.createElement('div')
+ const callbackSpy = jasmine.createSpy('callback spy')
+
+ spyOn(window, 'getComputedStyle').and.returnValue({
+ transitionDuration: '0.05s',
+ transitionDelay: '0s'
+ })
+
+ Util.executeAfterTransition(callbackSpy, el)
+
+ el.dispatchEvent(new TransitionEvent('transitionend'))
+
+ expect(callbackSpy).toHaveBeenCalled()
+ })
+
+ it('should execute a function after a computed CSS transition duration and there was no transitionend event dispatched', done => {
+ const el = document.createElement('div')
+ const callbackSpy = jasmine.createSpy('callback spy')
+
+ spyOn(window, 'getComputedStyle').and.returnValue({
+ transitionDuration: '0.05s',
+ transitionDelay: '0s'
+ })
+
+ Util.executeAfterTransition(callbackSpy, el)
+
+ setTimeout(() => {
+ expect(callbackSpy).toHaveBeenCalled()
+ done()
+ }, 70)
+ })
+
+ it('should not execute a function a second time after a computed CSS transition duration and if a transitionend event has already been dispatched', done => {
+ const el = document.createElement('div')
+ const callbackSpy = jasmine.createSpy('callback spy')
+
+ spyOn(window, 'getComputedStyle').and.returnValue({
+ transitionDuration: '0.05s',
+ transitionDelay: '0s'
+ })
+
+ Util.executeAfterTransition(callbackSpy, el)
+
+ setTimeout(() => {
+ el.dispatchEvent(new TransitionEvent('transitionend'))
+ }, 50)
+
+ setTimeout(() => {
+ expect(callbackSpy).toHaveBeenCalledTimes(1)
+ done()
+ }, 70)
+ })
+
+ it('should not trigger a transitionend event if another transitionend event had already happened', done => {
+ const el = document.createElement('div')
+
+ spyOn(window, 'getComputedStyle').and.returnValue({
+ transitionDuration: '0.05s',
+ transitionDelay: '0s'
+ })
+
+ Util.executeAfterTransition(() => {}, el)
+
+ // simulate a event dispatched by the browser
+ el.dispatchEvent(new TransitionEvent('transitionend'))
+
+ const dispatchSpy = spyOn(el, 'dispatchEvent').and.callThrough()
+
+ setTimeout(() => {
+ // setTimeout should not have triggered another transitionend event.
+ expect(dispatchSpy).not.toHaveBeenCalled()
+ done()
+ }, 70)
+ })
+
+ it('should ignore transitionend events from nested elements', done => {
+ fixtureEl.innerHTML = [
+ '<div class="outer">',
+ ' <div class="nested"></div>',
+ '</div>'
+ ].join('')
+
+ const outer = fixtureEl.querySelector('.outer')
+ const nested = fixtureEl.querySelector('.nested')
+ const callbackSpy = jasmine.createSpy('callback spy')
+
+ spyOn(window, 'getComputedStyle').and.returnValue({
+ transitionDuration: '0.05s',
+ transitionDelay: '0s'
+ })
+
+ Util.executeAfterTransition(callbackSpy, outer)
+
+ nested.dispatchEvent(new TransitionEvent('transitionend', {
+ bubbles: true
+ }))
+
+ setTimeout(() => {
+ expect(callbackSpy).not.toHaveBeenCalled()
+ }, 20)
+
+ setTimeout(() => {
+ expect(callbackSpy).toHaveBeenCalled()
+ done()
+ }, 70)
+ })
+ })
+
+ describe('getNextActiveElement', () => {
+ it('should return first element if active not exists or not given and shouldGetNext is either true, or false with cycling being disabled', () => {
+ const array = ['a', 'b', 'c', 'd']
+
+ expect(Util.getNextActiveElement(array, '', true, true)).toEqual('a')
+ expect(Util.getNextActiveElement(array, 'g', true, true)).toEqual('a')
+ expect(Util.getNextActiveElement(array, '', true, false)).toEqual('a')
+ expect(Util.getNextActiveElement(array, 'g', true, false)).toEqual('a')
+ expect(Util.getNextActiveElement(array, '', false, false)).toEqual('a')
+ expect(Util.getNextActiveElement(array, 'g', false, false)).toEqual('a')
+ })
+
+ it('should return last element if active not exists or not given and shouldGetNext is false but cycling is enabled', () => {
+ const array = ['a', 'b', 'c', 'd']
+
+ expect(Util.getNextActiveElement(array, '', false, true)).toEqual('d')
+ expect(Util.getNextActiveElement(array, 'g', false, true)).toEqual('d')
+ })
+
+ it('should return next element or same if is last', () => {
+ const array = ['a', 'b', 'c', 'd']
+
+ expect(Util.getNextActiveElement(array, 'a', true, true)).toEqual('b')
+ expect(Util.getNextActiveElement(array, 'b', true, true)).toEqual('c')
+ expect(Util.getNextActiveElement(array, 'd', true, false)).toEqual('d')
+ })
+
+ it('should return next element or first, if is last and "isCycleAllowed = true"', () => {
+ const array = ['a', 'b', 'c', 'd']
+
+ expect(Util.getNextActiveElement(array, 'c', true, true)).toEqual('d')
+ expect(Util.getNextActiveElement(array, 'd', true, true)).toEqual('a')
+ })
+
+ it('should return previous element or same if is first', () => {
+ const array = ['a', 'b', 'c', 'd']
+
+ expect(Util.getNextActiveElement(array, 'b', false, true)).toEqual('a')
+ expect(Util.getNextActiveElement(array, 'd', false, true)).toEqual('c')
+ expect(Util.getNextActiveElement(array, 'a', false, false)).toEqual('a')
+ })
+
+ it('should return next element or first, if is last and "isCycleAllowed = true"', () => {
+ const array = ['a', 'b', 'c', 'd']
+
+ expect(Util.getNextActiveElement(array, 'd', false, true)).toEqual('c')
+ expect(Util.getNextActiveElement(array, 'a', false, true)).toEqual('d')
+ })
+ })
})