aboutsummaryrefslogtreecommitdiff
path: root/js/tests/unit/dom
diff options
context:
space:
mode:
Diffstat (limited to 'js/tests/unit/dom')
-rw-r--r--js/tests/unit/dom/data.spec.js15
-rw-r--r--js/tests/unit/dom/event-handler.spec.js579
-rw-r--r--js/tests/unit/dom/manipulator.spec.js101
-rw-r--r--js/tests/unit/dom/selector-engine.spec.js234
4 files changed, 557 insertions, 372 deletions
diff --git a/js/tests/unit/dom/data.spec.js b/js/tests/unit/dom/data.spec.js
index 2560caff7..04e57a8bc 100644
--- a/js/tests/unit/dom/data.spec.js
+++ b/js/tests/unit/dom/data.spec.js
@@ -1,5 +1,5 @@
-import Data from '../../../src/dom/data'
-import { getFixture, clearFixture } from '../../helpers/fixture'
+import Data from '../../../src/dom/data.js'
+import { clearFixture, getFixture } from '../../helpers/fixture.js'
describe('Data', () => {
const TEST_KEY = 'bs.test'
@@ -50,7 +50,7 @@ describe('Data', () => {
Data.set(div, TEST_KEY, data)
- expect(Data.get(div, TEST_KEY)).toBe(data)
+ expect(Data.get(div, TEST_KEY)).toEqual(data)
})
it('should overwrite data if something is already stored', () => {
@@ -60,11 +60,12 @@ describe('Data', () => {
Data.set(div, TEST_KEY, data)
Data.set(div, TEST_KEY, copy)
+ // Using `toBe` since spread creates a shallow copy
expect(Data.get(div, TEST_KEY)).not.toBe(data)
expect(Data.get(div, TEST_KEY)).toBe(copy)
})
- it('should do nothing when an element have nothing stored', () => {
+ it('should do nothing when an element has nothing stored', () => {
Data.remove(div, TEST_KEY)
expect().nothing()
@@ -76,7 +77,7 @@ describe('Data', () => {
Data.set(div, TEST_KEY, data)
Data.remove(div, UNKNOWN_KEY)
- expect(Data.get(div, TEST_KEY)).toBe(data)
+ expect(Data.get(div, TEST_KEY)).toEqual(data)
})
it('should remove data for a given key', () => {
@@ -88,7 +89,6 @@ describe('Data', () => {
expect(Data.get(div, TEST_KEY)).toBeNull()
})
- /* eslint-disable no-console */
it('should console.error a message if called with multiple keys', () => {
console.error = jasmine.createSpy('console.error')
@@ -99,7 +99,6 @@ describe('Data', () => {
Data.set(div, UNKNOWN_KEY, copy)
expect(console.error).toHaveBeenCalled()
- expect(Data.get(div, UNKNOWN_KEY)).toBe(null)
+ expect(Data.get(div, UNKNOWN_KEY)).toBeNull()
})
- /* eslint-enable no-console */
})
diff --git a/js/tests/unit/dom/event-handler.spec.js b/js/tests/unit/dom/event-handler.spec.js
index 19d63492b..7f99c4122 100644
--- a/js/tests/unit/dom/event-handler.spec.js
+++ b/js/tests/unit/dom/event-handler.spec.js
@@ -1,5 +1,6 @@
-import EventHandler from '../../../src/dom/event-handler'
-import { getFixture, clearFixture } from '../../helpers/fixture'
+import EventHandler from '../../../src/dom/event-handler.js'
+import { noop } from '../../../src/util/index.js'
+import { clearFixture, getFixture } from '../../helpers/fixture.js'
describe('EventHandler', () => {
let fixtureEl
@@ -18,176 +19,190 @@ describe('EventHandler', () => {
const div = fixtureEl.querySelector('div')
- EventHandler.on(div, null, () => {})
- EventHandler.on(null, 'click', () => {})
+ EventHandler.on(div, null, noop)
+ EventHandler.on(null, 'click', noop)
expect().nothing()
})
- it('should add event listener', done => {
- fixtureEl.innerHTML = '<div></div>'
+ it('should add event listener', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
+ const div = fixtureEl.querySelector('div')
- EventHandler.on(div, 'click', () => {
- expect().nothing()
- done()
- })
+ EventHandler.on(div, 'click', () => {
+ expect().nothing()
+ resolve()
+ })
- div.click()
+ div.click()
+ })
})
- it('should add namespaced event listener', done => {
- fixtureEl.innerHTML = '<div></div>'
+ it('should add namespaced event listener', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
+ const div = fixtureEl.querySelector('div')
- EventHandler.on(div, 'bs.namespace', () => {
- expect().nothing()
- done()
- })
+ EventHandler.on(div, 'bs.namespace', () => {
+ expect().nothing()
+ resolve()
+ })
- EventHandler.trigger(div, 'bs.namespace')
+ EventHandler.trigger(div, 'bs.namespace')
+ })
})
- it('should add native namespaced event listener', done => {
- fixtureEl.innerHTML = '<div></div>'
+ it('should add native namespaced event listener', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
+ const div = fixtureEl.querySelector('div')
- EventHandler.on(div, 'click.namespace', () => {
- expect().nothing()
- done()
- })
+ EventHandler.on(div, 'click.namespace', () => {
+ expect().nothing()
+ resolve()
+ })
- EventHandler.trigger(div, 'click')
+ EventHandler.trigger(div, 'click')
+ })
})
- it('should handle event delegation', done => {
- EventHandler.on(document, 'click', '.test', () => {
- expect().nothing()
- done()
- })
+ it('should handle event delegation', () => {
+ return new Promise(resolve => {
+ EventHandler.on(document, 'click', '.test', () => {
+ expect().nothing()
+ resolve()
+ })
- fixtureEl.innerHTML = '<div class="test"></div>'
+ fixtureEl.innerHTML = '<div class="test"></div>'
- const div = fixtureEl.querySelector('div')
-
- div.click()
- })
+ const div = fixtureEl.querySelector('div')
- it('should handle mouseenter/mouseleave like the native counterpart', done => {
- fixtureEl.innerHTML = [
- '<div class="outer">',
- '<div class="inner">',
- '<div class="nested">',
- '<div class="deep"></div>',
- '</div>',
- '</div>',
- '<div class="sibling"></div>',
- '</div>'
- ]
-
- const outer = fixtureEl.querySelector('.outer')
- const inner = fixtureEl.querySelector('.inner')
- const nested = fixtureEl.querySelector('.nested')
- const deep = fixtureEl.querySelector('.deep')
- const sibling = fixtureEl.querySelector('.sibling')
-
- const enterSpy = jasmine.createSpy('mouseenter')
- const leaveSpy = jasmine.createSpy('mouseleave')
- const delegateEnterSpy = jasmine.createSpy('mouseenter')
- const delegateLeaveSpy = jasmine.createSpy('mouseleave')
-
- EventHandler.on(inner, 'mouseenter', enterSpy)
- EventHandler.on(inner, 'mouseleave', leaveSpy)
- EventHandler.on(outer, 'mouseenter', '.inner', delegateEnterSpy)
- EventHandler.on(outer, 'mouseleave', '.inner', delegateLeaveSpy)
-
- EventHandler.on(sibling, 'mouseenter', () => {
- expect(enterSpy.calls.count()).toBe(2)
- expect(leaveSpy.calls.count()).toBe(2)
- expect(delegateEnterSpy.calls.count()).toBe(2)
- expect(delegateLeaveSpy.calls.count()).toBe(2)
- done()
+ div.click()
})
+ })
- const moveMouse = (from, to) => {
- from.dispatchEvent(new MouseEvent('mouseout', {
- bubbles: true,
- relatedTarget: to
- }))
-
- to.dispatchEvent(new MouseEvent('mouseover', {
- bubbles: true,
- relatedTarget: from
- }))
- }
+ it('should handle mouseenter/mouseleave like the native counterpart', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div class="outer">',
+ '<div class="inner">',
+ '<div class="nested">',
+ '<div class="deep"></div>',
+ '</div>',
+ '</div>',
+ '<div class="sibling"></div>',
+ '</div>'
+ ].join('')
+
+ const outer = fixtureEl.querySelector('.outer')
+ const inner = fixtureEl.querySelector('.inner')
+ const nested = fixtureEl.querySelector('.nested')
+ const deep = fixtureEl.querySelector('.deep')
+ const sibling = fixtureEl.querySelector('.sibling')
+
+ const enterSpy = jasmine.createSpy('mouseenter')
+ const leaveSpy = jasmine.createSpy('mouseleave')
+ const delegateEnterSpy = jasmine.createSpy('mouseenter')
+ const delegateLeaveSpy = jasmine.createSpy('mouseleave')
+
+ EventHandler.on(inner, 'mouseenter', enterSpy)
+ EventHandler.on(inner, 'mouseleave', leaveSpy)
+ EventHandler.on(outer, 'mouseenter', '.inner', delegateEnterSpy)
+ EventHandler.on(outer, 'mouseleave', '.inner', delegateLeaveSpy)
+
+ EventHandler.on(sibling, 'mouseenter', () => {
+ expect(enterSpy.calls.count()).toEqual(2)
+ expect(leaveSpy.calls.count()).toEqual(2)
+ expect(delegateEnterSpy.calls.count()).toEqual(2)
+ expect(delegateLeaveSpy.calls.count()).toEqual(2)
+ resolve()
+ })
+
+ const moveMouse = (from, to) => {
+ from.dispatchEvent(new MouseEvent('mouseout', {
+ bubbles: true,
+ relatedTarget: to
+ }))
+
+ to.dispatchEvent(new MouseEvent('mouseover', {
+ bubbles: true,
+ relatedTarget: from
+ }))
+ }
- // from outer to deep and back to outer (nested)
- moveMouse(outer, inner)
- moveMouse(inner, nested)
- moveMouse(nested, deep)
- moveMouse(deep, nested)
- moveMouse(nested, inner)
- moveMouse(inner, outer)
-
- setTimeout(() => {
- expect(enterSpy.calls.count()).toBe(1)
- expect(leaveSpy.calls.count()).toBe(1)
- expect(delegateEnterSpy.calls.count()).toBe(1)
- expect(delegateLeaveSpy.calls.count()).toBe(1)
-
- // from outer to inner to sibling (adjacent)
+ // from outer to deep and back to outer (nested)
moveMouse(outer, inner)
- moveMouse(inner, sibling)
- }, 20)
+ moveMouse(inner, nested)
+ moveMouse(nested, deep)
+ moveMouse(deep, nested)
+ moveMouse(nested, inner)
+ moveMouse(inner, outer)
+
+ setTimeout(() => {
+ expect(enterSpy.calls.count()).toEqual(1)
+ expect(leaveSpy.calls.count()).toEqual(1)
+ expect(delegateEnterSpy.calls.count()).toEqual(1)
+ expect(delegateLeaveSpy.calls.count()).toEqual(1)
+
+ // from outer to inner to sibling (adjacent)
+ moveMouse(outer, inner)
+ moveMouse(inner, sibling)
+ }, 20)
+ })
})
})
describe('one', () => {
- it('should call listener just once', done => {
- fixtureEl.innerHTML = '<div></div>'
-
- let called = 0
- const div = fixtureEl.querySelector('div')
- const obj = {
- oneListener() {
- called++
+ it('should call listener just once', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ let called = 0
+ const div = fixtureEl.querySelector('div')
+ const obj = {
+ oneListener() {
+ called++
+ }
}
- }
- EventHandler.one(div, 'bootstrap', obj.oneListener)
+ EventHandler.one(div, 'bootstrap', obj.oneListener)
- EventHandler.trigger(div, 'bootstrap')
- EventHandler.trigger(div, 'bootstrap')
+ EventHandler.trigger(div, 'bootstrap')
+ EventHandler.trigger(div, 'bootstrap')
- setTimeout(() => {
- expect(called).toEqual(1)
- done()
- }, 20)
+ setTimeout(() => {
+ expect(called).toEqual(1)
+ resolve()
+ }, 20)
+ })
})
- it('should call delegated listener just once', done => {
- fixtureEl.innerHTML = '<div></div>'
+ it('should call delegated listener just once', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
- let called = 0
- const div = fixtureEl.querySelector('div')
- const obj = {
- oneListener() {
- called++
+ let called = 0
+ const div = fixtureEl.querySelector('div')
+ const obj = {
+ oneListener() {
+ called++
+ }
}
- }
- EventHandler.one(fixtureEl, 'bootstrap', 'div', obj.oneListener)
+ EventHandler.one(fixtureEl, 'bootstrap', 'div', obj.oneListener)
- EventHandler.trigger(div, 'bootstrap')
- EventHandler.trigger(div, 'bootstrap')
+ EventHandler.trigger(div, 'bootstrap')
+ EventHandler.trigger(div, 'bootstrap')
- setTimeout(() => {
- expect(called).toEqual(1)
- done()
- }, 20)
+ setTimeout(() => {
+ expect(called).toEqual(1)
+ resolve()
+ }, 20)
+ })
})
})
@@ -196,171 +211,185 @@ describe('EventHandler', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
- EventHandler.off(div, null, () => {})
- EventHandler.off(null, 'click', () => {})
+ EventHandler.off(div, null, noop)
+ EventHandler.off(null, 'click', noop)
expect().nothing()
})
- it('should remove a listener', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
+ it('should remove a listener', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
- let called = 0
- const handler = () => {
- called++
- }
+ let called = 0
+ const handler = () => {
+ called++
+ }
- EventHandler.on(div, 'foobar', handler)
- EventHandler.trigger(div, 'foobar')
+ EventHandler.on(div, 'foobar', handler)
+ EventHandler.trigger(div, 'foobar')
- EventHandler.off(div, 'foobar', handler)
- EventHandler.trigger(div, 'foobar')
+ EventHandler.off(div, 'foobar', handler)
+ EventHandler.trigger(div, 'foobar')
- setTimeout(() => {
- expect(called).toEqual(1)
- done()
- }, 20)
+ setTimeout(() => {
+ expect(called).toEqual(1)
+ resolve()
+ }, 20)
+ })
})
- it('should remove all the events', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
+ it('should remove all the events', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
- let called = 0
+ let called = 0
- EventHandler.on(div, 'foobar', () => {
- called++
- })
- EventHandler.on(div, 'foobar', () => {
- called++
- })
- EventHandler.trigger(div, 'foobar')
+ EventHandler.on(div, 'foobar', () => {
+ called++
+ })
+ EventHandler.on(div, 'foobar', () => {
+ called++
+ })
+ EventHandler.trigger(div, 'foobar')
- EventHandler.off(div, 'foobar')
- EventHandler.trigger(div, 'foobar')
+ EventHandler.off(div, 'foobar')
+ EventHandler.trigger(div, 'foobar')
- setTimeout(() => {
- expect(called).toEqual(2)
- done()
- }, 20)
+ setTimeout(() => {
+ expect(called).toEqual(2)
+ resolve()
+ }, 20)
+ })
})
- it('should remove all the namespaced listeners if namespace is passed', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
+ it('should remove all the namespaced listeners if namespace is passed', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
- let called = 0
+ let called = 0
- EventHandler.on(div, 'foobar.namespace', () => {
- called++
- })
- EventHandler.on(div, 'foofoo.namespace', () => {
- called++
+ 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)
+ resolve()
+ }, 20)
})
- 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')
+ it('should remove the namespaced listeners', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
- let calledCallback1 = 0
- let calledCallback2 = 0
+ let calledCallback1 = 0
+ let calledCallback2 = 0
- EventHandler.on(div, 'foobar.namespace', () => {
- calledCallback1++
- })
- EventHandler.on(div, 'foofoo.namespace', () => {
- calledCallback2++
- })
+ 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, 'foobar.namespace')
+ EventHandler.off(div, 'foobar.namespace')
+ EventHandler.trigger(div, 'foobar.namespace')
- EventHandler.trigger(div, 'foofoo.namespace')
+ EventHandler.trigger(div, 'foofoo.namespace')
- setTimeout(() => {
- expect(calledCallback1).toEqual(1)
- expect(calledCallback2).toEqual(1)
- done()
- }, 20)
+ setTimeout(() => {
+ expect(calledCallback1).toEqual(1)
+ expect(calledCallback2).toEqual(1)
+ resolve()
+ }, 20)
+ })
})
- it('should remove the all the namespaced listeners for native events', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
+ it('should remove the all the namespaced listeners for native events', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = '<div></div>'
+ const div = fixtureEl.querySelector('div')
- let called = 0
+ let called = 0
- EventHandler.on(div, 'click.namespace', () => {
- called++
- })
- EventHandler.on(div, 'click.namespace2', () => {
- called++
- })
+ EventHandler.on(div, 'click.namespace', () => {
+ called++
+ })
+ EventHandler.on(div, 'click.namespace2', () => {
+ called++
+ })
- EventHandler.trigger(div, 'click')
- EventHandler.off(div, 'click')
- EventHandler.trigger(div, 'click')
+ EventHandler.trigger(div, 'click')
+ EventHandler.off(div, 'click')
+ EventHandler.trigger(div, 'click')
- setTimeout(() => {
- expect(called).toEqual(2)
- done()
- }, 20)
+ setTimeout(() => {
+ expect(called).toEqual(2)
+ resolve()
+ }, 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++
+ it('should remove the specified namespaced listeners for native events', () => {
+ return new Promise(resolve => {
+ 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)
+ resolve()
+ }, 20)
})
- 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>'
+ it('should remove a listener registered by .one', () => {
+ return new Promise((resolve, reject) => {
+ fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
- const handler = () => {
- throw new Error('called')
- }
+ const div = fixtureEl.querySelector('div')
+ const handler = () => {
+ reject(new Error('called'))
+ }
- EventHandler.one(div, 'foobar', handler)
- EventHandler.off(div, 'foobar', handler)
+ EventHandler.one(div, 'foobar', handler)
+ EventHandler.off(div, 'foobar', handler)
- EventHandler.trigger(div, 'foobar')
- setTimeout(() => {
- expect().nothing()
- done()
- }, 20)
+ EventHandler.trigger(div, 'foobar')
+ setTimeout(() => {
+ expect().nothing()
+ resolve()
+ }, 20)
+ })
})
it('should remove the correct delegated event listener', () => {
@@ -412,4 +441,40 @@ describe('EventHandler', () => {
expect(i).toEqual(5)
})
})
+
+ describe('general functionality', () => {
+ it('should hydrate properties, and make them configurable', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '<div id="div1">',
+ ' <div id="div2"></div>',
+ ' <div id="div3"></div>',
+ '</div>'
+ ].join('')
+
+ const div1 = fixtureEl.querySelector('#div1')
+ const div2 = fixtureEl.querySelector('#div2')
+
+ EventHandler.on(div1, 'click', event => {
+ expect(event.currentTarget).toBe(div2)
+ expect(event.delegateTarget).toBe(div1)
+ expect(event.originalTarget).toBeNull()
+
+ Object.defineProperty(event, 'currentTarget', {
+ configurable: true,
+ get() {
+ return div1
+ }
+ })
+
+ expect(event.currentTarget).toBe(div1)
+ resolve()
+ })
+
+ expect(() => {
+ EventHandler.trigger(div1, 'click', { originalTarget: null, currentTarget: div2 })
+ }).not.toThrowError(TypeError)
+ })
+ })
+ })
})
diff --git a/js/tests/unit/dom/manipulator.spec.js b/js/tests/unit/dom/manipulator.spec.js
index 61ffe7455..9d0be3218 100644
--- a/js/tests/unit/dom/manipulator.spec.js
+++ b/js/tests/unit/dom/manipulator.spec.js
@@ -1,5 +1,5 @@
-import Manipulator from '../../../src/dom/manipulator'
-import { getFixture, clearFixture } from '../../helpers/fixture'
+import Manipulator from '../../../src/dom/manipulator.js'
+import { clearFixture, getFixture } from '../../helpers/fixture.js'
describe('Manipulator', () => {
let fixtureEl
@@ -70,6 +70,17 @@ describe('Manipulator', () => {
target: '#element'
})
})
+
+ it('should omit `bs-config` data attribute', () => {
+ fixtureEl.innerHTML = '<div data-bs-toggle="tabs" data-bs-target="#element" data-bs-config=\'{"testBool":false}\'></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ expect(Manipulator.getDataAttributes(div)).toEqual({
+ toggle: 'tabs',
+ target: '#element'
+ })
+ })
})
describe('getDataAttribute', () => {
@@ -96,93 +107,29 @@ describe('Manipulator', () => {
const div = fixtureEl.querySelector('div')
- expect(Manipulator.getDataAttribute(div, 'test')).toEqual(false)
+ expect(Manipulator.getDataAttribute(div, 'test')).toBeFalse()
div.setAttribute('data-bs-test', 'true')
- expect(Manipulator.getDataAttribute(div, 'test')).toEqual(true)
+ expect(Manipulator.getDataAttribute(div, 'test')).toBeTrue()
div.setAttribute('data-bs-test', '1')
expect(Manipulator.getDataAttribute(div, 'test')).toEqual(1)
})
- })
-
- describe('offset', () => {
- it('should return an 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))
- })
-
- it('should return offset relative to attached element\'s offset', () => {
- const top = 500
- const left = 1000
-
- fixtureEl.innerHTML = `<div style="position:absolute;top:${top}px;left:${left}px"></div>`
-
- const div = fixtureEl.querySelector('div')
- const offset = Manipulator.offset(div)
- const fixtureOffset = Manipulator.offset(fixtureEl)
-
- expect(offset).toEqual({
- top: fixtureOffset.top + top,
- left: fixtureOffset.left + left
- })
- })
-
- it('should not change offset when viewport is scrolled', done => {
- const top = 500
- const left = 1000
- const scrollY = 200
- const scrollX = 400
- fixtureEl.innerHTML = `<div style="position:absolute;top:${top}px;left:${left}px"></div>`
+ it('should normalize json data', () => {
+ fixtureEl.innerHTML = '<div data-bs-test=\'{"delay":{"show":100,"hide":10}}\'></div>'
const div = fixtureEl.querySelector('div')
- const offset = Manipulator.offset(div)
-
- // append an element that forces scrollbars on the window so we can scroll
- const { defaultView: win, body } = fixtureEl.ownerDocument
- const forceScrollBars = document.createElement('div')
- forceScrollBars.style.cssText = 'position:absolute;top:5000px;left:5000px;width:1px;height:1px'
- body.append(forceScrollBars)
-
- const scrollHandler = () => {
- expect(window.pageYOffset).toBe(scrollY)
- expect(window.pageXOffset).toBe(scrollX)
- const newOffset = Manipulator.offset(div)
+ expect(Manipulator.getDataAttribute(div, 'test')).toEqual({ delay: { show: 100, hide: 10 } })
- expect(newOffset).toEqual({
- top: offset.top,
- left: offset.left
- })
-
- win.removeEventListener('scroll', scrollHandler)
- forceScrollBars.remove()
- win.scrollTo(0, 0)
- done()
- }
-
- win.addEventListener('scroll', scrollHandler)
- win.scrollTo(scrollX, scrollY)
- })
- })
-
- describe('position', () => {
- it('should return an object with two properties top and left, both numbers', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const position = Manipulator.position(div)
+ const objectData = { 'Super Hero': ['Iron Man', 'Super Man'], testNum: 90, url: 'http://localhost:8080/test?foo=bar' }
+ const dataStr = JSON.stringify(objectData)
+ div.setAttribute('data-bs-test', encodeURIComponent(dataStr))
+ expect(Manipulator.getDataAttribute(div, 'test')).toEqual(objectData)
- expect(position).toBeDefined()
- expect(position.top).toEqual(jasmine.any(Number))
- expect(position.left).toEqual(jasmine.any(Number))
+ div.setAttribute('data-bs-test', dataStr)
+ expect(Manipulator.getDataAttribute(div, 'test')).toEqual(objectData)
})
})
})
diff --git a/js/tests/unit/dom/selector-engine.spec.js b/js/tests/unit/dom/selector-engine.spec.js
index 09c85a88a..95d9bf8ec 100644
--- a/js/tests/unit/dom/selector-engine.spec.js
+++ b/js/tests/unit/dom/selector-engine.spec.js
@@ -1,5 +1,5 @@
-import SelectorEngine from '../../../src/dom/selector-engine'
-import { getFixture, clearFixture } from '../../helpers/fixture'
+import SelectorEngine from '../../../src/dom/selector-engine.js'
+import { clearFixture, getFixture } from '../../helpers/fixture.js'
describe('SelectorEngine', () => {
let fixtureEl
@@ -21,7 +21,7 @@ describe('SelectorEngine', () => {
expect(SelectorEngine.find('div', fixtureEl)).toEqual([div])
})
- it('should find elements globaly', () => {
+ it('should find elements globally', () => {
fixtureEl.innerHTML = '<div id="test"></div>'
const div = fixtureEl.querySelector('#test')
@@ -30,13 +30,15 @@ describe('SelectorEngine', () => {
})
it('should handle :scope selectors', () => {
- fixtureEl.innerHTML = `<ul>
- <li></li>
- <li>
- <a href="#" class="active">link</a>
- </li>
- <li></li>
- </ul>`
+ fixtureEl.innerHTML = [
+ '<ul>',
+ ' <li></li>',
+ ' <li>',
+ ' <a href="#" class="active">link</a>',
+ ' </li>',
+ ' <li></li>',
+ '</ul>'
+ ].join('')
const listEl = fixtureEl.querySelector('ul')
const aActive = fixtureEl.querySelector('.active')
@@ -57,11 +59,13 @@ describe('SelectorEngine', () => {
describe('children', () => {
it('should find children', () => {
- fixtureEl.innerHTML = `<ul>
- <li></li>
- <li></li>
- <li></li>
- </ul>`
+ fixtureEl.innerHTML = [
+ '<ul>',
+ ' <li></li>',
+ ' <li></li>',
+ ' <li></li>',
+ '</ul>'
+ ].join('')
const list = fixtureEl.querySelector('ul')
const liList = [].concat(...fixtureEl.querySelectorAll('li'))
@@ -73,7 +77,7 @@ describe('SelectorEngine', () => {
describe('parents', () => {
it('should return parents', () => {
- expect(SelectorEngine.parents(fixtureEl, 'body').length).toEqual(1)
+ expect(SelectorEngine.parents(fixtureEl, 'body')).toHaveSize(1)
})
})
@@ -162,7 +166,7 @@ describe('SelectorEngine', () => {
'<span>lorem</span>',
'<a>lorem</a>',
'<button>lorem</button>',
- '<input />',
+ '<input>',
'<textarea></textarea>',
'<select></select>',
'<details>lorem</details>'
@@ -197,9 +201,7 @@ describe('SelectorEngine', () => {
})
it('should return not return elements with negative tab index', () => {
- fixtureEl.innerHTML = [
- '<button tabindex="-1">lorem</button>'
- ].join('')
+ fixtureEl.innerHTML = '<button tabindex="-1">lorem</button>'
const expectedElements = []
@@ -207,9 +209,7 @@ describe('SelectorEngine', () => {
})
it('should return contenteditable elements', () => {
- fixtureEl.innerHTML = [
- '<div contenteditable="true">lorem</div>'
- ].join('')
+ fixtureEl.innerHTML = '<div contenteditable="true">lorem</div>'
const expectedElements = [fixtureEl.querySelector('[contenteditable="true"]')]
@@ -217,9 +217,7 @@ describe('SelectorEngine', () => {
})
it('should not return disabled elements', () => {
- fixtureEl.innerHTML = [
- '<button disabled="true">lorem</button>'
- ].join('')
+ fixtureEl.innerHTML = '<button disabled="true">lorem</button>'
const expectedElements = []
@@ -227,14 +225,190 @@ describe('SelectorEngine', () => {
})
it('should not return invisible elements', () => {
- fixtureEl.innerHTML = [
- '<button style="display:none;">lorem</button>'
- ].join('')
+ fixtureEl.innerHTML = '<button style="display:none;">lorem</button>'
const expectedElements = []
expect(SelectorEngine.focusableChildren(fixtureEl)).toEqual(expectedElements)
})
})
-})
+ describe('getSelectorFromElement', () => {
+ it('should get selector from data-bs-target', () => {
+ fixtureEl.innerHTML = [
+ '<div id="test" data-bs-target=".target"></div>',
+ '<div class="target"></div>'
+ ].join('')
+
+ const testEl = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.getSelectorFromElement(testEl)).toEqual('.target')
+ })
+
+ it('should get selector from href if no data-bs-target set', () => {
+ fixtureEl.innerHTML = [
+ '<a id="test" href=".target"></a>',
+ '<div class="target"></div>'
+ ].join('')
+
+ const testEl = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.getSelectorFromElement(testEl)).toEqual('.target')
+ })
+
+ it('should get selector from href if data-bs-target equal to #', () => {
+ fixtureEl.innerHTML = [
+ '<a id="test" data-bs-target="#" href=".target"></a>',
+ '<div class="target"></div>'
+ ].join('')
+
+ const testEl = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.getSelectorFromElement(testEl)).toEqual('.target')
+ })
+
+ it('should return null if a selector from a href is a url without an anchor', () => {
+ fixtureEl.innerHTML = [
+ '<a id="test" data-bs-target="#" href="foo/bar.html"></a>',
+ '<div class="target"></div>'
+ ].join('')
+
+ const testEl = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.getSelectorFromElement(testEl)).toBeNull()
+ })
+
+ it('should return the anchor if a selector from a href is a url', () => {
+ fixtureEl.innerHTML = [
+ '<a id="test" data-bs-target="#" href="foo/bar.html#target"></a>',
+ '<div id="target"></div>'
+ ].join('')
+
+ const testEl = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.getSelectorFromElement(testEl)).toEqual('#target')
+ })
+
+ it('should return null if selector not found', () => {
+ fixtureEl.innerHTML = '<a id="test" href=".target"></a>'
+
+ const testEl = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.getSelectorFromElement(testEl)).toBeNull()
+ })
+
+ it('should return null if no selector', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const testEl = fixtureEl.querySelector('div')
+
+ expect(SelectorEngine.getSelectorFromElement(testEl)).toBeNull()
+ })
+ })
+
+ describe('getElementFromSelector', () => {
+ it('should get element from data-bs-target', () => {
+ fixtureEl.innerHTML = [
+ '<div id="test" data-bs-target=".target"></div>',
+ '<div class="target"></div>'
+ ].join('')
+
+ const testEl = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.getElementFromSelector(testEl)).toEqual(fixtureEl.querySelector('.target'))
+ })
+
+ it('should get element from href if no data-bs-target set', () => {
+ fixtureEl.innerHTML = [
+ '<a id="test" href=".target"></a>',
+ '<div class="target"></div>'
+ ].join('')
+
+ const testEl = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.getElementFromSelector(testEl)).toEqual(fixtureEl.querySelector('.target'))
+ })
+
+ it('should return null if element not found', () => {
+ fixtureEl.innerHTML = '<a id="test" href=".target"></a>'
+
+ const testEl = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.getElementFromSelector(testEl)).toBeNull()
+ })
+
+ it('should return null if no selector', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const testEl = fixtureEl.querySelector('div')
+
+ expect(SelectorEngine.getElementFromSelector(testEl)).toBeNull()
+ })
+ })
+
+ describe('getMultipleElementsFromSelector', () => {
+ it('should get elements from data-bs-target', () => {
+ fixtureEl.innerHTML = [
+ '<div id="test" data-bs-target=".target"></div>',
+ '<div class="target"></div>',
+ '<div class="target"></div>'
+ ].join('')
+
+ const testEl = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.getMultipleElementsFromSelector(testEl)).toEqual(Array.from(fixtureEl.querySelectorAll('.target')))
+ })
+
+ it('should get elements if several ids are given', () => {
+ fixtureEl.innerHTML = [
+ '<div id="test" data-bs-target="#target1,#target2"></div>',
+ '<div class="target" id="target1"></div>',
+ '<div class="target" id="target2"></div>'
+ ].join('')
+
+ const testEl = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.getMultipleElementsFromSelector(testEl)).toEqual(Array.from(fixtureEl.querySelectorAll('.target')))
+ })
+
+ it('should get elements if several ids with special chars are given', () => {
+ fixtureEl.innerHTML = [
+ '<div id="test" data-bs-target="#j_id11:exampleModal,#j_id22:exampleModal"></div>',
+ '<div class="target" id="j_id11:exampleModal"></div>',
+ '<div class="target" id="j_id22:exampleModal"></div>'
+ ].join('')
+
+ const testEl = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.getMultipleElementsFromSelector(testEl)).toEqual(Array.from(fixtureEl.querySelectorAll('.target')))
+ })
+
+ it('should get elements in array, from href if no data-bs-target set', () => {
+ fixtureEl.innerHTML = [
+ '<a id="test" href=".target"></a>',
+ '<div class="target"></div>',
+ '<div class="target"></div>'
+ ].join('')
+
+ const testEl = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.getMultipleElementsFromSelector(testEl)).toEqual(Array.from(fixtureEl.querySelectorAll('.target')))
+ })
+
+ it('should return empty array if elements not found', () => {
+ fixtureEl.innerHTML = '<a id="test" href=".target"></a>'
+
+ const testEl = fixtureEl.querySelector('#test')
+
+ expect(SelectorEngine.getMultipleElementsFromSelector(testEl)).toHaveSize(0)
+ })
+
+ it('should return empty array if no selector', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const testEl = fixtureEl.querySelector('div')
+
+ expect(SelectorEngine.getMultipleElementsFromSelector(testEl)).toHaveSize(0)
+ })
+ })
+})