aboutsummaryrefslogtreecommitdiff
path: root/js/tests
diff options
context:
space:
mode:
authorlucascono <[email protected]>2017-10-04 05:33:17 -0300
committerlucascono <[email protected]>2017-10-04 05:33:17 -0300
commit8c04a74c8c7f0174ea08bc02fa3762f49bf615a3 (patch)
treedb9d6923c082243d765c57885992db8dd26a70b5 /js/tests
parent9aff890efa3798f831b714c41794c9fee0684bae (diff)
parentb29b1e155880ac953899889c9cbb67f7f7df0529 (diff)
downloadbootstrap-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.json4
-rw-r--r--js/tests/index.html2
-rw-r--r--js/tests/unit/alert.js2
-rw-r--r--js/tests/unit/button.js2
-rw-r--r--js/tests/unit/carousel.js86
-rw-r--r--js/tests/unit/collapse.js71
-rw-r--r--js/tests/unit/dropdown.js4
-rw-r--r--js/tests/unit/modal.js128
-rw-r--r--js/tests/unit/popover.js29
-rw-r--r--js/tests/unit/scrollspy.js43
-rw-r--r--js/tests/unit/tab.js77
-rw-r--r--js/tests/unit/tooltip.js28
-rw-r--r--js/tests/visual/alert.html2
-rw-r--r--js/tests/visual/button.html2
-rw-r--r--js/tests/visual/carousel.html8
-rw-r--r--js/tests/visual/collapse.html4
-rw-r--r--js/tests/visual/dropdown.html2
-rw-r--r--js/tests/visual/modal.html6
-rw-r--r--js/tests/visual/popover.html2
-rw-r--r--js/tests/visual/scrollspy.html2
-rw-r--r--js/tests/visual/tab.html10
-rw-r--r--js/tests/visual/tooltip.html2
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">&lsaquo;</a>'
+ + ' <a class="right carousel-control" href="#myCarousel" data-slide="next">&rsaquo;</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">&lsaquo;</a>'
+ + ' <a class="right carousel-control" href="#myCarousel" data-slide="next">&rsaquo;</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="&lt;div id=&quot;modal-test&quot;&gt;&lt;div class=&quot;contents&quot;&lt;div&lt;div id=&quot;close&quot; data-dismiss=&quot;modal&quot;/&gt;&lt;/div&gt;&lt;/div&gt;"/>')
+ .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="&lt;div&gt;&lt;image src=&quot;missing.png&quot; onerror=&quot;$(&apos;#qunit-fixture button.control&apos;).trigger(&apos;click&apos;)&quot;&gt;&lt;/div&gt;"/>')
+ .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="&#x3C;div class=&#x22;modal fade the-bad&#x22; tabindex=&#x22;-1&#x22; role=&#x22;dialog&#x22;&#x3E;&#x3C;div class=&#x22;modal-dialog&#x22; role=&#x22;document&#x22;&#x3E;&#x3C;div class=&#x22;modal-content&#x22;&#x3E;&#x3C;div class=&#x22;modal-header&#x22;&#x3E;&#x3C;button type=&#x22;button&#x22; class=&#x22;close&#x22; data-dismiss=&#x22;modal&#x22; aria-label=&#x22;Close&#x22;&#x3E;&#x3C;span aria-hidden=&#x22;true&#x22;&#x3E;&#x26;times;&#x3C;/span&#x3E;&#x3C;/button&#x3E;&#x3C;h4 class=&#x22;modal-title&#x22;&#x3E;The Bad Modal&#x3C;/h4&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;modal-body&#x22;&#x3E;This modal&#x27;s HTTML source code is declared inline, inside the data-target attribute of it&#x27;s show-button&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;">
+ 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">