diff options
Diffstat (limited to 'js/tests/unit/dom/event-handler.spec.js')
| -rw-r--r-- | js/tests/unit/dom/event-handler.spec.js | 579 |
1 files changed, 322 insertions, 257 deletions
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) + }) + }) + }) }) |
