diff options
| author | XhmikosR <[email protected]> | 2019-10-09 01:27:43 +0300 |
|---|---|---|
| committer | GitHub <[email protected]> | 2019-10-09 01:27:43 +0300 |
| commit | 577bf8b14d76a864a8d69dbfb03b757fbeb6e241 (patch) | |
| tree | 354238ff0aaca853a9698c191eeb4c2143c39c16 /js/tests/unit/dom | |
| parent | 1770691b339bdbf17de5e8824158b358dc0284a9 (diff) | |
| download | bootstrap-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.js | 131 | ||||
| -rw-r--r-- | js/tests/unit/dom/event-handler.spec.js | 327 | ||||
| -rw-r--r-- | js/tests/unit/dom/manipulator.spec.js | 158 | ||||
| -rw-r--r-- | js/tests/unit/dom/selector-engine.spec.js | 115 |
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]) + }) + }) +}) + |
