diff options
Diffstat (limited to 'js/tests/unit/toast.spec.js')
| -rw-r--r-- | js/tests/unit/toast.spec.js | 253 |
1 files changed, 245 insertions, 8 deletions
diff --git a/js/tests/unit/toast.spec.js b/js/tests/unit/toast.spec.js index f8ef6e54b..c491650b1 100644 --- a/js/tests/unit/toast.spec.js +++ b/js/tests/unit/toast.spec.js @@ -1,7 +1,7 @@ import Toast from '../../src/toast' /** Test helpers */ -import { getFixture, clearFixture, jQueryMock } from '../helpers/fixture' +import { getFixture, clearFixture, createEvent, jQueryMock } from '../helpers/fixture' describe('Toast', () => { let fixtureEl @@ -27,6 +27,17 @@ describe('Toast', () => { }) describe('constructor', () => { + it('should take care of element either passed as a CSS selector or DOM element', () => { + fixtureEl.innerHTML = '<div class="toast"></div>' + + const toastEl = fixtureEl.querySelector('.toast') + const toastBySelector = new Toast('.toast') + const toastByElement = new Toast(toastEl) + + expect(toastBySelector._element).toEqual(toastEl) + expect(toastByElement._element).toEqual(toastEl) + }) + it('should allow to config in js', done => { fixtureEl.innerHTML = [ '<div class="toast">', @@ -199,6 +210,182 @@ describe('Toast', () => { toast.show() }) + + it('should clear timeout if toast is interacted with mouse', done => { + fixtureEl.innerHTML = [ + '<div class="toast">', + ' <div class="toast-body">', + ' a simple toast', + ' </div>', + '</div>' + ].join('') + + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) + const spy = spyOn(toast, '_clearTimeout').and.callThrough() + + setTimeout(() => { + spy.calls.reset() + + toastEl.addEventListener('mouseover', () => { + expect(toast._clearTimeout).toHaveBeenCalledTimes(1) + expect(toast._timeout).toBeNull() + done() + }) + + const mouseOverEvent = createEvent('mouseover') + toastEl.dispatchEvent(mouseOverEvent) + }, toast._config.delay / 2) + + toast.show() + }) + + it('should clear timeout if toast is interacted with keyboard', done => { + fixtureEl.innerHTML = [ + '<button id="outside-focusable">outside focusable</button>', + '<div class="toast">', + ' <div class="toast-body">', + ' a simple toast', + ' <button>with a button</button>', + ' </div>', + '</div>' + ].join('') + + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) + const spy = spyOn(toast, '_clearTimeout').and.callThrough() + + setTimeout(() => { + spy.calls.reset() + + toastEl.addEventListener('focusin', () => { + expect(toast._clearTimeout).toHaveBeenCalledTimes(1) + expect(toast._timeout).toBeNull() + done() + }) + + const insideFocusable = toastEl.querySelector('button') + insideFocusable.focus() + }, toast._config.delay / 2) + + toast.show() + }) + + it('should still auto hide after being interacted with mouse and keyboard', done => { + fixtureEl.innerHTML = [ + '<button id="outside-focusable">outside focusable</button>', + '<div class="toast">', + ' <div class="toast-body">', + ' a simple toast', + ' <button>with a button</button>', + ' </div>', + '</div>' + ].join('') + + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) + + setTimeout(() => { + toastEl.addEventListener('mouseover', () => { + const insideFocusable = toastEl.querySelector('button') + insideFocusable.focus() + }) + + toastEl.addEventListener('focusin', () => { + const mouseOutEvent = createEvent('mouseout') + toastEl.dispatchEvent(mouseOutEvent) + }) + + toastEl.addEventListener('mouseout', () => { + const outsideFocusable = document.getElementById('outside-focusable') + outsideFocusable.focus() + }) + + toastEl.addEventListener('focusout', () => { + expect(toast._timeout).not.toBeNull() + done() + }) + + const mouseOverEvent = createEvent('mouseover') + toastEl.dispatchEvent(mouseOverEvent) + }, toast._config.delay / 2) + + toast.show() + }) + + it('should not auto hide if focus leaves but mouse pointer remains inside', done => { + fixtureEl.innerHTML = [ + '<button id="outside-focusable">outside focusable</button>', + '<div class="toast">', + ' <div class="toast-body">', + ' a simple toast', + ' <button>with a button</button>', + ' </div>', + '</div>' + ].join('') + + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) + + setTimeout(() => { + toastEl.addEventListener('mouseover', () => { + const insideFocusable = toastEl.querySelector('button') + insideFocusable.focus() + }) + + toastEl.addEventListener('focusin', () => { + const outsideFocusable = document.getElementById('outside-focusable') + outsideFocusable.focus() + }) + + toastEl.addEventListener('focusout', () => { + expect(toast._timeout).toBeNull() + done() + }) + + const mouseOverEvent = createEvent('mouseover') + toastEl.dispatchEvent(mouseOverEvent) + }, toast._config.delay / 2) + + toast.show() + }) + + it('should not auto hide if mouse pointer leaves but focus remains inside', done => { + fixtureEl.innerHTML = [ + '<button id="outside-focusable">outside focusable</button>', + '<div class="toast">', + ' <div class="toast-body">', + ' a simple toast', + ' <button>with a button</button>', + ' </div>', + '</div>' + ].join('') + + const toastEl = fixtureEl.querySelector('.toast') + const toast = new Toast(toastEl) + + setTimeout(() => { + toastEl.addEventListener('mouseover', () => { + const insideFocusable = toastEl.querySelector('button') + insideFocusable.focus() + }) + + toastEl.addEventListener('focusin', () => { + const mouseOutEvent = createEvent('mouseout') + toastEl.dispatchEvent(mouseOutEvent) + }) + + toastEl.addEventListener('mouseout', () => { + expect(toast._timeout).toBeNull() + done() + }) + + const mouseOverEvent = createEvent('mouseover') + toastEl.dispatchEvent(mouseOverEvent) + }, toast._config.delay / 2) + + toast.show() + }) }) describe('hide', () => { @@ -280,18 +467,14 @@ describe('Toast', () => { fixtureEl.innerHTML = '<div></div>' const toastEl = fixtureEl.querySelector('div') - spyOn(toastEl, 'addEventListener').and.callThrough() - spyOn(toastEl, 'removeEventListener').and.callThrough() const toast = new Toast(toastEl) - expect(Toast.getInstance(toastEl)).toBeDefined() - expect(toastEl.addEventListener).toHaveBeenCalledWith('click', jasmine.any(Function), jasmine.any(Boolean)) + expect(Toast.getInstance(toastEl)).not.toBeNull() toast.dispose() expect(Toast.getInstance(toastEl)).toBeNull() - expect(toastEl.removeEventListener).toHaveBeenCalledWith('click', jasmine.any(Function), jasmine.any(Boolean)) }) it('should allow to destroy toast and hide it before that', done => { @@ -307,7 +490,7 @@ describe('Toast', () => { const toast = new Toast(toastEl) const expected = () => { expect(toastEl.classList.contains('show')).toEqual(true) - expect(Toast.getInstance(toastEl)).toBeDefined() + expect(Toast.getInstance(toastEl)).not.toBeNull() toast.dispose() @@ -336,7 +519,7 @@ describe('Toast', () => { jQueryMock.fn.toast.call(jQueryMock) - expect(Toast.getInstance(div)).toBeDefined() + expect(Toast.getInstance(div)).not.toBeNull() }) it('should not re create a toast', () => { @@ -404,4 +587,58 @@ describe('Toast', () => { expect(Toast.getInstance(div)).toEqual(null) }) }) + + describe('getOrCreateInstance', () => { + it('should return toast instance', () => { + fixtureEl.innerHTML = '<div></div>' + + const div = fixtureEl.querySelector('div') + const toast = new Toast(div) + + expect(Toast.getOrCreateInstance(div)).toEqual(toast) + expect(Toast.getInstance(div)).toEqual(Toast.getOrCreateInstance(div, {})) + expect(Toast.getOrCreateInstance(div)).toBeInstanceOf(Toast) + }) + + it('should return new instance when there is no toast instance', () => { + fixtureEl.innerHTML = '<div></div>' + + const div = fixtureEl.querySelector('div') + + expect(Toast.getInstance(div)).toEqual(null) + expect(Toast.getOrCreateInstance(div)).toBeInstanceOf(Toast) + }) + + it('should return new instance when there is no toast instance with given configuration', () => { + fixtureEl.innerHTML = '<div></div>' + + const div = fixtureEl.querySelector('div') + + expect(Toast.getInstance(div)).toEqual(null) + const toast = Toast.getOrCreateInstance(div, { + delay: 1 + }) + expect(toast).toBeInstanceOf(Toast) + + expect(toast._config.delay).toEqual(1) + }) + + it('should return the instance when exists without given configuration', () => { + fixtureEl.innerHTML = '<div></div>' + + const div = fixtureEl.querySelector('div') + const toast = new Toast(div, { + delay: 1 + }) + expect(Toast.getInstance(div)).toEqual(toast) + + const toast2 = Toast.getOrCreateInstance(div, { + delay: 2 + }) + expect(toast).toBeInstanceOf(Toast) + expect(toast2).toEqual(toast) + + expect(toast2._config.delay).toEqual(1) + }) + }) }) |
