diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-06-24 12:44:36 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-06-24 12:44:36 +0000 |
commit | c1d5a801b4bc66e3866f815be00e11d1b20d3539 (patch) | |
tree | 394cfedf644640ac80b78aaddaff93ceb8eefa5e /js/tests/unit | |
parent | Adding upstream version 5.2.3+dfsg. (diff) | |
download | bootstrap-html-upstream/5.3.0+dfsg.tar.xz bootstrap-html-upstream/5.3.0+dfsg.zip |
Adding upstream version 5.3.0+dfsg.upstream/5.3.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/tests/unit')
28 files changed, 488 insertions, 317 deletions
diff --git a/js/tests/unit/.eslintrc.json b/js/tests/unit/.eslintrc.json deleted file mode 100644 index 6362a1a..0000000 --- a/js/tests/unit/.eslintrc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": [ - "../../../.eslintrc.json" - ], - "env": { - "jasmine": true - }, - "rules": { - "unicorn/consistent-function-scoping": "off", - "unicorn/no-useless-undefined": "off", - "unicorn/prefer-add-event-listener": "off" - } -} diff --git a/js/tests/unit/alert.spec.js b/js/tests/unit/alert.spec.js index d3740c9..97cc3cc 100644 --- a/js/tests/unit/alert.spec.js +++ b/js/tests/unit/alert.spec.js @@ -1,6 +1,6 @@ -import Alert from '../../src/alert' -import { getTransitionDurationFromElement } from '../../src/util/index' -import { clearFixture, getFixture, jQueryMock } from '../helpers/fixture' +import Alert from '../../src/alert.js' +import { getTransitionDurationFromElement } from '../../src/util/index.js' +import { clearFixture, getFixture, jQueryMock } from '../helpers/fixture.js' describe('Alert', () => { let fixtureEl diff --git a/js/tests/unit/base-component.spec.js b/js/tests/unit/base-component.spec.js index b2352d6..5b7d52e 100644 --- a/js/tests/unit/base-component.spec.js +++ b/js/tests/unit/base-component.spec.js @@ -1,7 +1,7 @@ -import BaseComponent from '../../src/base-component' -import { clearFixture, getFixture } from '../helpers/fixture' -import EventHandler from '../../src/dom/event-handler' -import { noop } from '../../src/util' +import BaseComponent from '../../src/base-component.js' +import EventHandler from '../../src/dom/event-handler.js' +import { noop } from '../../src/util/index.js' +import { clearFixture, getFixture } from '../helpers/fixture.js' class DummyClass extends BaseComponent { constructor(element) { diff --git a/js/tests/unit/button.spec.js b/js/tests/unit/button.spec.js index 09ed17e..6624fee 100644 --- a/js/tests/unit/button.spec.js +++ b/js/tests/unit/button.spec.js @@ -1,5 +1,5 @@ -import Button from '../../src/button' -import { getFixture, clearFixture, jQueryMock } from '../helpers/fixture' +import Button from '../../src/button.js' +import { clearFixture, getFixture, jQueryMock } from '../helpers/fixture.js' describe('Button', () => { let fixtureEl diff --git a/js/tests/unit/carousel.spec.js b/js/tests/unit/carousel.spec.js index d951bd5..c468b5c 100644 --- a/js/tests/unit/carousel.spec.js +++ b/js/tests/unit/carousel.spec.js @@ -1,8 +1,8 @@ -import Carousel from '../../src/carousel' -import EventHandler from '../../src/dom/event-handler' -import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' -import { isRTL, noop } from '../../src/util/index' -import Swipe from '../../src/util/swipe' +import Carousel from '../../src/carousel.js' +import EventHandler from '../../src/dom/event-handler.js' +import { isRTL, noop } from '../../src/util/index.js' +import Swipe from '../../src/util/swipe.js' +import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' describe('Carousel', () => { const { Simulator, PointerEvent } = window diff --git a/js/tests/unit/collapse.spec.js b/js/tests/unit/collapse.spec.js index 9c86719..58c5367 100644 --- a/js/tests/unit/collapse.spec.js +++ b/js/tests/unit/collapse.spec.js @@ -1,6 +1,6 @@ -import Collapse from '../../src/collapse' -import EventHandler from '../../src/dom/event-handler' -import { clearFixture, getFixture, jQueryMock } from '../helpers/fixture' +import Collapse from '../../src/collapse.js' +import EventHandler from '../../src/dom/event-handler.js' +import { clearFixture, getFixture, jQueryMock } from '../helpers/fixture.js' describe('Collapse', () => { let fixtureEl @@ -277,25 +277,25 @@ describe('Collapse', () => { return new Promise(resolve => { fixtureEl.innerHTML = [ '<div id="parentGroup" class="accordion">', - ' <div id="parentHeader" class="accordion-header">', - ' <button data-bs-target="#parentContent" data-bs-toggle="collapse" role="button" class="accordion-toggle">Parent</button>', + ' <div class="accordion-header">', + ' <button data-bs-target="#parentContent" data-bs-toggle="collapse" class="accordion-toggle">Parent</button>', ' </div>', - ' <div id="parentContent" class="accordion-collapse collapse" aria-labelledby="parentHeader" data-bs-parent="#parentGroup">', + ' <div id="parentContent" class="accordion-collapse collapse" data-bs-parent="#parentGroup">', ' <div class="accordion-body">', ' <div id="childGroup" class="accordion">', ' <div class="accordion-item">', - ' <div id="childHeader1" class="accordion-header">', - ' <button data-bs-target="#childContent1" data-bs-toggle="collapse" role="button" class="accordion-toggle">Child 1</button>', + ' <div class="accordion-header">', + ' <button data-bs-target="#childContent1" data-bs-toggle="collapse" class="accordion-toggle">Child 1</button>', ' </div>', - ' <div id="childContent1" class="accordion-collapse collapse" aria-labelledby="childHeader1" data-bs-parent="#childGroup">', + ' <div id="childContent1" class="accordion-collapse collapse" data-bs-parent="#childGroup">', ' <div>content</div>', ' </div>', ' </div>', ' <div class="accordion-item">', - ' <div id="childHeader2" class="accordion-header">', - ' <button data-bs-target="#childContent2" data-bs-toggle="collapse" role="button" class="accordion-toggle">Child 2</button>', + ' <div class="accordion-header">', + ' <button data-bs-target="#childContent2" data-bs-toggle="collapse" class="accordion-toggle">Child 2</button>', ' </div>', - ' <div id="childContent2" class="accordion-collapse collapse" aria-labelledby="childHeader2" data-bs-parent="#childGroup">', + ' <div id="childContent2" class="accordion-collapse collapse" data-bs-parent="#childGroup">', ' <div>content</div>', ' </div>', ' </div>', @@ -338,12 +338,12 @@ describe('Collapse', () => { fixtureEl.innerHTML = [ '<div class="accordion" id="accordionExample">', ' <div class="accordion-item">', - ' <h2 class="accordion-header" id="headingOne">', + ' <h2 class="accordion-header">', ' <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">', ' Accordion Item #1', ' </button>', ' </h2>', - ' <div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">', + ' <div id="collapseOne" class="accordion-collapse collapse show" data-bs-parent="#accordionExample">', ' <div class="accordion-body">', ' <nav>', ' <div class="nav nav-tabs" id="nav-tab" role="tablist">', @@ -640,11 +640,11 @@ describe('Collapse', () => { '<div id="accordion">', ' <div class="item">', ' <a id="linkTrigger" data-bs-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>', - ' <div id="collapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree" data-bs-parent="#accordion"></div>', + ' <div id="collapseOne" class="collapse" role="tabpanel" data-bs-parent="#accordion"></div>', ' </div>', ' <div class="item">', ' <a id="linkTriggerTwo" data-bs-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>', - ' <div id="collapseTwo" class="collapse show" role="tabpanel" aria-labelledby="headingTwo" data-bs-parent="#accordion"></div>', + ' <div id="collapseTwo" class="collapse show" role="tabpanel" data-bs-parent="#accordion"></div>', ' </div>', '</div>' ].join('') @@ -699,13 +699,13 @@ describe('Collapse', () => { ' <div class="col-lg-6">', ' <div class="item">', ' <a id="linkTrigger" data-bs-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>', - ' <div id="collapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree" data-bs-parent="#accordion"></div>', + ' <div id="collapseOne" class="collapse" role="tabpanel" data-bs-parent="#accordion"></div>', ' </div>', ' </div>', ' <div class="col-lg-6">', ' <div class="item">', ' <a id="linkTriggerTwo" data-bs-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>', - ' <div id="collapseTwo" class="collapse show" role="tabpanel" aria-labelledby="headingTwo" data-bs-parent="#accordion"></div>', + ' <div id="collapseTwo" class="collapse show" role="tabpanel" data-bs-parent="#accordion"></div>', ' </div>', ' </div>', ' </div>', @@ -829,18 +829,18 @@ describe('Collapse', () => { '<div id="accordion">', ' <div class="item">', ' <a id="linkTrigger" data-bs-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>', - ' <div id="collapseOne" data-bs-parent="#accordion" class="collapse" role="tabpanel" aria-labelledby="headingThree">', + ' <div id="collapseOne" data-bs-parent="#accordion" class="collapse" role="tabpanel">', ' <div id="nestedAccordion">', ' <div class="item">', ' <a id="nestedLinkTrigger" data-bs-toggle="collapse" href="#nestedCollapseOne" aria-expanded="false" aria-controls="nestedCollapseOne"></a>', - ' <div id="nestedCollapseOne" data-bs-parent="#nestedAccordion" class="collapse" role="tabpanel" aria-labelledby="headingThree"></div>', + ' <div id="nestedCollapseOne" data-bs-parent="#nestedAccordion" class="collapse" role="tabpanel"></div>', ' </div>', ' </div>', ' </div>', ' </div>', ' <div class="item">', ' <a id="linkTriggerTwo" data-bs-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>', - ' <div id="collapseTwo" data-bs-parent="#accordion" class="collapse show" role="tabpanel" aria-labelledby="headingTwo"></div>', + ' <div id="collapseTwo" data-bs-parent="#accordion" class="collapse show" role="tabpanel"></div>', ' </div>', '</div>' ].join('') @@ -887,17 +887,17 @@ describe('Collapse', () => { return new Promise(resolve => { fixtureEl.innerHTML = [ '<a id="trigger1" role="button" data-bs-toggle="collapse" href="#test1"></a>', - '<a id="trigger2" role="button" data-bs-toggle="collapse" href="#test2"></a>', + '<a id="trigger2" role="button" data-bs-toggle="collapse" href="#0/my/id"></a>', '<a id="trigger3" role="button" data-bs-toggle="collapse" href=".multi"></a>', '<div id="test1" class="multi"></div>', - '<div id="test2" class="multi"></div>' + '<div id="0/my/id" class="multi"></div>' ].join('') const trigger1 = fixtureEl.querySelector('#trigger1') const trigger2 = fixtureEl.querySelector('#trigger2') const trigger3 = fixtureEl.querySelector('#trigger3') const target1 = fixtureEl.querySelector('#test1') - const target2 = fixtureEl.querySelector('#test2') + const target2 = fixtureEl.querySelector(`#${CSS.escape('0/my/id')}`) const target2Shown = () => { expect(trigger1).not.toHaveClass('collapsed') diff --git a/js/tests/unit/dom/data.spec.js b/js/tests/unit/dom/data.spec.js index e898cbb..04e57a8 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' @@ -89,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') @@ -102,5 +101,4 @@ describe('Data', () => { expect(console.error).toHaveBeenCalled() 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 623b9c1..7f99c41 100644 --- a/js/tests/unit/dom/event-handler.spec.js +++ b/js/tests/unit/dom/event-handler.spec.js @@ -1,6 +1,6 @@ -import EventHandler from '../../../src/dom/event-handler' -import { clearFixture, getFixture } from '../../helpers/fixture' -import { noop } from '../../../src/util' +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 diff --git a/js/tests/unit/dom/manipulator.spec.js b/js/tests/unit/dom/manipulator.spec.js index 4561e2e..9d0be32 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 { clearFixture, getFixture } from '../../helpers/fixture' +import Manipulator from '../../../src/dom/manipulator.js' +import { clearFixture, getFixture } from '../../helpers/fixture.js' describe('Manipulator', () => { let fixtureEl diff --git a/js/tests/unit/dom/selector-engine.spec.js b/js/tests/unit/dom/selector-engine.spec.js index 0245896..8dd7b1f 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 @@ -232,5 +232,159 @@ describe('SelectorEngine', () => { 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 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) + }) + }) +}) diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js index 2bbd7c0..8447be6 100644 --- a/js/tests/unit/dropdown.spec.js +++ b/js/tests/unit/dropdown.spec.js @@ -1,7 +1,7 @@ -import Dropdown from '../../src/dropdown' -import EventHandler from '../../src/dom/event-handler' -import { noop } from '../../src/util/index' -import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' +import EventHandler from '../../src/dom/event-handler.js' +import Dropdown from '../../src/dropdown.js' +import { noop } from '../../src/util/index.js' +import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' describe('Dropdown', () => { let fixtureEl @@ -75,6 +75,7 @@ describe('Dropdown', () => { resolve() }) + expect().nothing() dropdown.show() }) }) diff --git a/js/tests/unit/jquery.spec.js b/js/tests/unit/jquery.spec.js index 7da39d6..7d7f29d 100644 --- a/js/tests/unit/jquery.spec.js +++ b/js/tests/unit/jquery.spec.js @@ -1,18 +1,18 @@ /* eslint-env jquery */ -import Alert from '../../src/alert' -import Button from '../../src/button' -import Carousel from '../../src/carousel' -import Collapse from '../../src/collapse' -import Dropdown from '../../src/dropdown' -import Modal from '../../src/modal' -import Offcanvas from '../../src/offcanvas' -import Popover from '../../src/popover' -import ScrollSpy from '../../src/scrollspy' -import Tab from '../../src/tab' -import Toast from '../../src/toast' -import Tooltip from '../../src/tooltip' -import { clearFixture, getFixture } from '../helpers/fixture' +import Alert from '../../src/alert.js' +import Button from '../../src/button.js' +import Carousel from '../../src/carousel.js' +import Collapse from '../../src/collapse.js' +import Dropdown from '../../src/dropdown.js' +import Modal from '../../src/modal.js' +import Offcanvas from '../../src/offcanvas.js' +import Popover from '../../src/popover.js' +import ScrollSpy from '../../src/scrollspy.js' +import Tab from '../../src/tab.js' +import Toast from '../../src/toast.js' +import Tooltip from '../../src/tooltip.js' +import { clearFixture, getFixture } from '../helpers/fixture.js' describe('jQuery', () => { let fixtureEl diff --git a/js/tests/unit/modal.spec.js b/js/tests/unit/modal.spec.js index fdee29e..6434d8b 100644 --- a/js/tests/unit/modal.spec.js +++ b/js/tests/unit/modal.spec.js @@ -1,7 +1,7 @@ -import Modal from '../../src/modal' -import EventHandler from '../../src/dom/event-handler' -import ScrollBarHelper from '../../src/util/scrollbar' -import { clearBodyAndDocument, clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' +import EventHandler from '../../src/dom/event-handler.js' +import Modal from '../../src/modal.js' +import ScrollBarHelper from '../../src/util/scrollbar.js' +import { clearBodyAndDocument, clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' describe('Modal', () => { let fixtureEl diff --git a/js/tests/unit/offcanvas.spec.js b/js/tests/unit/offcanvas.spec.js index da2fb97..03e7d9e 100644 --- a/js/tests/unit/offcanvas.spec.js +++ b/js/tests/unit/offcanvas.spec.js @@ -1,8 +1,8 @@ -import Offcanvas from '../../src/offcanvas' -import EventHandler from '../../src/dom/event-handler' -import { clearBodyAndDocument, clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' -import { isVisible } from '../../src/util/index' -import ScrollBarHelper from '../../src/util/scrollbar' +import EventHandler from '../../src/dom/event-handler.js' +import Offcanvas from '../../src/offcanvas.js' +import { isVisible } from '../../src/util/index.js' +import ScrollBarHelper from '../../src/util/scrollbar.js' +import { clearBodyAndDocument, clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' describe('Offcanvas', () => { let fixtureEl diff --git a/js/tests/unit/popover.spec.js b/js/tests/unit/popover.spec.js index baf691c..53dc7d8 100644 --- a/js/tests/unit/popover.spec.js +++ b/js/tests/unit/popover.spec.js @@ -1,6 +1,6 @@ -import Popover from '../../src/popover' -import EventHandler from '../../src/dom/event-handler' -import { clearFixture, getFixture, jQueryMock } from '../helpers/fixture' +import EventHandler from '../../src/dom/event-handler.js' +import Popover from '../../src/popover.js' +import { clearFixture, getFixture, jQueryMock } from '../helpers/fixture.js' describe('Popover', () => { let fixtureEl diff --git a/js/tests/unit/scrollspy.spec.js b/js/tests/unit/scrollspy.spec.js index c7951e6..ecbd952 100644 --- a/js/tests/unit/scrollspy.spec.js +++ b/js/tests/unit/scrollspy.spec.js @@ -1,8 +1,6 @@ -import ScrollSpy from '../../src/scrollspy' - -/** Test helpers */ -import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' -import EventHandler from '../../src/dom/event-handler' +import EventHandler from '../../src/dom/event-handler.js' +import ScrollSpy from '../../src/scrollspy.js' +import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' describe('ScrollSpy', () => { let fixtureEl @@ -942,5 +940,39 @@ describe('ScrollSpy', () => { }, 100) link.click() }) + + it('should smoothscroll to observable with anchor link that contains a french word as id', done => { + fixtureEl.innerHTML = [ + '<nav id="navBar" class="navbar">', + ' <ul class="nav">', + ' <li class="nav-item"><a id="li-jsm-1" class="nav-link" href="#présentation">div 1</a></li>', + ' </ul>', + '</nav>', + '<div class="content" data-bs-target="#navBar" style="overflow-y: auto">', + ' <div id="présentation">div 1</div>', + '</div>' + ].join('') + + const div = fixtureEl.querySelector('.content') + const link = fixtureEl.querySelector('[href="#présentation"]') + const observable = fixtureEl.querySelector('#présentation') + const clickSpy = getElementScrollSpy(div) + // eslint-disable-next-line no-new + new ScrollSpy(div, { + offset: 1, + smoothScroll: true + }) + + setTimeout(() => { + if (div.scrollTo) { + expect(clickSpy).toHaveBeenCalledWith({ top: observable.offsetTop - div.offsetTop, behavior: 'smooth' }) + } else { + expect(clickSpy).toHaveBeenCalledWith(observable.offsetTop - div.offsetTop) + } + + done() + }, 100) + link.click() + }) }) }) diff --git a/js/tests/unit/tab.spec.js b/js/tests/unit/tab.spec.js index e0c7d86..84690fc 100644 --- a/js/tests/unit/tab.spec.js +++ b/js/tests/unit/tab.spec.js @@ -1,5 +1,5 @@ -import Tab from '../../src/tab' -import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' +import Tab from '../../src/tab.js' +import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' describe('Tab', () => { let fixtureEl @@ -177,6 +177,43 @@ describe('Tab', () => { }) }) + it('should work with tab id being an int', done => { + fixtureEl.innerHTML = [ + '<div class="card-header d-block d-inline-block">', + ' <ul class="nav nav-tabs card-header-tabs" id="page_tabs">', + ' <li class="nav-item">', + ' <a class="nav-link" draggable="false" data-toggle="tab" href="#tab1">', + ' Working Tab 1 (#tab1)', + ' </a>', + ' </li>', + ' <li class="nav-item">', + ' <a id="trigger2" class="nav-link" draggable="false" data-toggle="tab" href="#2">', + ' Tab with numeric ID should work (#2)', + ' </a>', + ' </li>', + ' </ul>', + '</div>', + '<div class="card-body">', + ' <div class="tab-content" id="page_content">', + ' <div class="tab-pane fade" id="tab1">', + ' Working Tab 1 (#tab1) Content Here', + ' </div>', + ' <div class="tab-pane fade" id="2">', + ' Working Tab 2 (#2) with numeric ID', + ' </div>', + '</div>' + ].join('') + const profileTriggerEl = fixtureEl.querySelector('#trigger2') + const tab = new Tab(profileTriggerEl) + + profileTriggerEl.addEventListener('shown.bs.tab', () => { + expect(fixtureEl.querySelector(`#${CSS.escape('2')}`)).toHaveClass('active') + done() + }) + + tab.show() + }) + it('should not fire shown when show is prevented', () => { return new Promise((resolve, reject) => { fixtureEl.innerHTML = '<div class="nav"><div class="nav-link"></div></div>' @@ -477,7 +514,7 @@ describe('Tab', () => { expect(tabPanel.hasAttribute('tabindex')).toBeFalse() expect(tabPanel.hasAttribute('tabindex2')).toBeFalse() - expect(tabPanel.getAttribute('aria-labelledby')).toEqual('#foo') + expect(tabPanel.getAttribute('aria-labelledby')).toEqual('foo') expect(tabPanel2.hasAttribute('aria-labelledby')).toBeFalse() }) }) @@ -603,19 +640,19 @@ describe('Tab', () => { '</div>' ].join('') - const tabEl = fixtureEl.querySelector('#tab1') + const tabEl1 = fixtureEl.querySelector('#tab1') const tabEl2 = fixtureEl.querySelector('#tab2') const tabEl3 = fixtureEl.querySelector('#tab3') const tabEl4 = fixtureEl.querySelector('#tab4') - const tab = new Tab(tabEl) + const tab1 = new Tab(tabEl1) const tab2 = new Tab(tabEl2) const tab3 = new Tab(tabEl3) const tab4 = new Tab(tabEl4) - const spy1 = spyOn(tab, 'show').and.callThrough() + const spy1 = spyOn(tab1, 'show').and.callThrough() const spy2 = spyOn(tab2, 'show').and.callThrough() const spy3 = spyOn(tab3, 'show').and.callThrough() const spy4 = spyOn(tab4, 'show').and.callThrough() - const spyFocus1 = spyOn(tabEl, 'focus').and.callThrough() + const spyFocus1 = spyOn(tabEl1, 'focus').and.callThrough() const spyFocus2 = spyOn(tabEl2, 'focus').and.callThrough() const spyFocus3 = spyOn(tabEl3, 'focus').and.callThrough() const spyFocus4 = spyOn(tabEl4, 'focus').and.callThrough() @@ -623,7 +660,7 @@ describe('Tab', () => { const keydown = createEvent('keydown') keydown.key = 'ArrowRight' - tabEl.dispatchEvent(keydown) + tabEl1.dispatchEvent(keydown) expect(spy1).not.toHaveBeenCalled() expect(spy2).not.toHaveBeenCalled() expect(spy3).not.toHaveBeenCalled() @@ -644,19 +681,19 @@ describe('Tab', () => { '</div>' ].join('') - const tabEl = fixtureEl.querySelector('#tab1') + const tabEl1 = fixtureEl.querySelector('#tab1') const tabEl2 = fixtureEl.querySelector('#tab2') const tabEl3 = fixtureEl.querySelector('#tab3') const tabEl4 = fixtureEl.querySelector('#tab4') - const tab = new Tab(tabEl) + const tab1 = new Tab(tabEl1) const tab2 = new Tab(tabEl2) const tab3 = new Tab(tabEl3) const tab4 = new Tab(tabEl4) - const spy1 = spyOn(tab, 'show').and.callThrough() + const spy1 = spyOn(tab1, 'show').and.callThrough() const spy2 = spyOn(tab2, 'show').and.callThrough() const spy3 = spyOn(tab3, 'show').and.callThrough() const spy4 = spyOn(tab4, 'show').and.callThrough() - const spyFocus1 = spyOn(tabEl, 'focus').and.callThrough() + const spyFocus1 = spyOn(tabEl1, 'focus').and.callThrough() const spyFocus2 = spyOn(tabEl2, 'focus').and.callThrough() const spyFocus3 = spyOn(tabEl3, 'focus').and.callThrough() const spyFocus4 = spyOn(tabEl4, 'focus').and.callThrough() diff --git a/js/tests/unit/toast.spec.js b/js/tests/unit/toast.spec.js index 42d2515..cfc56c7 100644 --- a/js/tests/unit/toast.spec.js +++ b/js/tests/unit/toast.spec.js @@ -1,5 +1,5 @@ -import Toast from '../../src/toast' -import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' +import Toast from '../../src/toast.js' +import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' describe('Toast', () => { let fixtureEl diff --git a/js/tests/unit/tooltip.spec.js b/js/tests/unit/tooltip.spec.js index 4330571..080432e 100644 --- a/js/tests/unit/tooltip.spec.js +++ b/js/tests/unit/tooltip.spec.js @@ -1,7 +1,7 @@ -import Tooltip from '../../src/tooltip' -import EventHandler from '../../src/dom/event-handler' -import { noop } from '../../src/util/index' -import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' +import EventHandler from '../../src/dom/event-handler.js' +import Tooltip from '../../src/tooltip.js' +import { noop } from '../../src/util/index.js' +import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture.js' describe('Tooltip', () => { let fixtureEl @@ -56,7 +56,7 @@ describe('Tooltip', () => { describe('constructor', () => { it('should take care of element either passed as a CSS selector or DOM element', () => { - fixtureEl.innerHTML = '<a href="#" id="tooltipEl" rel="tooltip" title="Nice and short title">' + fixtureEl.innerHTML = '<a href="#" id="tooltipEl" rel="tooltip" title="Nice and short title"></a>' const tooltipEl = fixtureEl.querySelector('#tooltipEl') const tooltipBySelector = new Tooltip('#tooltipEl') @@ -67,7 +67,7 @@ describe('Tooltip', () => { }) it('should not take care of disallowed data attributes', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" data-bs-sanitize="false" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" data-bs-sanitize="false" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -76,7 +76,7 @@ describe('Tooltip', () => { }) it('should convert title and content to string if numbers', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { @@ -98,7 +98,7 @@ describe('Tooltip', () => { trigger: 'click' }) - containerEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + containerEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipInContainerEl = containerEl.querySelector('a') @@ -114,7 +114,7 @@ describe('Tooltip', () => { it('should create offset modifier when offset is passed as a function', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Offset from function">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Offset from function"></a>' const getOffset = jasmine.createSpy('getOffset').and.returnValue([10, 20]) const tooltipEl = fixtureEl.querySelector('a') @@ -141,7 +141,7 @@ describe('Tooltip', () => { }) it('should create offset modifier when offset option is passed in data attribute', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" data-bs-offset="10,20" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" data-bs-offset="10,20" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -150,7 +150,7 @@ describe('Tooltip', () => { }) it('should allow to pass config to Popper with `popperConfig`', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { @@ -165,7 +165,7 @@ describe('Tooltip', () => { }) it('should allow to pass config to Popper with `popperConfig` as a function', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const getPopperConfig = jasmine.createSpy('getPopperConfig').and.returnValue({ placement: 'left' }) @@ -192,7 +192,7 @@ describe('Tooltip', () => { describe('enable', () => { it('should enable a tooltip', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -212,7 +212,7 @@ describe('Tooltip', () => { describe('disable', () => { it('should disable tooltip', () => { return new Promise((resolve, reject) => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -235,7 +235,7 @@ describe('Tooltip', () => { describe('toggleEnabled', () => { it('should toggle enabled', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -251,7 +251,7 @@ describe('Tooltip', () => { describe('toggle', () => { it('should do nothing if disabled', () => { return new Promise((resolve, reject) => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -273,7 +273,7 @@ describe('Tooltip', () => { it('should show a tooltip', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -289,7 +289,7 @@ describe('Tooltip', () => { it('should call toggle and show the tooltip when trigger is "click"', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { @@ -309,7 +309,7 @@ describe('Tooltip', () => { it('should hide a tooltip', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -329,7 +329,7 @@ describe('Tooltip', () => { it('should call toggle and hide the tooltip when trigger is "click"', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { @@ -354,7 +354,7 @@ describe('Tooltip', () => { describe('dispose', () => { it('should destroy a tooltip', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const addEventSpy = spyOn(tooltipEl, 'addEventListener').and.callThrough() @@ -381,7 +381,7 @@ describe('Tooltip', () => { it('should destroy a tooltip after it is shown and hidden', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -402,7 +402,7 @@ describe('Tooltip', () => { it('should destroy a tooltip and remove it from the dom', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -443,7 +443,7 @@ describe('Tooltip', () => { describe('show', () => { it('should show a tooltip', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -488,7 +488,7 @@ describe('Tooltip', () => { it('should show a tooltip on mobile', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -509,7 +509,7 @@ describe('Tooltip', () => { it('should show a tooltip relative to placement option', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { @@ -532,7 +532,7 @@ describe('Tooltip', () => { it('should not error when trying to show a tooltip that has been removed from the dom', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -561,7 +561,7 @@ describe('Tooltip', () => { it('should show a tooltip with a dom element container', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { @@ -579,7 +579,7 @@ describe('Tooltip', () => { it('should show a tooltip with a jquery element container', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { @@ -600,7 +600,7 @@ describe('Tooltip', () => { it('should show a tooltip with a selector in container', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { @@ -618,7 +618,7 @@ describe('Tooltip', () => { it('should show a tooltip with placement as a function', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const spy = jasmine.createSpy('placement').and.returnValue('top') const tooltipEl = fixtureEl.querySelector('a') @@ -638,7 +638,7 @@ describe('Tooltip', () => { it('should show a tooltip without the animation', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { @@ -658,7 +658,7 @@ describe('Tooltip', () => { }) it('should throw an error the element is not visible', () => { - fixtureEl.innerHTML = '<a href="#" style="display: none" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" style="display: none" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -672,7 +672,7 @@ describe('Tooltip', () => { it('should not show a tooltip if show.bs.tooltip is prevented', () => { return new Promise((resolve, reject) => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -699,7 +699,7 @@ describe('Tooltip', () => { it('should show tooltip if leave event hasn\'t occurred before delay expires', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { @@ -723,7 +723,7 @@ describe('Tooltip', () => { it('should not show tooltip if leave event occurs before delay expires', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { @@ -845,7 +845,7 @@ describe('Tooltip', () => { it('should only trigger inserted event if a new tooltip element was created', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -878,7 +878,7 @@ describe('Tooltip', () => { it('should show a tooltip with custom class provided in data attributes', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip" data-bs-custom-class="custom-class">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip" data-bs-custom-class="custom-class"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -896,7 +896,7 @@ describe('Tooltip', () => { it('should show a tooltip with custom class provided as a string in config', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { @@ -917,7 +917,7 @@ describe('Tooltip', () => { it('should show a tooltip with custom class provided as a function in config', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const spy = jasmine.createSpy('customClass').and.returnValue('custom-class') const tooltipEl = fixtureEl.querySelector('a') @@ -956,7 +956,7 @@ describe('Tooltip', () => { describe('hide', () => { it('should hide a tooltip', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -974,7 +974,7 @@ describe('Tooltip', () => { it('should hide a tooltip on mobile', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -998,7 +998,7 @@ describe('Tooltip', () => { it('should hide a tooltip without animation', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { @@ -1018,7 +1018,7 @@ describe('Tooltip', () => { it('should not hide a tooltip if hide event is prevented', () => { return new Promise((resolve, reject) => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const assertDone = () => { setTimeout(() => { @@ -1063,7 +1063,7 @@ describe('Tooltip', () => { describe('update', () => { it('should call popper update', () => { return new Promise(resolve => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -1082,7 +1082,7 @@ describe('Tooltip', () => { }) it('should do nothing if the tooltip is not shown', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -1094,7 +1094,7 @@ describe('Tooltip', () => { describe('_isWithContent', () => { it('should return true if there is content', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -1103,7 +1103,7 @@ describe('Tooltip', () => { }) it('should return false if there is no content', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title=""></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -1114,7 +1114,7 @@ describe('Tooltip', () => { describe('_getTipElement', () => { it('should create the tip element and return it', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -1126,7 +1126,7 @@ describe('Tooltip', () => { }) it('should return the created tip element', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -1145,7 +1145,7 @@ describe('Tooltip', () => { describe('setContent', () => { it('should set tip content', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl, { animation: false }) @@ -1160,7 +1160,7 @@ describe('Tooltip', () => { }) it('should re-show tip if it was already shown', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" data-bs-title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" data-bs-title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -1175,7 +1175,7 @@ describe('Tooltip', () => { }) it('should keep tip hidden, if it was already hidden before', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" data-bs-title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" data-bs-title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -1190,7 +1190,7 @@ describe('Tooltip', () => { }) it('"setContent" should keep the initial template', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) @@ -1207,7 +1207,7 @@ describe('Tooltip', () => { describe('setContent', () => { it('should do nothing if the element is null', () => { - fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">' + fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>' const tooltipEl = fixtureEl.querySelector('a') const tooltip = new Tooltip(tooltipEl) diff --git a/js/tests/unit/util/backdrop.spec.js b/js/tests/unit/util/backdrop.spec.js index 73384fc..0faaac6 100644 --- a/js/tests/unit/util/backdrop.spec.js +++ b/js/tests/unit/util/backdrop.spec.js @@ -1,6 +1,6 @@ -import Backdrop from '../../../src/util/backdrop' -import { getTransitionDurationFromElement } from '../../../src/util/index' -import { clearFixture, getFixture } from '../../helpers/fixture' +import Backdrop from '../../../src/util/backdrop.js' +import { getTransitionDurationFromElement } from '../../../src/util/index.js' +import { clearFixture, getFixture } from '../../helpers/fixture.js' const CLASS_BACKDROP = '.modal-backdrop' const CLASS_NAME_FADE = 'fade' diff --git a/js/tests/unit/util/component-functions.spec.js b/js/tests/unit/util/component-functions.spec.js index ec36672..ce83785 100644 --- a/js/tests/unit/util/component-functions.spec.js +++ b/js/tests/unit/util/component-functions.spec.js @@ -1,8 +1,6 @@ -/* Test helpers */ - -import { clearFixture, createEvent, getFixture } from '../../helpers/fixture' -import { enableDismissTrigger } from '../../../src/util/component-functions' -import BaseComponent from '../../../src/base-component' +import BaseComponent from '../../../src/base-component.js' +import { enableDismissTrigger } from '../../../src/util/component-functions.js' +import { clearFixture, createEvent, getFixture } from '../../helpers/fixture.js' class DummyClass2 extends BaseComponent { static get NAME() { diff --git a/js/tests/unit/util/config.spec.js b/js/tests/unit/util/config.spec.js index e1693c0..93987a7 100644 --- a/js/tests/unit/util/config.spec.js +++ b/js/tests/unit/util/config.spec.js @@ -1,5 +1,5 @@ -import Config from '../../../src/util/config' -import { clearFixture, getFixture } from '../../helpers/fixture' +import Config from '../../../src/util/config.js' +import { clearFixture, getFixture } from '../../helpers/fixture.js' class DummyConfigClass extends Config { static get NAME() { @@ -128,7 +128,7 @@ describe('Config', () => { const obj = new DummyConfigClass() expect(() => { obj._typeCheckConfig(config) - }).toThrowError(TypeError, obj.constructor.NAME.toUpperCase() + ': Option "parent" provided type "number" but expected type "(string|element)".') + }).toThrowError(TypeError, `${obj.constructor.NAME.toUpperCase()}: Option "parent" provided type "number" but expected type "(string|element)".`) }) it('should return null stringified when null is passed', () => { diff --git a/js/tests/unit/util/focustrap.spec.js b/js/tests/unit/util/focustrap.spec.js index bedd124..0a20017 100644 --- a/js/tests/unit/util/focustrap.spec.js +++ b/js/tests/unit/util/focustrap.spec.js @@ -1,7 +1,7 @@ -import FocusTrap from '../../../src/util/focustrap' -import EventHandler from '../../../src/dom/event-handler' -import SelectorEngine from '../../../src/dom/selector-engine' -import { clearFixture, createEvent, getFixture } from '../../helpers/fixture' +import EventHandler from '../../../src/dom/event-handler.js' +import SelectorEngine from '../../../src/dom/selector-engine.js' +import FocusTrap from '../../../src/util/focustrap.js' +import { clearFixture, createEvent, getFixture } from '../../helpers/fixture.js' describe('FocusTrap', () => { let fixtureEl diff --git a/js/tests/unit/util/index.spec.js b/js/tests/unit/util/index.spec.js index 9f28ce0..4065a91 100644 --- a/js/tests/unit/util/index.spec.js +++ b/js/tests/unit/util/index.spec.js @@ -1,6 +1,6 @@ -import * as Util from '../../../src/util/index' -import { clearFixture, getFixture } from '../../helpers/fixture' -import { noop } from '../../../src/util/index' +import * as Util from '../../../src/util/index.js' +import { noop } from '../../../src/util/index.js' +import { clearFixture, getFixture } from '../../helpers/fixture.js' describe('Util', () => { let fixtureEl @@ -22,119 +22,6 @@ describe('Util', () => { }) }) - 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(Util.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(Util.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(Util.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(Util.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(Util.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(Util.getSelectorFromElement(testEl)).toBeNull() - }) - - it('should return null if no selector', () => { - fixtureEl.innerHTML = '<div></div>' - - const testEl = fixtureEl.querySelector('div') - - expect(Util.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(Util.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(Util.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(Util.getElementFromSelector(testEl)).toBeNull() - }) - - it('should return null if no selector', () => { - fixtureEl.innerHTML = '<div></div>' - - const testEl = fixtureEl.querySelector('div') - - expect(Util.getElementFromSelector(testEl)).toBeNull() - }) - }) - describe('getTransitionDurationFromElement', () => { it('should get transition from element', () => { fixtureEl.innerHTML = '<div style="transition: all 300ms ease-out;"></div>' @@ -631,6 +518,25 @@ describe('Util', () => { Util.execute(spy) expect(spy).toHaveBeenCalled() }) + + it('should execute if arg is function & return the result', () => { + const functionFoo = (num1, num2 = 10) => num1 + num2 + const resultFoo = Util.execute(functionFoo, [4, 5]) + expect(resultFoo).toBe(9) + + const resultFoo1 = Util.execute(functionFoo, [4]) + expect(resultFoo1).toBe(14) + + const functionBar = () => 'foo' + const resultBar = Util.execute(functionBar) + expect(resultBar).toBe('foo') + }) + + it('should not execute if arg is not function & return default argument', () => { + const foo = 'bar' + expect(Util.execute(foo)).toBe('bar') + expect(Util.execute(foo, [], 4)).toBe(4) + }) }) describe('executeAfterTransition', () => { diff --git a/js/tests/unit/util/sanitizer.spec.js b/js/tests/unit/util/sanitizer.spec.js index c656aed..2b21ef2 100644 --- a/js/tests/unit/util/sanitizer.spec.js +++ b/js/tests/unit/util/sanitizer.spec.js @@ -1,4 +1,4 @@ -import { DefaultAllowlist, sanitizeHtml } from '../../../src/util/sanitizer' +import { DefaultAllowlist, sanitizeHtml } from '../../../src/util/sanitizer.js' describe('Sanitizer', () => { describe('sanitizeHtml', () => { @@ -10,17 +10,75 @@ describe('Sanitizer', () => { expect(result).toEqual(empty) }) - it('should sanitize template by removing tags with XSS', () => { - const template = [ - '<div>', - ' <a href="javascript:alert(7)">Click me</a>', - ' <span>Some content</span>', - '</div>' - ].join('') - - const result = sanitizeHtml(template, DefaultAllowlist, null) + it('should retain tags with valid URLs', () => { + const validUrls = [ + '', + 'http://abc', + 'HTTP://abc', + 'https://abc', + 'HTTPS://abc', + 'ftp://abc', + 'FTP://abc', + 'mailto:me@example.com', + 'MAILTO:me@example.com', + 'tel:123-123-1234', + 'TEL:123-123-1234', + 'sip:me@example.com', + 'SIP:me@example.com', + '#anchor', + '/page1.md', + 'http://JavaScript/my.js', + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/', // Truncated. + 'data:video/webm;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/', + 'data:audio/opus;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/', + 'unknown-scheme:abc' + ] + + for (const url of validUrls) { + const template = [ + '<div>', + ` <a href="${url}">Click me</a>`, + ' <span>Some content</span>', + '</div>' + ].join('') + + const result = sanitizeHtml(template, DefaultAllowlist, null) + + expect(result).toContain(`href="${url}"`) + } + }) - expect(result).not.toContain('href="javascript:alert(7)') + it('should sanitize template by removing tags with XSS', () => { + const invalidUrls = [ + // eslint-disable-next-line no-script-url + 'javascript:alert(7)', + // eslint-disable-next-line no-script-url + 'javascript:evil()', + // eslint-disable-next-line no-script-url + 'JavaScript:abc', + ' javascript:abc', + ' \n Java\n Script:abc', + 'javascript:', + 'javascript:', + 'j avascript:', + 'javascript:', + 'javascript:', + 'jav	ascript:alert();', + 'jav\u0000ascript:alert();' + ] + + for (const url of invalidUrls) { + const template = [ + '<div>', + ` <a href="${url}">Click me</a>`, + ' <span>Some content</span>', + '</div>' + ].join('') + + const result = sanitizeHtml(template, DefaultAllowlist, null) + + expect(result).not.toContain(`href="${url}"`) + } }) it('should sanitize template and work with multiple regex', () => { diff --git a/js/tests/unit/util/scrollbar.spec.js b/js/tests/unit/util/scrollbar.spec.js index 6fcf571..6dadfcd 100644 --- a/js/tests/unit/util/scrollbar.spec.js +++ b/js/tests/unit/util/scrollbar.spec.js @@ -1,6 +1,6 @@ -import { clearBodyAndDocument, clearFixture, getFixture } from '../../helpers/fixture' -import Manipulator from '../../../src/dom/manipulator' -import ScrollBarHelper from '../../../src/util/scrollbar' +import Manipulator from '../../../src/dom/manipulator.js' +import ScrollBarHelper from '../../../src/util/scrollbar.js' +import { clearBodyAndDocument, clearFixture, getFixture } from '../../helpers/fixture.js' describe('ScrollBar', () => { let fixtureEl diff --git a/js/tests/unit/util/swipe.spec.js b/js/tests/unit/util/swipe.spec.js index f92bb5d..9252d31 100644 --- a/js/tests/unit/util/swipe.spec.js +++ b/js/tests/unit/util/swipe.spec.js @@ -1,7 +1,7 @@ -import { clearFixture, getFixture } from '../../helpers/fixture' -import EventHandler from '../../../src/dom/event-handler' -import Swipe from '../../../src/util/swipe' -import { noop } from '../../../src/util' +import EventHandler from '../../../src/dom/event-handler.js' +import { noop } from '../../../src/util/index.js' +import Swipe from '../../../src/util/swipe.js' +import { clearFixture, getFixture } from '../../helpers/fixture.js' describe('Swipe', () => { const { Simulator, PointerEvent } = window diff --git a/js/tests/unit/util/template-factory.spec.js b/js/tests/unit/util/template-factory.spec.js index 5e5724c..07f4d91 100644 --- a/js/tests/unit/util/template-factory.spec.js +++ b/js/tests/unit/util/template-factory.spec.js @@ -1,5 +1,5 @@ -import { clearFixture, getFixture } from '../../helpers/fixture' -import TemplateFactory from '../../../src/util/template-factory' +import TemplateFactory from '../../../src/util/template-factory.js' +import { clearFixture, getFixture } from '../../helpers/fixture.js' describe('TemplateFactory', () => { let fixtureEl |