diff options
| author | lucascono <[email protected]> | 2017-10-04 05:33:17 -0300 |
|---|---|---|
| committer | lucascono <[email protected]> | 2017-10-04 05:33:17 -0300 |
| commit | 8c04a74c8c7f0174ea08bc02fa3762f49bf615a3 (patch) | |
| tree | db9d6923c082243d765c57885992db8dd26a70b5 /js/tests | |
| parent | 9aff890efa3798f831b714c41794c9fee0684bae (diff) | |
| parent | b29b1e155880ac953899889c9cbb67f7f7df0529 (diff) | |
| download | bootstrap-8c04a74c8c7f0174ea08bc02fa3762f49bf615a3.tar.xz bootstrap-8c04a74c8c7f0174ea08bc02fa3762f49bf615a3.zip | |
Merge remote-tracking branch 'refs/remotes/twbs/v4-dev' into v4-dev
Diffstat (limited to 'js/tests')
| -rw-r--r-- | js/tests/.eslintrc.json | 4 | ||||
| -rw-r--r-- | js/tests/index.html | 2 | ||||
| -rw-r--r-- | js/tests/unit/alert.js | 2 | ||||
| -rw-r--r-- | js/tests/unit/button.js | 2 | ||||
| -rw-r--r-- | js/tests/unit/carousel.js | 86 | ||||
| -rw-r--r-- | js/tests/unit/collapse.js | 71 | ||||
| -rw-r--r-- | js/tests/unit/dropdown.js | 4 | ||||
| -rw-r--r-- | js/tests/unit/modal.js | 128 | ||||
| -rw-r--r-- | js/tests/unit/popover.js | 29 | ||||
| -rw-r--r-- | js/tests/unit/scrollspy.js | 43 | ||||
| -rw-r--r-- | js/tests/unit/tab.js | 77 | ||||
| -rw-r--r-- | js/tests/unit/tooltip.js | 28 | ||||
| -rw-r--r-- | js/tests/visual/alert.html | 2 | ||||
| -rw-r--r-- | js/tests/visual/button.html | 2 | ||||
| -rw-r--r-- | js/tests/visual/carousel.html | 8 | ||||
| -rw-r--r-- | js/tests/visual/collapse.html | 4 | ||||
| -rw-r--r-- | js/tests/visual/dropdown.html | 2 | ||||
| -rw-r--r-- | js/tests/visual/modal.html | 6 | ||||
| -rw-r--r-- | js/tests/visual/popover.html | 2 | ||||
| -rw-r--r-- | js/tests/visual/scrollspy.html | 2 | ||||
| -rw-r--r-- | js/tests/visual/tab.html | 10 | ||||
| -rw-r--r-- | js/tests/visual/tooltip.html | 2 |
22 files changed, 453 insertions, 63 deletions
diff --git a/js/tests/.eslintrc.json b/js/tests/.eslintrc.json index a05a3a390..460286508 100644 --- a/js/tests/.eslintrc.json +++ b/js/tests/.eslintrc.json @@ -21,13 +21,11 @@ "no-magic-numbers": "off", "vars-on-top": "off", - // Strict Mode - "strict": "off", - // NodeJS and CommonJS "global-require": "off", "no-process-env": "off", "no-process-exit": "off", + "no-sync": "off", // Stylistic Issues "brace-style": "off", diff --git a/js/tests/index.html b/js/tests/index.html index 6e2b974f9..ad5b6437a 100644 --- a/js/tests/index.html +++ b/js/tests/index.html @@ -1,4 +1,4 @@ -<!DOCTYPE html> +<!doctype html> <html> <head> <meta charset="utf-8"> diff --git a/js/tests/unit/alert.js b/js/tests/unit/alert.js index e078082c3..aee2b70d5 100644 --- a/js/tests/unit/alert.js +++ b/js/tests/unit/alert.js @@ -21,7 +21,7 @@ $(function () { QUnit.test('should provide no conflict', function (assert) { assert.expect(1) - assert.strictEqual($.fn.alert, undefined, 'alert was set back to undefined (org value)') + assert.strictEqual(typeof $.fn.alert, 'undefined', 'alert was set back to undefined (org value)') }) QUnit.test('should return jquery collection containing the element', function (assert) { diff --git a/js/tests/unit/button.js b/js/tests/unit/button.js index 489d400a6..e2a51bb4d 100644 --- a/js/tests/unit/button.js +++ b/js/tests/unit/button.js @@ -21,7 +21,7 @@ $(function () { QUnit.test('should provide no conflict', function (assert) { assert.expect(1) - assert.strictEqual($.fn.button, undefined, 'button was set back to undefined (org value)') + assert.strictEqual(typeof $.fn.button, 'undefined', 'button was set back to undefined (org value)') }) QUnit.test('should return jquery collection containing the element', function (assert) { diff --git a/js/tests/unit/carousel.js b/js/tests/unit/carousel.js index 894f78ab5..521b24ca4 100644 --- a/js/tests/unit/carousel.js +++ b/js/tests/unit/carousel.js @@ -21,7 +21,7 @@ $(function () { QUnit.test('should provide no conflict', function (assert) { assert.expect(1) - assert.strictEqual($.fn.carousel, undefined, 'carousel was set back to undefined (orig value)') + assert.strictEqual(typeof $.fn.carousel, 'undefined', 'carousel was set back to undefined (orig value)') }) QUnit.test('should throw explicit error on undefined method', function (assert) { @@ -371,14 +371,14 @@ $(function () { var done = assert.async() $(template) .on('slid.bs.carousel', function (e) { - assert.ok(e.from !== undefined, 'from present') - assert.ok(e.to !== undefined, 'to present') + assert.ok(typeof e.from !== 'undefined', 'from present') + assert.ok(typeof e.to !== 'undefined', 'to present') $(this).off() done() }) .on('slide.bs.carousel', function (e) { - assert.ok(e.from !== undefined, 'from present') - assert.ok(e.to !== undefined, 'to present') + assert.ok(typeof e.from !== 'undefined', 'from present') + assert.ok(typeof e.to !== 'undefined', 'to present') $(this).off('slide.bs.carousel') }) .bootstrapCarousel('next') @@ -842,4 +842,80 @@ $(function () { }) $textArea.trigger(eventKeyDown) }) + + QUnit.test('Should not go to the next item when the carousel is not visible', function (assert) { + assert.expect(2) + var done = assert.async() + var html = '<div id="myCarousel" class="carousel slide" data-interval="50" style="display: none;">' + + ' <div class="carousel-inner">' + + ' <div id="firstItem" class="carousel-item active">' + + ' <img alt="">' + + ' </div>' + + ' <div class="carousel-item">' + + ' <img alt="">' + + ' </div>' + + ' <div class="carousel-item">' + + ' <img alt="">' + + ' </div>' + + ' <a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + + ' <a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + + '</div>' + var $html = $(html) + $html + .appendTo('#qunit-fixture') + .bootstrapCarousel() + + var $firstItem = $('#firstItem') + setTimeout(function () { + assert.ok($firstItem.hasClass('active')) + $html + .bootstrapCarousel('dispose') + .attr('style', 'visibility: hidden;') + .bootstrapCarousel() + + setTimeout(function () { + assert.ok($firstItem.hasClass('active')) + done() + }, 80) + }, 80) + }) + + QUnit.test('Should not go to the next item when the parent of the carousel is not visible', function (assert) { + assert.expect(2) + var done = assert.async() + var html = '<div id="parent" style="display: none;">' + + ' <div id="myCarousel" class="carousel slide" data-interval="50" style="display: none;">' + + ' <div class="carousel-inner">' + + ' <div id="firstItem" class="carousel-item active">' + + ' <img alt="">' + + ' </div>' + + ' <div class="carousel-item">' + + ' <img alt="">' + + ' </div>' + + ' <div class="carousel-item">' + + ' <img alt="">' + + ' </div>' + + ' <a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + + ' <a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + + ' </div>' + + '</div>' + var $html = $(html) + $html.appendTo('#qunit-fixture') + var $parent = $html.find('#parent') + var $carousel = $html.find('#myCarousel') + $carousel.bootstrapCarousel() + var $firstItem = $('#firstItem') + + setTimeout(function () { + assert.ok($firstItem.hasClass('active')) + $carousel.bootstrapCarousel('dispose') + $parent.attr('style', 'visibility: hidden;') + $carousel.bootstrapCarousel() + + setTimeout(function () { + assert.ok($firstItem.hasClass('active')) + done() + }, 80) + }, 80) + }) }) diff --git a/js/tests/unit/collapse.js b/js/tests/unit/collapse.js index 0e9e8b6a7..c36fe25be 100644 --- a/js/tests/unit/collapse.js +++ b/js/tests/unit/collapse.js @@ -21,7 +21,7 @@ $(function () { QUnit.test('should provide no conflict', function (assert) { assert.expect(1) - assert.strictEqual($.fn.collapse, undefined, 'collapse was set back to undefined (org value)') + assert.strictEqual(typeof $.fn.collapse, 'undefined', 'collapse was set back to undefined (org value)') }) QUnit.test('should throw explicit error on undefined method', function (assert) { @@ -673,4 +673,73 @@ $(function () { }) $trigger3.trigger('click') }) + + QUnit.test('should not prevent interactions inside the collapse element', function (assert) { + assert.expect(2) + var done = assert.async() + + var $target = $('<input type="checkbox" data-toggle="collapse" data-target="#collapsediv1" />').appendTo('#qunit-fixture') + var htmlCollapse = + '<div id="collapsediv1" class="collapse">' + + ' <input type="checkbox" id="testCheckbox" />' + + '</div>' + + $(htmlCollapse) + .appendTo('#qunit-fixture') + .on('shown.bs.collapse', function () { + assert.ok($target.prop('checked'), '$trigger is checked') + var $testCheckbox = $('#testCheckbox') + $testCheckbox.trigger($.Event('click')) + setTimeout(function () { + assert.ok($testCheckbox.prop('checked'), '$testCheckbox is checked too') + done() + }, 5) + }) + + $target.trigger($.Event('click')) + }) + + QUnit.test('should allow jquery object in parent config', function (assert) { + assert.expect(1) + var html = + '<div class="my-collapse">' + + ' <div class="item">' + + ' <a data-toggle="collapse" href="#">Toggle item</a>' + + ' <div class="collapse">Lorem ipsum</div>' + + ' </div>' + + '</div>' + + $(html).appendTo('#qunit-fixture') + try { + $('[data-toggle="collapse"]').bootstrapCollapse({ + parent: $('.my-collapse') + }) + assert.ok(true, 'collapse correctly created') + } + catch (e) { + assert.ok(false, 'collapse not created') + } + }) + + QUnit.test('should allow DOM object in parent config', function (assert) { + assert.expect(1) + var html = + '<div class="my-collapse">' + + ' <div class="item">' + + ' <a data-toggle="collapse" href="#">Toggle item</a>' + + ' <div class="collapse">Lorem ipsum</div>' + + ' </div>' + + '</div>' + + $(html).appendTo('#qunit-fixture') + try { + $('[data-toggle="collapse"]').bootstrapCollapse({ + parent: $('.my-collapse')[0] + }) + assert.ok(true, 'collapse correctly created') + } + catch (e) { + assert.ok(false, 'collapse not created') + } + }) }) diff --git a/js/tests/unit/dropdown.js b/js/tests/unit/dropdown.js index e44e47bbc..0b808cc48 100644 --- a/js/tests/unit/dropdown.js +++ b/js/tests/unit/dropdown.js @@ -21,7 +21,7 @@ $(function () { QUnit.test('should provide no conflict', function (assert) { assert.expect(1) - assert.strictEqual($.fn.dropdown, undefined, 'dropdown was set back to undefined (org value)') + assert.strictEqual(typeof $.fn.dropdown, 'undefined', 'dropdown was set back to undefined (org value)') }) QUnit.test('should throw explicit error on undefined method', function (assert) { @@ -644,7 +644,7 @@ $(function () { $triggerDropdown .parent('.dropdown') .on('shown.bs.dropdown', function () { - assert.ok($dropdownMenu.attr('style') === undefined, 'No inline style applied by Popper.js') + assert.ok(typeof $dropdownMenu.attr('style') === 'undefined', 'No inline style applied by Popper.js') done() }) $triggerDropdown.trigger($.Event('click')) diff --git a/js/tests/unit/modal.js b/js/tests/unit/modal.js index fc6c4f38c..e026cd7f1 100644 --- a/js/tests/unit/modal.js +++ b/js/tests/unit/modal.js @@ -21,6 +21,8 @@ $(function () { document.body.removeChild(scrollDiv) return scrollbarWidth } + // Simulate scrollbars in PhantomJS + $('html').css('padding-right', '16px') }, beforeEach: function () { // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode @@ -34,7 +36,7 @@ $(function () { QUnit.test('should provide no conflict', function (assert) { assert.expect(1) - assert.strictEqual($.fn.modal, undefined, 'modal was set back to undefined (orig value)') + assert.strictEqual(typeof $.fn.modal, 'undefined', 'modal was set back to undefined (orig value)') }) QUnit.test('should throw explicit error on undefined method', function (assert) { @@ -349,6 +351,20 @@ $(function () { $toggleBtn.trigger('click') }) + QUnit.test('should adjust the inline padding of the modal when opening', function (assert) { + assert.expect(1) + var done = assert.async() + + $('<div id="modal-test"/>') + .on('shown.bs.modal', function () { + var expectedPadding = $(this).getScrollbarWidth() + 'px' + var currentPadding = $(this).css('padding-right') + assert.strictEqual(currentPadding, expectedPadding, 'modal padding should be adjusted while opening') + done() + }) + .bootstrapModal('show') + }) + QUnit.test('should adjust the inline body padding when opening and restore when closing', function (assert) { assert.expect(2) var done = assert.async() @@ -380,7 +396,7 @@ $(function () { $('<div id="modal-test"/>') .on('hidden.bs.modal', function () { - assert.strictEqual($body.data('padding-right'), undefined, 'data-padding-right should be cleared after closing') + assert.strictEqual(typeof $body.data('padding-right'), 'undefined', 'data-padding-right should be cleared after closing') $body.removeAttr('style') done() }) @@ -391,6 +407,30 @@ $(function () { .bootstrapModal('show') }) + QUnit.test('should not adjust the inline body padding when it does not overflow', function (assert) { + assert.expect(1) + var done = assert.async() + var $body = $(document.body) + var originalPadding = $body.css('padding-right') + + // Hide scrollbars to prevent the body overflowing + $body.css('overflow', 'hidden') // real scrollbar (for in-browser testing) + $('html').css('padding-right', '0px') // simulated scrollbar (for PhantomJS) + + $('<div id="modal-test"/>') + .on('shown.bs.modal', function () { + var currentPadding = $body.css('padding-right') + assert.strictEqual(currentPadding, originalPadding, 'body padding should not be adjusted') + $(this).bootstrapModal('hide') + + // restore scrollbars + $body.css('overflow', 'auto') + $('html').css('padding-right', '16px') + done() + }) + .bootstrapModal('show') + }) + QUnit.test('should adjust the inline padding of fixed elements when opening and restore when closing', function (assert) { assert.expect(2) var done = assert.async() @@ -422,7 +462,7 @@ $(function () { $('<div id="modal-test"/>') .on('hidden.bs.modal', function () { - assert.strictEqual($element.data('padding-right'), undefined, 'data-padding-right should be cleared after closing') + assert.strictEqual(typeof $element.data('padding-right'), 'undefined', 'data-padding-right should be cleared after closing') $element.remove() done() }) @@ -433,6 +473,48 @@ $(function () { .bootstrapModal('show') }) + QUnit.test('should adjust the inline margin of sticky elements when opening and restore when closing', function (assert) { + assert.expect(2) + var done = assert.async() + var $element = $('<div class="sticky-top"></div>').appendTo('#qunit-fixture') + var originalPadding = $element.css('margin-right') + + $('<div id="modal-test"/>') + .on('hidden.bs.modal', function () { + var currentPadding = $element.css('margin-right') + assert.strictEqual(currentPadding, originalPadding, 'sticky element margin should be reset after closing') + $element.remove() + done() + }) + .on('shown.bs.modal', function () { + var expectedPadding = parseFloat(originalPadding) - $(this).getScrollbarWidth() + 'px' + var currentPadding = $element.css('margin-right') + assert.strictEqual(currentPadding, expectedPadding, 'sticky element margin should be adjusted while opening') + $(this).bootstrapModal('hide') + }) + .bootstrapModal('show') + }) + + QUnit.test('should store the original margin of sticky elements in data-margin-right before showing', function (assert) { + assert.expect(2) + var done = assert.async() + var $element = $('<div class="sticky-top"></div>').appendTo('#qunit-fixture') + var originalPadding = '0px' + $element.css('margin-right', originalPadding) + + $('<div id="modal-test"/>') + .on('hidden.bs.modal', function () { + assert.strictEqual(typeof $element.data('margin-right'), 'undefined', 'data-margin-right should be cleared after closing') + $element.remove() + done() + }) + .on('shown.bs.modal', function () { + assert.strictEqual($element.data('margin-right'), originalPadding, 'original sticky element margin should be stored in data-margin-right') + $(this).bootstrapModal('hide') + }) + .bootstrapModal('show') + }) + QUnit.test('should adjust the inline margin of the navbar-toggler when opening and restore when closing', function (assert) { assert.expect(2) var done = assert.async() @@ -464,7 +546,7 @@ $(function () { $('<div id="modal-test"/>') .on('hidden.bs.modal', function () { - assert.strictEqual($element.data('margin-right'), undefined, 'data-margin-right should be cleared after closing') + assert.strictEqual(typeof $element.data('margin-right'), 'undefined', 'data-margin-right should be cleared after closing') $element.remove() done() }) @@ -483,7 +565,7 @@ $(function () { $('<div id="modal-test"/>') .on('hidden.bs.modal', function () { - assert.ok(!$body.attr('style'), 'body does not have inline padding set') + assert.strictEqual($body.attr('style').indexOf('padding-right'), -1, 'body does not have inline padding set') $style.remove() done() }) @@ -555,4 +637,40 @@ $(function () { }) .trigger('click') }) + + QUnit.test('should not parse target as html', function (assert) { + assert.expect(1) + var done = assert.async() + + var $toggleBtn = $('<button data-toggle="modal" data-target="<div id="modal-test"><div class="contents"<div<div id="close" data-dismiss="modal"/></div></div>"/>') + .appendTo('#qunit-fixture') + + $toggleBtn.trigger('click') + setTimeout(function () { + assert.strictEqual($('#modal-test').length, 0, 'target has not been parsed and added to the document') + done() + }, 1) + }) + + QUnit.test('should not execute js from target', function (assert) { + assert.expect(0) + var done = assert.async() + + // This toggle button contains XSS payload in its data-target + // Note: it uses the onerror handler of an img element to execute the js, because a simple script element does not work here + // a script element works in manual tests though, so here it is likely blocked by the qunit framework + var $toggleBtn = $('<button data-toggle="modal" data-target="<div><image src="missing.png" onerror="$('#qunit-fixture button.control').trigger('click')"></div>"/>') + .appendTo('#qunit-fixture') + // The XSS payload above does not have a closure over this function and cannot access the assert object directly + // However, it can send a click event to the following control button, which will then fail the assert + $('<button>') + .addClass('control') + .on('click', function () { + assert.notOk(true, 'XSS payload is not executed as js') + }) + .appendTo('#qunit-fixture') + + $toggleBtn.trigger('click') + setTimeout(done, 500) + }) }) diff --git a/js/tests/unit/popover.js b/js/tests/unit/popover.js index f9c1b429d..b5ea714ea 100644 --- a/js/tests/unit/popover.js +++ b/js/tests/unit/popover.js @@ -22,7 +22,7 @@ $(function () { QUnit.test('should provide no conflict', function (assert) { assert.expect(1) - assert.strictEqual($.fn.popover, undefined, 'popover was set back to undefined (org value)') + assert.strictEqual(typeof $.fn.popover, 'undefined', 'popover was set back to undefined (org value)') }) QUnit.test('should throw explicit error on undefined method', function (assert) { @@ -242,7 +242,7 @@ $(function () { QUnit.test('should render popover element using delegated selector', function (assert) { assert.expect(2) - var $div = $('<div><a href="#" title="mdo" data-content="http://twitter.com/mdo">@mdo</a></div>') + var $div = $('<div><a href="#" title="mdo" data-content="https://twitter.com/mdo">@mdo</a></div>') .appendTo('#qunit-fixture') .bootstrapPopover({ selector: 'a', @@ -304,7 +304,7 @@ $(function () { assert.ok(false, 'should not fire any popover events') }) .bootstrapPopover('hide') - assert.strictEqual($popover.data('bs.popover'), undefined, 'should not initialize the popover') + assert.strictEqual(typeof $popover.data('bs.popover'), 'undefined', 'should not initialize the popover') }) QUnit.test('should fire inserted event', function (assert) { @@ -387,4 +387,27 @@ $(function () { $popover.bootstrapPopover('show') }) + + QUnit.test('popover should be shown right away after the call of disable/enable', function (assert) { + assert.expect(2) + var done = assert.async() + var $popover = $('<a href="#">@mdo</a>') + .appendTo('#qunit-fixture') + .bootstrapPopover({ + title: 'Test popover', + content: 'with disable/enable' + }) + .on('shown.bs.popover', function () { + assert.strictEqual($('.popover').hasClass('show'), true) + done() + }) + + $popover.bootstrapPopover('disable') + $popover.trigger($.Event('click')) + setTimeout(function () { + assert.strictEqual($('.popover').length === 0, true) + $popover.bootstrapPopover('enable') + $popover.trigger($.Event('click')) + }, 200) + }) }) diff --git a/js/tests/unit/scrollspy.js b/js/tests/unit/scrollspy.js index a6a72e7a6..7bdeb4a8d 100644 --- a/js/tests/unit/scrollspy.js +++ b/js/tests/unit/scrollspy.js @@ -21,7 +21,7 @@ $(function () { QUnit.test('should provide no conflict', function (assert) { assert.expect(1) - assert.strictEqual($.fn.scrollspy, undefined, 'scrollspy was set back to undefined (org value)') + assert.strictEqual(typeof $.fn.scrollspy, 'undefined', 'scrollspy was set back to undefined (org value)') }) QUnit.test('should throw explicit error on undefined method', function (assert) { @@ -360,6 +360,47 @@ $(function () { testActiveElements() }) + + QUnit.test('should add the active class correctly when there are nested elements (nav nav-item markup)', function (assert) { + assert.expect(6) + var times = 0 + var done = assert.async() + var navbarHtml = '<nav id="navigation" class="navbar">' + + '<ul class="nav">' + + '<li class="nav-item"><a id="a-1" class="nav-link" href="#div-1">div 1</a></li>' + + '<ul class="nav">' + + '<li class="nav-item"><a id="a-2" class="nav-link" href="#div-2">div 2</a></li>' + + '</ul>' + + '</ul>' + + '</nav>' + + var contentHtml = '<div class="content" style="position: absolute; top: 0px; overflow: auto; height: 50px">' + + '<div id="div-1" style="padding: 0; margin: 0">' + + '<div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>' + + '</div>' + + '</div>' + + $(navbarHtml).appendTo('#qunit-fixture') + + var $content = $(contentHtml) + .appendTo('#qunit-fixture') + .bootstrapScrollspy({ offset: 0, target: '#navigation' }) + + function testActiveElements() { + if (++times > 3) { return done() } + + $content.one('scroll', function () { + assert.ok($('#a-1').hasClass('active'), 'nav item for outer element has "active" class') + assert.ok($('#a-2').hasClass('active'), 'nav item for inner element has "active" class') + testActiveElements() + }) + + $content.scrollTop($content.scrollTop() + 10) + } + + testActiveElements() + }) + QUnit.test('should add the active class correctly when there are nested elements (list-group markup)', function (assert) { assert.expect(6) var times = 0 diff --git a/js/tests/unit/tab.js b/js/tests/unit/tab.js index 1e2b66c04..73ebbd660 100644 --- a/js/tests/unit/tab.js +++ b/js/tests/unit/tab.js @@ -21,7 +21,7 @@ $(function () { QUnit.test('should provide no conflict', function (assert) { assert.expect(1) - assert.strictEqual($.fn.tab, undefined, 'tab was set back to undefined (org value)') + assert.strictEqual(typeof $.fn.tab, 'undefined', 'tab was set back to undefined (org value)') }) QUnit.test('should throw explicit error on undefined method', function (assert) { @@ -182,13 +182,14 @@ $(function () { assert.expect(2) var done = assert.async() - var dropHTML = '<ul class="drop nav">' - + '<li class="dropdown"><a data-toggle="dropdown" href="#">1</a>' - + '<ul class="dropdown-menu">' - + '<li><a href="#1-1" data-toggle="tab">1-1</a></li>' - + '<li><a href="#1-2" data-toggle="tab">1-2</a></li>' - + '</ul>' - + '</li>' + var dropHTML = + '<ul class="drop nav">' + + ' <li class="dropdown"><a data-toggle="dropdown" href="#">1</a>' + + ' <ul class="dropdown-menu nav">' + + ' <li><a href="#1-1" data-toggle="tab">1-1</a></li>' + + ' <li><a href="#1-2" data-toggle="tab">1-2</a></li>' + + ' </ul>' + + ' </li>' + '</ul>' $(dropHTML) @@ -286,29 +287,29 @@ $(function () { .bootstrapTab('show') }) - QUnit.test('selected tab should have aria-expanded', function (assert) { + QUnit.test('selected tab should have aria-selected', function (assert) { assert.expect(8) var tabsHTML = '<ul class="nav nav-tabs">' - + '<li><a class="nav-item active" href="#home" toggle="tab" aria-expanded="true">Home</a></li>' - + '<li><a class="nav-item" href="#profile" toggle="tab" aria-expanded="false">Profile</a></li>' + + '<li><a class="nav-item active" href="#home" toggle="tab" aria-selected="true">Home</a></li>' + + '<li><a class="nav-item" href="#profile" toggle="tab" aria-selected="false">Profile</a></li>' + '</ul>' var $tabs = $(tabsHTML).appendTo('#qunit-fixture') $tabs.find('li:first a').bootstrapTab('show') - assert.strictEqual($tabs.find('.active').attr('aria-expanded'), 'true', 'shown tab has aria-expanded = true') - assert.strictEqual($tabs.find('a:not(.active)').attr('aria-expanded'), 'false', 'hidden tab has aria-expanded = false') + assert.strictEqual($tabs.find('.active').attr('aria-selected'), 'true', 'shown tab has aria-selected = true') + assert.strictEqual($tabs.find('a:not(.active)').attr('aria-selected'), 'false', 'hidden tab has aria-selected = false') $tabs.find('li:last a').trigger('click') - assert.strictEqual($tabs.find('.active').attr('aria-expanded'), 'true', 'after click, shown tab has aria-expanded = true') - assert.strictEqual($tabs.find('a:not(.active)').attr('aria-expanded'), 'false', 'after click, hidden tab has aria-expanded = false') + assert.strictEqual($tabs.find('.active').attr('aria-selected'), 'true', 'after click, shown tab has aria-selected = true') + assert.strictEqual($tabs.find('a:not(.active)').attr('aria-selected'), 'false', 'after click, hidden tab has aria-selected = false') $tabs.find('li:first a').bootstrapTab('show') - assert.strictEqual($tabs.find('.active').attr('aria-expanded'), 'true', 'shown tab has aria-expanded = true') - assert.strictEqual($tabs.find('a:not(.active)').attr('aria-expanded'), 'false', 'hidden tab has aria-expanded = false') + assert.strictEqual($tabs.find('.active').attr('aria-selected'), 'true', 'shown tab has aria-selected = true') + assert.strictEqual($tabs.find('a:not(.active)').attr('aria-selected'), 'false', 'hidden tab has aria-selected = false') $tabs.find('li:first a').trigger('click') - assert.strictEqual($tabs.find('.active').attr('aria-expanded'), 'true', 'after second show event, shown tab still has aria-expanded = true') - assert.strictEqual($tabs.find('a:not(.active)').attr('aria-expanded'), 'false', 'after second show event, hidden tab has aria-expanded = false') + assert.strictEqual($tabs.find('.active').attr('aria-selected'), 'true', 'after second show event, shown tab still has aria-selected = true') + assert.strictEqual($tabs.find('a:not(.active)').attr('aria-selected'), 'false', 'after second show event, hidden tab has aria-selected = false') }) QUnit.test('selected tab should deactivate previous selected tab', function (assert) { @@ -343,4 +344,42 @@ $(function () { assert.notOk($tabs.find('li:last > a').hasClass('active')) assert.notOk($tabs.find('li:last > .dropdown-menu > a:first').hasClass('active')) }) + + QUnit.test('Nested tabs', function (assert) { + assert.expect(2) + var done = assert.async() + var tabsHTML = + '<nav class="nav nav-tabs" role="tablist">' + + ' <a id="tab1" href="#x-tab1" class="nav-item nav-link" data-toggle="tab" role="tab" aria-controls="x-tab1">Tab 1</a>' + + ' <a href="#x-tab2" class="nav-item nav-link active" data-toggle="tab" role="tab" aria-controls="x-tab2" aria-selected="true">Tab 2</a>' + + ' <a href="#x-tab3" class="nav-item nav-link" data-toggle="tab" role="tab" aria-controls="x-tab3">Tab 3</a>' + + '</nav>' + + '<div class="tab-content">' + + ' <div class="tab-pane" id="x-tab1" role="tabpanel">' + + ' <nav class="nav nav-tabs" role="tablist">' + + ' <a href="#nested-tab1" class="nav-item nav-link active" data-toggle="tab" role="tab" aria-controls="x-tab1" aria-selected="true">Nested Tab 1</a>' + + ' <a id="tabNested2" href="#nested-tab2" class="nav-item nav-link" data-toggle="tab" role="tab" aria-controls="x-profile">Nested Tab2</a>' + + ' </nav>' + + ' <div class="tab-content">' + + ' <div class="tab-pane active" id="nested-tab1" role="tabpanel">Nested Tab1 Content</div>' + + ' <div class="tab-pane" id="nested-tab2" role="tabpanel">Nested Tab2 Content</div>' + + ' </div>' + + ' </div>' + + ' <div class="tab-pane active" id="x-tab2" role="tabpanel">Tab2 Content</div>' + + ' <div class="tab-pane" id="x-tab3" role="tabpanel">Tab3 Content</div>' + + '</div>' + + $(tabsHTML).appendTo('#qunit-fixture') + + $('#tabNested2').on('shown.bs.tab', function () { + assert.ok($('#x-tab1').hasClass('active')) + done() + }) + + $('#tab1').on('shown.bs.tab', function () { + assert.ok($('#x-tab1').hasClass('active')) + $('#tabNested2').trigger($.Event('click')) + }) + .trigger($.Event('click')) + }) }) diff --git a/js/tests/unit/tooltip.js b/js/tests/unit/tooltip.js index c0cafefe5..e4e6bdd6c 100644 --- a/js/tests/unit/tooltip.js +++ b/js/tests/unit/tooltip.js @@ -22,7 +22,7 @@ $(function () { QUnit.test('should provide no conflict', function (assert) { assert.expect(1) - assert.strictEqual($.fn.tooltip, undefined, 'tooltip was set back to undefined (org value)') + assert.strictEqual(typeof $.fn.tooltip, 'undefined', 'tooltip was set back to undefined (org value)') }) QUnit.test('should throw explicit error on undefined method', function (assert) { @@ -382,7 +382,7 @@ $(function () { .on('inserted.bs.tooltip', function () { var $tooltip = $($(this).data('bs.tooltip').tip) assert.ok($tooltip.hasClass('bs-tooltip-right')) - assert.ok($tooltip.attr('style') === undefined) + assert.ok(typeof $tooltip.attr('style') === 'undefined') $styles.remove() done() }) @@ -701,7 +701,7 @@ $(function () { assert.ok(false, 'should not fire any tooltip events') }) .bootstrapTooltip('hide') - assert.strictEqual($tooltip.data('bs.tooltip'), undefined, 'should not initialize the tooltip') + assert.strictEqual(typeof $tooltip.data('bs.tooltip'), 'undefined', 'should not initialize the tooltip') }) QUnit.test('should not remove tooltip if multiple triggers are set and one is still active', function (assert) { @@ -826,4 +826,26 @@ $(function () { $el.bootstrapTooltip('show') }) + + QUnit.test('tooltip should be shown right away after the call of disable/enable', function (assert) { + assert.expect(2) + var done = assert.async() + + var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip() + .on('shown.bs.tooltip', function () { + assert.strictEqual($('.tooltip').hasClass('show'), true) + done() + }) + + + $trigger.bootstrapTooltip('disable') + $trigger.trigger($.Event('click')) + setTimeout(function () { + assert.strictEqual($('.tooltip').length === 0, true) + $trigger.bootstrapTooltip('enable') + $trigger.trigger($.Event('click')) + }, 200) + }) }) diff --git a/js/tests/visual/alert.html b/js/tests/visual/alert.html index 4632e894a..bb2d9cb48 100644 --- a/js/tests/visual/alert.html +++ b/js/tests/visual/alert.html @@ -1,4 +1,4 @@ -<!DOCTYPE html> +<!doctype html> <html> <head> <meta charset="utf-8"> diff --git a/js/tests/visual/button.html b/js/tests/visual/button.html index 9aaf08d44..33de14d8b 100644 --- a/js/tests/visual/button.html +++ b/js/tests/visual/button.html @@ -1,4 +1,4 @@ -<!DOCTYPE html> +<!doctype html> <html> <head> <meta charset="utf-8"> diff --git a/js/tests/visual/carousel.html b/js/tests/visual/carousel.html index eae9df705..5bdd6160b 100644 --- a/js/tests/visual/carousel.html +++ b/js/tests/visual/carousel.html @@ -1,4 +1,4 @@ -<!DOCTYPE html> +<!doctype html> <html> <head> <meta charset="utf-8"> @@ -20,13 +20,13 @@ </ol> <div class="carousel-inner"> <div class="carousel-item active"> - <img src="http://i.imgur.com/iEZgY7Y.jpg" alt="First slide"> + <img src="https://i.imgur.com/iEZgY7Y.jpg" alt="First slide"> </div> <div class="carousel-item"> - <img src="http://i.imgur.com/eNWn1Xs.jpg" alt="Second slide"> + <img src="https://i.imgur.com/eNWn1Xs.jpg" alt="Second slide"> </div> <div class="carousel-item"> - <img src="http://i.imgur.com/Nm7xoti.jpg" alt="Third slide"> + <img src="https://i.imgur.com/Nm7xoti.jpg" alt="Third slide"> </div> </div> <a class="carousel-control-prev" href="#carousel-example-generic" role="button" data-slide="prev"> diff --git a/js/tests/visual/collapse.html b/js/tests/visual/collapse.html index 1d61ef19c..0c19def73 100644 --- a/js/tests/visual/collapse.html +++ b/js/tests/visual/collapse.html @@ -1,4 +1,4 @@ -<!DOCTYPE html> +<!doctype html> <html> <head> <meta charset="utf-8"> @@ -57,7 +57,7 @@ </div> </div> - <script src="../../../docs/assets/js/vendor/jquery-slim.min.js"></script> + <script src="../../../assets/js/vendor/jquery-slim.min.js"></script> <script src="../../dist/util.js"></script> <script src="../../dist/collapse.js"></script> </body> diff --git a/js/tests/visual/dropdown.html b/js/tests/visual/dropdown.html index 5a5cc45f6..bb0fc6e41 100644 --- a/js/tests/visual/dropdown.html +++ b/js/tests/visual/dropdown.html @@ -1,4 +1,4 @@ -<!DOCTYPE html> +<!doctype html> <html> <head> <meta charset="utf-8"> diff --git a/js/tests/visual/modal.html b/js/tests/visual/modal.html index c9a950b8c..6e9f0f710 100644 --- a/js/tests/visual/modal.html +++ b/js/tests/visual/modal.html @@ -1,4 +1,4 @@ -<!DOCTYPE html> +<!doctype html> <html> <head> <meta charset="utf-8"> @@ -167,6 +167,10 @@ <div class="bg-dark text-white p-2" id="tall" style="display: none;"> Tall body content to force the page to have a scrollbar. </div> + + <button type="button" class="btn btn-secondary btn-lg" data-toggle="modal" data-target="<div class="modal fade the-bad" tabindex="-1" role="dialog"><div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button><h4 class="modal-title">The Bad Modal</h4></div><div class="modal-body">This modal's HTTML source code is declared inline, inside the data-target attribute of it's show-button</div></div></div></div>"> + Modal with an XSS inside the data-target + </button> </div> <script src="../../../assets/js/vendor/jquery-slim.min.js"></script> diff --git a/js/tests/visual/popover.html b/js/tests/visual/popover.html index e26dca491..d979d967a 100644 --- a/js/tests/visual/popover.html +++ b/js/tests/visual/popover.html @@ -1,4 +1,4 @@ -<!DOCTYPE html> +<!doctype html> <html> <head> <meta charset="utf-8"> diff --git a/js/tests/visual/scrollspy.html b/js/tests/visual/scrollspy.html index b3d4fb0b1..cfa31ceea 100644 --- a/js/tests/visual/scrollspy.html +++ b/js/tests/visual/scrollspy.html @@ -1,4 +1,4 @@ -<!DOCTYPE html> +<!doctype html> <html> <head> <meta charset="utf-8"> diff --git a/js/tests/visual/tab.html b/js/tests/visual/tab.html index 37730e591..defb577cf 100644 --- a/js/tests/visual/tab.html +++ b/js/tests/visual/tab.html @@ -1,4 +1,4 @@ -<!DOCTYPE html> +<!doctype html> <html> <head> <meta charset="utf-8"> @@ -200,10 +200,10 @@ <div class="row"> <div class="col-4"> <div class="list-group" id="list-tab" role="tablist"> - <a class="list-group-item list-group-item-action active" id="list-home-list" data-toggle="tab" href="#list-home" role="tab" aria-controls="home">Home</a> - <a class="list-group-item list-group-item-action" id="list-profile-list" data-toggle="tab" href="#list-profile" role="tab" aria-controls="profile">Profile</a> - <a class="list-group-item list-group-item-action" id="list-messages-list" data-toggle="tab" href="#list-messages" role="tab" aria-controls="messages">Messages</a> - <a class="list-group-item list-group-item-action" id="list-settings-list" data-toggle="tab" href="#list-settings" role="tab" aria-controls="settings">Settings</a> + <a class="list-group-item list-group-item-action active" id="list-home-list" data-toggle="tab" href="#list-home" role="tab" aria-controls="list-home">Home</a> + <a class="list-group-item list-group-item-action" id="list-profile-list" data-toggle="tab" href="#list-profile" role="tab" aria-controls="list-profile">Profile</a> + <a class="list-group-item list-group-item-action" id="list-messages-list" data-toggle="tab" href="#list-messages" role="tab" aria-controls="list-messages">Messages</a> + <a class="list-group-item list-group-item-action" id="list-settings-list" data-toggle="tab" href="#list-settings" role="tab" aria-controls="list-settings">Settings</a> </div> </div> <div class="col-8"> diff --git a/js/tests/visual/tooltip.html b/js/tests/visual/tooltip.html index fa84a20e4..2d3767830 100644 --- a/js/tests/visual/tooltip.html +++ b/js/tests/visual/tooltip.html @@ -1,4 +1,4 @@ -<!DOCTYPE html> +<!doctype html> <html> <head> <meta charset="utf-8"> |
