aboutsummaryrefslogtreecommitdiff
path: root/js/tests/unit/dom
diff options
context:
space:
mode:
authorXhmikosR <[email protected]>2019-10-09 01:27:43 +0300
committerGitHub <[email protected]>2019-10-09 01:27:43 +0300
commit577bf8b14d76a864a8d69dbfb03b757fbeb6e241 (patch)
tree354238ff0aaca853a9698c191eeb4c2143c39c16 /js/tests/unit/dom
parent1770691b339bdbf17de5e8824158b358dc0284a9 (diff)
downloadbootstrap-577bf8b14d76a864a8d69dbfb03b757fbeb6e241.tar.xz
bootstrap-577bf8b14d76a864a8d69dbfb03b757fbeb6e241.zip
Rename "js/tests/units" to "js/tests/unit". (#29503)
Diffstat (limited to 'js/tests/unit/dom')
-rw-r--r--js/tests/unit/dom/data.spec.js131
-rw-r--r--js/tests/unit/dom/event-handler.spec.js327
-rw-r--r--js/tests/unit/dom/manipulator.spec.js158
-rw-r--r--js/tests/unit/dom/selector-engine.spec.js115
4 files changed, 731 insertions, 0 deletions
diff --git a/js/tests/unit/dom/data.spec.js b/js/tests/unit/dom/data.spec.js
new file mode 100644
index 000000000..ab3240b9b
--- /dev/null
+++ b/js/tests/unit/dom/data.spec.js
@@ -0,0 +1,131 @@
+import Data from '../../../src/dom/data'
+
+/** Test helpers */
+import { getFixture, clearFixture } from '../../helpers/fixture'
+
+describe('Data', () => {
+ let fixtureEl
+
+ beforeAll(() => {
+ fixtureEl = getFixture()
+ })
+
+ afterEach(() => {
+ clearFixture()
+ })
+
+ describe('setData', () => {
+ it('should set data in an element by adding a key attribute', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+ const data = {
+ test: 'bsData'
+ }
+
+ Data.setData(div, 'test', data)
+ expect(div.key).toBeDefined()
+ })
+
+ it('should change data if something is already stored', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+ const data = {
+ test: 'bsData'
+ }
+
+ Data.setData(div, 'test', data)
+
+ data.test = 'bsData2'
+ Data.setData(div, 'test', data)
+
+ expect(div.key).toBeDefined()
+ })
+ })
+
+ describe('getData', () => {
+ it('should return stored data', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+ const data = {
+ test: 'bsData'
+ }
+
+ Data.setData(div, 'test', data)
+ expect(Data.getData(div, 'test')).toEqual(data)
+ })
+
+ it('should return null on undefined element', () => {
+ expect(Data.getData(null)).toEqual(null)
+ expect(Data.getData(undefined)).toEqual(null)
+ })
+
+ it('should return null when an element have nothing stored', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ expect(Data.getData(div, 'test')).toEqual(null)
+ })
+
+ it('should return null when an element have nothing stored with the provided key', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+ const data = {
+ test: 'bsData'
+ }
+
+ Data.setData(div, 'test', data)
+
+ expect(Data.getData(div, 'test2')).toEqual(null)
+ })
+ })
+
+ describe('removeData', () => {
+ it('should do nothing when an element have nothing stored', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ Data.removeData(div, 'test')
+ expect().nothing()
+ })
+
+ it('should should do nothing if it\'s not a valid key provided', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+ const data = {
+ test: 'bsData'
+ }
+
+ Data.setData(div, 'test', data)
+
+ expect(div.key).toBeDefined()
+
+ Data.removeData(div, 'test2')
+
+ expect(div.key).toBeDefined()
+ })
+
+ it('should remove data if something is stored', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+ const data = {
+ test: 'bsData'
+ }
+
+ Data.setData(div, 'test', data)
+
+ expect(div.key).toBeDefined()
+
+ Data.removeData(div, 'test')
+
+ expect(div.key).toBeUndefined()
+ })
+ })
+})
diff --git a/js/tests/unit/dom/event-handler.spec.js b/js/tests/unit/dom/event-handler.spec.js
new file mode 100644
index 000000000..5551ddaa3
--- /dev/null
+++ b/js/tests/unit/dom/event-handler.spec.js
@@ -0,0 +1,327 @@
+import EventHandler from '../../../src/dom/event-handler'
+
+/** Test helpers */
+import { getFixture, clearFixture } from '../../helpers/fixture'
+
+describe('EventHandler', () => {
+ let fixtureEl
+
+ beforeAll(() => {
+ fixtureEl = getFixture()
+ })
+
+ afterEach(() => {
+ clearFixture()
+ })
+
+ describe('on', () => {
+ it('should not add event listener if the event is not a string', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ EventHandler.on(div, null, () => {})
+ EventHandler.on(null, 'click', () => {})
+
+ expect().nothing()
+ })
+
+ it('should add event listener', done => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ EventHandler.on(div, 'click', () => {
+ expect().nothing()
+ done()
+ })
+
+ div.click()
+ })
+
+ it('should add namespaced event listener', done => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ EventHandler.on(div, 'bs.namespace', () => {
+ expect().nothing()
+ done()
+ })
+
+ EventHandler.trigger(div, 'bs.namespace')
+ })
+
+ it('should add native namespaced event listener', done => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ EventHandler.on(div, 'click.namespace', () => {
+ expect().nothing()
+ done()
+ })
+
+ EventHandler.trigger(div, 'click')
+ })
+
+ it('should handle event delegation', done => {
+ EventHandler.on(document, 'click', '.test', () => {
+ expect().nothing()
+ done()
+ })
+
+ fixtureEl.innerHTML = '<div class="test"></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ div.click()
+ })
+ })
+
+ describe('one', () => {
+ it('should call listener just one', done => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ let called = 0
+ const div = fixtureEl.querySelector('div')
+ const obj = {
+ oneListener() {
+ called++
+ }
+ }
+
+ EventHandler.one(div, 'bootstrap', obj.oneListener)
+
+ EventHandler.trigger(div, 'bootstrap')
+ EventHandler.trigger(div, 'bootstrap')
+
+ setTimeout(() => {
+ expect(called).toEqual(1)
+ done()
+ }, 20)
+ })
+ })
+
+ describe('off', () => {
+ it('should not remove a listener', () => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
+
+ EventHandler.off(div, null, () => {})
+ EventHandler.off(null, 'click', () => {})
+ expect().nothing()
+ })
+
+ it('should remove a listener', done => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
+
+ let called = 0
+ const handler = () => {
+ called++
+ }
+
+ EventHandler.on(div, 'foobar', handler)
+ EventHandler.trigger(div, 'foobar')
+
+ EventHandler.off(div, 'foobar', handler)
+ EventHandler.trigger(div, 'foobar')
+
+ setTimeout(() => {
+ expect(called).toEqual(1)
+ done()
+ }, 20)
+ })
+
+ it('should remove all the events', done => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
+
+ let called = 0
+
+ EventHandler.on(div, 'foobar', () => {
+ called++
+ })
+ EventHandler.on(div, 'foobar', () => {
+ called++
+ })
+ EventHandler.trigger(div, 'foobar')
+
+ EventHandler.off(div, 'foobar')
+ EventHandler.trigger(div, 'foobar')
+
+ setTimeout(() => {
+ expect(called).toEqual(2)
+ done()
+ }, 20)
+ })
+
+ it('should remove all the namespaced listeners if namespace is passed', done => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
+
+ let called = 0
+
+ EventHandler.on(div, 'foobar.namespace', () => {
+ called++
+ })
+ EventHandler.on(div, 'foofoo.namespace', () => {
+ called++
+ })
+ EventHandler.trigger(div, 'foobar.namespace')
+ EventHandler.trigger(div, 'foofoo.namespace')
+
+ EventHandler.off(div, '.namespace')
+ EventHandler.trigger(div, 'foobar.namespace')
+ EventHandler.trigger(div, 'foofoo.namespace')
+
+ setTimeout(() => {
+ expect(called).toEqual(2)
+ done()
+ }, 20)
+ })
+
+ it('should remove the namespaced listeners', done => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
+
+ let calledCallback1 = 0
+ let calledCallback2 = 0
+
+ EventHandler.on(div, 'foobar.namespace', () => {
+ calledCallback1++
+ })
+ EventHandler.on(div, 'foofoo.namespace', () => {
+ calledCallback2++
+ })
+
+ EventHandler.trigger(div, 'foobar.namespace')
+ EventHandler.off(div, 'foobar.namespace')
+ EventHandler.trigger(div, 'foobar.namespace')
+
+ EventHandler.trigger(div, 'foofoo.namespace')
+
+ setTimeout(() => {
+ expect(calledCallback1).toEqual(1)
+ expect(calledCallback2).toEqual(1)
+ done()
+ }, 20)
+ })
+
+ it('should remove the all the namespaced listeners for native events', done => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
+
+ let called = 0
+
+ EventHandler.on(div, 'click.namespace', () => {
+ called++
+ })
+ EventHandler.on(div, 'click.namespace2', () => {
+ called++
+ })
+
+ EventHandler.trigger(div, 'click')
+ EventHandler.off(div, 'click')
+ EventHandler.trigger(div, 'click')
+
+ setTimeout(() => {
+ expect(called).toEqual(2)
+ done()
+ }, 20)
+ })
+
+ it('should remove the specified namespaced listeners for native events', done => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
+
+ let called1 = 0
+ let called2 = 0
+
+ EventHandler.on(div, 'click.namespace', () => {
+ called1++
+ })
+ EventHandler.on(div, 'click.namespace2', () => {
+ called2++
+ })
+ EventHandler.trigger(div, 'click')
+
+ EventHandler.off(div, 'click.namespace')
+ EventHandler.trigger(div, 'click')
+
+ setTimeout(() => {
+ expect(called1).toEqual(1)
+ expect(called2).toEqual(2)
+ done()
+ }, 20)
+ })
+
+ it('should remove a listener registered by .one', done => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+ const handler = () => {
+ throw new Error('called')
+ }
+
+ EventHandler.one(div, 'foobar', handler)
+ EventHandler.off(div, 'foobar', handler)
+
+ EventHandler.trigger(div, 'foobar')
+ setTimeout(() => {
+ expect().nothing()
+ done()
+ }, 20)
+ })
+
+ it('should remove the correct delegated event listener', () => {
+ const element = document.createElement('div')
+ const subelement = document.createElement('span')
+ element.appendChild(subelement)
+
+ const anchor = document.createElement('a')
+ element.appendChild(anchor)
+
+ let i = 0
+ const handler = () => {
+ i++
+ }
+
+ EventHandler.on(element, 'click', 'a', handler)
+ EventHandler.on(element, 'click', 'span', handler)
+
+ fixtureEl.appendChild(element)
+
+ EventHandler.trigger(anchor, 'click')
+ EventHandler.trigger(subelement, 'click')
+
+ // first listeners called
+ expect(i === 2).toEqual(true)
+
+ EventHandler.off(element, 'click', 'span', handler)
+ EventHandler.trigger(subelement, 'click')
+
+ // removed listener not called
+ expect(i === 2).toEqual(true)
+
+ EventHandler.trigger(anchor, 'click')
+
+ // not removed listener called
+ expect(i === 3).toEqual(true)
+
+ EventHandler.on(element, 'click', 'span', handler)
+ EventHandler.trigger(anchor, 'click')
+ EventHandler.trigger(subelement, 'click')
+
+ // listener re-registered
+ expect(i === 5).toEqual(true)
+
+ EventHandler.off(element, 'click', 'span')
+ EventHandler.trigger(subelement, 'click')
+
+ // listener removed again
+ expect(i === 5).toEqual(true)
+ })
+ })
+})
diff --git a/js/tests/unit/dom/manipulator.spec.js b/js/tests/unit/dom/manipulator.spec.js
new file mode 100644
index 000000000..986f69298
--- /dev/null
+++ b/js/tests/unit/dom/manipulator.spec.js
@@ -0,0 +1,158 @@
+import Manipulator from '../../../src/dom/manipulator'
+
+/** Test helpers */
+import { getFixture, clearFixture } from '../../helpers/fixture'
+
+describe('Manipulator', () => {
+ let fixtureEl
+
+ beforeAll(() => {
+ fixtureEl = getFixture()
+ })
+
+ afterEach(() => {
+ clearFixture()
+ })
+
+ describe('setDataAttribute', () => {
+ it('should set data attribute', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ Manipulator.setDataAttribute(div, 'key', 'value')
+ expect(div.getAttribute('data-key')).toEqual('value')
+ })
+
+ it('should set data attribute in lower case', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ Manipulator.setDataAttribute(div, 'tEsT', 'value')
+ expect(div.getAttribute('data-test')).toEqual('value')
+ })
+ })
+
+ describe('removeDataAttribute', () => {
+ it('should remove data attribute', () => {
+ fixtureEl.innerHTML = '<div data-key="value"></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ Manipulator.removeDataAttribute(div, 'key')
+ expect(div.getAttribute('data-key')).toBeNull()
+ })
+
+ it('should remove data attribute in lower case', () => {
+ fixtureEl.innerHTML = '<div data-testkey="value" ></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ Manipulator.removeDataAttribute(div, 'tEStKeY')
+ expect(div.getAttribute('data-testkey')).toBeNull()
+ })
+ })
+
+ describe('getDataAttributes', () => {
+ it('should return empty object for null', () => {
+ expect(Manipulator.getDataAttributes(null), {})
+ expect().nothing()
+ })
+
+ it('should get all data attributes', () => {
+ fixtureEl.innerHTML = '<div data-test="js" data-test2="js2" ></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ expect(Manipulator.getDataAttributes(div)).toEqual({
+ test: 'js',
+ test2: 'js2'
+ })
+ })
+ })
+
+ describe('getDataAttribute', () => {
+ it('should get data attribute', () => {
+ fixtureEl.innerHTML = '<div data-test="null" ></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ expect(Manipulator.getDataAttribute(div, 'test')).toBeNull()
+ })
+
+ it('should get data attribute in lower case', () => {
+ fixtureEl.innerHTML = '<div data-test="value" ></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ expect(Manipulator.getDataAttribute(div, 'tEsT')).toEqual('value')
+ })
+
+ it('should normalize data', () => {
+ fixtureEl.innerHTML = '<div data-test="false" ></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ expect(Manipulator.getDataAttribute(div, 'test')).toEqual(false)
+
+ div.setAttribute('data-test', 'true')
+ expect(Manipulator.getDataAttribute(div, 'test')).toEqual(true)
+
+ div.setAttribute('data-test', '1')
+ expect(Manipulator.getDataAttribute(div, 'test')).toEqual(1)
+ })
+ })
+
+ describe('offset', () => {
+ it('should return object with two properties top and left, both numbers', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+ const offset = Manipulator.offset(div)
+
+ expect(offset).toBeDefined()
+ expect(offset.top).toEqual(jasmine.any(Number))
+ expect(offset.left).toEqual(jasmine.any(Number))
+ })
+ })
+
+ describe('position', () => {
+ it('should return object with two properties top and left, both numbers', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+ const position = Manipulator.position(div)
+
+ expect(position).toBeDefined()
+ expect(position.top).toEqual(jasmine.any(Number))
+ expect(position.left).toEqual(jasmine.any(Number))
+ })
+ })
+
+ describe('toggleClass', () => {
+ it('should not error out if element is null or undefined', () => {
+ Manipulator.toggleClass(null, 'test')
+ Manipulator.toggleClass(undefined, 'test')
+ expect().nothing()
+ })
+
+ it('should add class if it is missing', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ Manipulator.toggleClass(div, 'test')
+ expect(div.classList.contains('test')).toEqual(true)
+ })
+
+ it('should remove class if it is set', () => {
+ fixtureEl.innerHTML = '<div class="test"></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ Manipulator.toggleClass(div, 'test')
+ expect(div.classList.contains('test')).toEqual(false)
+ })
+ })
+})
diff --git a/js/tests/unit/dom/selector-engine.spec.js b/js/tests/unit/dom/selector-engine.spec.js
new file mode 100644
index 000000000..e13438e6f
--- /dev/null
+++ b/js/tests/unit/dom/selector-engine.spec.js
@@ -0,0 +1,115 @@
+import SelectorEngine from '../../../src/dom/selector-engine'
+import { makeArray } from '../../../src/util/index'
+
+/** Test helpers */
+import { getFixture, clearFixture } from '../../helpers/fixture'
+
+describe('SelectorEngine', () => {
+ let fixtureEl
+
+ beforeAll(() => {
+ fixtureEl = getFixture()
+ })
+
+ afterEach(() => {
+ clearFixture()
+ })
+
+ describe('matches', () => {
+ it('should return matched elements', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ expect(SelectorEngine.matches(fixtureEl, 'div')).toEqual(true)
+ })
+ })
+
+ describe('find', () => {
+ it('should find elements', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ expect(makeArray(SelectorEngine.find('div', fixtureEl))).toEqual([div])
+ })
+
+ it('should find elements globaly', () => {
+ fixtureEl.innerHTML = '<div id="test"></div>'
+
+ const div = fixtureEl.querySelector('#test')
+
+ expect(makeArray(SelectorEngine.find('#test'))).toEqual([div])
+ })
+
+ it('should handle :scope selectors', () => {
+ fixtureEl.innerHTML = `<ul>
+ <li></li>
+ <li>
+ <a href="#" class="active">link</a>
+ </li>
+ <li></li>
+ </ul>`
+
+ const listEl = fixtureEl.querySelector('ul')
+ const aActive = fixtureEl.querySelector('.active')
+
+ expect(makeArray(SelectorEngine.find(':scope > li > .active', listEl))).toEqual([aActive])
+ })
+ })
+
+ describe('findOne', () => {
+ it('should return one element', () => {
+ fixtureEl.innerHTML = '<div id="test"></div>'
+
+ const div = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.findOne('#test')).toEqual(div)
+ })
+ })
+
+ describe('children', () => {
+ it('should find children', () => {
+ fixtureEl.innerHTML = `<ul>
+ <li></li>
+ <li></li>
+ <li></li>
+ </ul>`
+
+ const list = fixtureEl.querySelector('ul')
+ const liList = makeArray(fixtureEl.querySelectorAll('li'))
+ const result = makeArray(SelectorEngine.children(list, 'li'))
+
+ expect(result).toEqual(liList)
+ })
+ })
+
+ describe('parents', () => {
+ it('should return parents', () => {
+ expect(SelectorEngine.parents(fixtureEl, 'body').length).toEqual(1)
+ })
+ })
+
+ describe('prev', () => {
+ it('should return previous element', () => {
+ fixtureEl.innerHTML = '<div class="test"></div><button class="btn"></button>'
+
+ const btn = fixtureEl.querySelector('.btn')
+ const divTest = fixtureEl.querySelector('.test')
+
+ expect(SelectorEngine.prev(btn, '.test')).toEqual([divTest])
+ })
+
+ it('should return previous element with an extra element between', () => {
+ fixtureEl.innerHTML = [
+ '<div class="test"></div>',
+ '<span></span>',
+ '<button class="btn"></button>'
+ ].join('')
+
+ const btn = fixtureEl.querySelector('.btn')
+ const divTest = fixtureEl.querySelector('.test')
+
+ expect(SelectorEngine.prev(btn, '.test')).toEqual([divTest])
+ })
+ })
+})
+