diff options
Diffstat (limited to 'js/tests')
41 files changed, 590 insertions, 350 deletions
diff --git a/js/tests/browsers.js b/js/tests/browsers.js index 8adedc6..c515e64 100644 --- a/js/tests/browsers.js +++ b/js/tests/browsers.js @@ -1,6 +1,7 @@ -/* eslint-env node */ /* eslint-disable camelcase */ +'use strict' + const browsers = { safariMac: { base: 'BrowserStack', diff --git a/js/tests/integration/bundle-modularity.js b/js/tests/integration/bundle-modularity.js index 8546141..3c1eec9 100644 --- a/js/tests/integration/bundle-modularity.js +++ b/js/tests/integration/bundle-modularity.js @@ -1,3 +1,5 @@ +/* eslint-disable import/extensions, import/no-unassigned-import */ + import Tooltip from '../../dist/tooltip' import '../../dist/carousel' diff --git a/js/tests/integration/rollup.bundle-modularity.js b/js/tests/integration/rollup.bundle-modularity.js index a8670ca..63d6515 100644 --- a/js/tests/integration/rollup.bundle-modularity.js +++ b/js/tests/integration/rollup.bundle-modularity.js @@ -1,7 +1,7 @@ -/* eslint-env node */ +'use strict' const commonjs = require('@rollup/plugin-commonjs') -const configRollup = require('./rollup.bundle') +const configRollup = require('./rollup.bundle.js') const config = { ...configRollup, diff --git a/js/tests/integration/rollup.bundle.js b/js/tests/integration/rollup.bundle.js index caddcab..8b3c578 100644 --- a/js/tests/integration/rollup.bundle.js +++ b/js/tests/integration/rollup.bundle.js @@ -1,4 +1,4 @@ -/* eslint-env node */ +'use strict' const { babel } = require('@rollup/plugin-babel') const { nodeResolve } = require('@rollup/plugin-node-resolve') diff --git a/js/tests/karma.conf.js b/js/tests/karma.conf.js index 6636ff1..36bf7f2 100644 --- a/js/tests/karma.conf.js +++ b/js/tests/karma.conf.js @@ -1,5 +1,3 @@ -/* eslint-env node */ - 'use strict' const path = require('node:path') @@ -8,7 +6,7 @@ const { babel } = require('@rollup/plugin-babel') const istanbul = require('rollup-plugin-istanbul') const { nodeResolve } = require('@rollup/plugin-node-resolve') const replace = require('@rollup/plugin-replace') -const { browsers } = require('./browsers') +const { browsers } = require('./browsers.js') const ENV = process.env const BROWSERSTACK = Boolean(ENV.BROWSERSTACK) @@ -105,7 +103,7 @@ if (BROWSERSTACK) { config.browserStack = { username: ENV.BROWSER_STACK_USERNAME, accessKey: ENV.BROWSER_STACK_ACCESS_KEY, - build: `bootstrap-${ENV.GITHUB_SHA ? ENV.GITHUB_SHA.slice(0, 7) + '-' : ''}${new Date().toISOString()}`, + build: `bootstrap-${ENV.GITHUB_SHA ? `${ENV.GITHUB_SHA.slice(0, 7)}-` : ''}${new Date().toISOString()}`, project: 'Bootstrap', retryLimit: 2 } 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 diff --git a/js/tests/visual/.eslintrc.json b/js/tests/visual/.eslintrc.json deleted file mode 100644 index 8a33225..0000000 --- a/js/tests/visual/.eslintrc.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "plugins": [ - "html" - ], - "extends": "../../../.eslintrc.json", - "parserOptions": { - "sourceType": "module" - }, - "settings": { - "html/html-extensions": [ - ".html" - ] - }, - "rules": { - "no-console": "off", - "no-new": "off", - "unicorn/no-array-for-each": "off" - } -} diff --git a/js/tests/visual/button.html b/js/tests/visual/button.html index 0c54934..47c5088 100644 --- a/js/tests/visual/button.html +++ b/js/tests/visual/button.html @@ -15,7 +15,7 @@ </button> <p>For checkboxes and radio buttons, ensure that keyboard behavior is functioning correctly.</p> - <p>Navigate to the checkboxes with the keyboard (generally, using <kbd>TAB</kbd> / <kbd>SHIFT + TAB</kbd>), and ensure that <kbd>SPACE</kbd> toggles the currently focused checkbox. Click on one of the checkboxes using the mouse, ensure that focus was correctly set on the actual checkbox, and that <kbd>SPACE</kbd> toggles the checkbox again.</p> + <p>Navigate to the checkboxes with the keyboard (generally, using <kbd>Tab</kbd> / <kbd><kbd>Shift</kbd> + <kbd>Tab</kbd></kbd>), and ensure that <kbd>Space</kbd> toggles the currently focused checkbox. Click on one of the checkboxes using the mouse, ensure that focus was correctly set on the actual checkbox, and that <kbd>Space</kbd> toggles the checkbox again.</p> <div class="btn-group" data-bs-toggle="buttons"> <label class="btn btn-primary active"> @@ -29,7 +29,7 @@ </label> </div> - <p>Navigate to the radio button group with the keyboard (generally, using <kbd>TAB</kbd> / <kbd>SHIFT + TAB</kbd>). If no radio button was initially set to be selected, the first/last radio button should receive focus (depending on whether you navigated "forward" to the group with <kbd>TAB</kbd> or "backwards" using <kbd>SHIFT + TAB</kbd>). If a radio button was already selected, navigating with the keyboard should set focus to that particular radio button. Only one radio button in a group should receive focus at any given time. Ensure that the selected radio button can be changed by using the <kbd>←</kbd> and <kbd>→</kbd> arrow keys. Click on one of the radio buttons with the mouse, ensure that focus was correctly set on the actual radio button, and that <kbd>←</kbd> and <kbd>→</kbd> change the selected radio button again.</p> + <p>Navigate to the radio button group with the keyboard (generally, using <kbd>Tab</kbd> / <kbd><kbd>Shift</kbd> + <kbd>Tab</kbd></kbd>). If no radio button was initially set to be selected, the first/last radio button should receive focus (depending on whether you navigated "forward" to the group with <kbd>Tab</kbd> or "backwards" using <kbd><kbd>Shift</kbd> + <kbd>Tab</kbd></kbd>). If a radio button was already selected, navigating with the keyboard should set focus to that particular radio button. Only one radio button in a group should receive focus at any given time. Ensure that the selected radio button can be changed by using the <kbd>←</kbd> and <kbd>→</kbd> arrow keys. Click on one of the radio buttons with the mouse, ensure that focus was correctly set on the actual radio button, and that <kbd>←</kbd> and <kbd>→</kbd> change the selected radio button again.</p> <div class="btn-group" data-bs-toggle="buttons"> <label class="btn btn-primary active"> diff --git a/js/tests/visual/carousel.html b/js/tests/visual/carousel.html index 153c866..1b2de52 100644 --- a/js/tests/visual/carousel.html +++ b/js/tests/visual/carousel.html @@ -55,7 +55,7 @@ // Test to show that transition-duration can be changed with css carousel.addEventListener('slid.bs.carousel', event => { t1 = performance.now() - console.log('transition-duration took ' + (t1 - t0) + 'ms, slid at ' + event.timeStamp) + console.log(`transition-duration took ${t1 - t0}ms, slid at ${event.timeStamp}`) }) carousel.addEventListener('slide.bs.carousel', () => { t0 = performance.now() diff --git a/js/tests/visual/input.html b/js/tests/visual/input.html new file mode 100644 index 0000000..1e5eec2 --- /dev/null +++ b/js/tests/visual/input.html @@ -0,0 +1,78 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link href="../../../dist/css/bootstrap.min.css" rel="stylesheet"> + <title>Form</title> + <style></style> + </head> + <body> + <div class="container"> + <h1>Input <small>Bootstrap Visual Test</small></h1> + + <h2>No layout</h2> + + <div class="mb-3"> + Text + <input class="form-control"> + </div> + <div class="mb-3"> + Email + <input type="email" class="form-control"> + </div> + <div class="mb-3"> + Number + <input type="number" class="form-control"> + </div> + <div class="mb-3"> + Date + <input type="date" class="form-control"> + </div> + + <h2>Flex</h2> + + <div class="d-flex flex-wrap gap-3 mb-3"> + <div> + Text + <input class="form-control"> + </div> + <div> + Email + <input type="email" class="form-control"> + </div> + <div> + Number + <input type="number" class="form-control"> + </div> + <div> + Date + <input type="date" class="form-control"> + </div> + </div> + + <h2>Grid</h2> + + <div class="row mb-3"> + <div class="col"> + Text + <input class="form-control"> + </div> + <div class="col"> + Email + <input type="email" class="form-control"> + </div> + <div class="col"> + Number + <input type="number" class="form-control"> + </div> + <div class="col"> + Date + <input type="date" class="form-control"> + </div> + </div> + </div> + + <script src="../../../dist/js/bootstrap.bundle.js"></script> + </body> +</html> diff --git a/js/tests/visual/modal.html b/js/tests/visual/modal.html index b738d9e..09d4233 100644 --- a/js/tests/visual/modal.html +++ b/js/tests/visual/modal.html @@ -264,7 +264,7 @@ slowModal.addEventListener('shown.bs.modal', () => { t1 = performance.now() - console.log('transition-duration took ' + (t1 - t0) + 'ms.') + console.log(`transition-duration took ${t1 - t0}ms.`) }) slowModal.addEventListener('show.bs.modal', () => { diff --git a/js/tests/visual/scrollspy.html b/js/tests/visual/scrollspy.html index 2daa7ab..5410284 100644 --- a/js/tests/visual/scrollspy.html +++ b/js/tests/visual/scrollspy.html @@ -29,6 +29,7 @@ <li><a class="dropdown-item" href="#one">One</a></li> <li><a class="dropdown-item" href="#two">Two</a></li> <li><a class="dropdown-item" href="#three">Three</a></li> + <li><a class="dropdown-item" href="#présentation">Présentation</a></li> </ul> </li> <li class="nav-item"> @@ -82,6 +83,14 @@ <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> <hr> + <h2 id="présentation">Présentation</h2> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <hr> <h2 id="final">Final section</h2> <p>Ad leggings keytar, brunch id art party dolor labore.</p> </div> diff --git a/js/tests/visual/toast.html b/js/tests/visual/toast.html index f86926d..e64fd1d 100644 --- a/js/tests/visual/toast.html +++ b/js/tests/visual/toast.html @@ -41,7 +41,7 @@ <div class="toast-header"> <span class="d-block bg-primary rounded me-2" style="width: 20px; height: 20px;"></span> <strong class="me-auto">Bootstrap</strong> - <small class="text-muted">2 seconds ago</small> + <small class="text-body-secondary">2 seconds ago</small> <button type="button" class="ms-2 mb-1 btn-close" data-bs-dismiss="toast" aria-label="Close"></button> </div> <div class="toast-body"> diff --git a/js/tests/visual/tooltip.html b/js/tests/visual/tooltip.html index 1a3b9f2..09144b5 100644 --- a/js/tests/visual/tooltip.html +++ b/js/tests/visual/tooltip.html @@ -20,7 +20,7 @@ <div class="container"> <h1>Tooltip <small>Bootstrap Visual Test</small></h1> - <p class="text-muted">Tight pants next level keffiyeh <a href="#" data-bs-toggle="tooltip" title="Default tooltip">you probably</a> haven't heard of them. Photo booth beard raw denim letterpress vegan messenger bag stumptown. Farm-to-table seitan, mcsweeney's fixie sustainable quinoa 8-bit american apparel <a href="#" data-bs-toggle="tooltip" title="Another tooltip">have a</a> terry richardson vinyl chambray. Beard stumptown, cardigans banh mi lomo thundercats. Tofu biodiesel williamsburg marfa, four loko mcsweeney's cleanse vegan chambray. A really ironic artisan <a href="#" data-bs-toggle="tooltip" title="Another one here too">whatever keytar</a>, scenester farm-to-table banksy Austin <a href="#" data-bs-toggle="tooltip" title="The last tip!">twitter handle</a> freegan cred raw denim single-origin coffee viral.</p> + <p class="text-body-secondary">Tight pants next level keffiyeh <a href="#" data-bs-toggle="tooltip" title="Default tooltip">you probably</a> haven't heard of them. Photo booth beard raw denim letterpress vegan messenger bag stumptown. Farm-to-table seitan, mcsweeney's fixie sustainable quinoa 8-bit american apparel <a href="#" data-bs-toggle="tooltip" title="Another tooltip">have a</a> terry richardson vinyl chambray. Beard stumptown, cardigans banh mi lomo thundercats. Tofu biodiesel williamsburg marfa, four loko mcsweeney's cleanse vegan chambray. A really ironic artisan <a href="#" data-bs-toggle="tooltip" title="Another one here too">whatever keytar</a>, scenester farm-to-table banksy Austin <a href="#" data-bs-toggle="tooltip" title="The last tip!">twitter handle</a> freegan cred raw denim single-origin coffee viral.</p> <hr> |