tooltip.js 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183
  1. $(function () {
  2. 'use strict';
  3. QUnit.module('tooltip plugin')
  4. QUnit.test('should be defined on jquery object', function (assert) {
  5. assert.expect(1)
  6. assert.ok($(document.body).tooltip, 'tooltip method is defined')
  7. })
  8. QUnit.module('tooltip', {
  9. beforeEach: function () {
  10. // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
  11. $.fn.bootstrapTooltip = $.fn.tooltip.noConflict()
  12. },
  13. afterEach: function () {
  14. $.fn.tooltip = $.fn.bootstrapTooltip
  15. delete $.fn.bootstrapTooltip
  16. }
  17. })
  18. QUnit.test('should provide no conflict', function (assert) {
  19. assert.expect(1)
  20. assert.strictEqual($.fn.tooltip, undefined, 'tooltip was set back to undefined (org value)')
  21. })
  22. QUnit.test('should return jquery collection containing the element', function (assert) {
  23. assert.expect(2)
  24. var $el = $('<div/>')
  25. var $tooltip = $el.bootstrapTooltip()
  26. assert.ok($tooltip instanceof $, 'returns jquery collection')
  27. assert.strictEqual($tooltip[0], $el[0], 'collection contains element')
  28. })
  29. QUnit.test('should expose default settings', function (assert) {
  30. assert.expect(1)
  31. assert.ok($.fn.bootstrapTooltip.Constructor.DEFAULTS, 'defaults is defined')
  32. })
  33. QUnit.test('should empty title attribute', function (assert) {
  34. assert.expect(1)
  35. var $trigger = $('<a href="#" rel="tooltip" title="Another tooltip"/>').bootstrapTooltip()
  36. assert.strictEqual($trigger.attr('title'), '', 'title attribute was emptied')
  37. })
  38. QUnit.test('should add data attribute for referencing original title', function (assert) {
  39. assert.expect(1)
  40. var $trigger = $('<a href="#" rel="tooltip" title="Another tooltip"/>').bootstrapTooltip()
  41. assert.strictEqual($trigger.attr('data-original-title'), 'Another tooltip', 'original title preserved in data attribute')
  42. })
  43. QUnit.test('should add aria-describedby to the trigger on show', function (assert) {
  44. assert.expect(3)
  45. var $trigger = $('<a href="#" rel="tooltip" title="Another tooltip"/>')
  46. .bootstrapTooltip()
  47. .appendTo('#qunit-fixture')
  48. .bootstrapTooltip('show')
  49. var id = $('.tooltip').attr('id')
  50. assert.strictEqual($('#' + id).length, 1, 'has a unique id')
  51. assert.strictEqual($('.tooltip').attr('aria-describedby'), $trigger.attr('id'), 'tooltip id and aria-describedby on trigger match')
  52. assert.ok($trigger[0].hasAttribute('aria-describedby'), 'trigger has aria-describedby')
  53. })
  54. QUnit.test('should remove aria-describedby from trigger on hide', function (assert) {
  55. assert.expect(2)
  56. var $trigger = $('<a href="#" rel="tooltip" title="Another tooltip"/>')
  57. .bootstrapTooltip()
  58. .appendTo('#qunit-fixture')
  59. $trigger.bootstrapTooltip('show')
  60. assert.ok($trigger[0].hasAttribute('aria-describedby'), 'trigger has aria-describedby')
  61. $trigger.bootstrapTooltip('hide')
  62. assert.ok(!$trigger[0].hasAttribute('aria-describedby'), 'trigger does not have aria-describedby')
  63. })
  64. QUnit.test('should assign a unique id tooltip element', function (assert) {
  65. assert.expect(2)
  66. $('<a href="#" rel="tooltip" title="Another tooltip"/>')
  67. .appendTo('#qunit-fixture')
  68. .bootstrapTooltip('show')
  69. var id = $('.tooltip').attr('id')
  70. assert.strictEqual($('#' + id).length, 1, 'tooltip has unique id')
  71. assert.strictEqual(id.indexOf('tooltip'), 0, 'tooltip id has prefix')
  72. })
  73. QUnit.test('should place tooltips relative to placement option', function (assert) {
  74. assert.expect(2)
  75. var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>')
  76. .appendTo('#qunit-fixture')
  77. .bootstrapTooltip({ placement: 'bottom' })
  78. $tooltip.bootstrapTooltip('show')
  79. assert.ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied')
  80. $tooltip.bootstrapTooltip('hide')
  81. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed')
  82. })
  83. QUnit.test('should allow html entities', function (assert) {
  84. assert.expect(2)
  85. var $tooltip = $('<a href="#" rel="tooltip" title="&lt;b&gt;@fat&lt;/b&gt;"/>')
  86. .appendTo('#qunit-fixture')
  87. .bootstrapTooltip({ html: true })
  88. $tooltip.bootstrapTooltip('show')
  89. assert.notEqual($('.tooltip b').length, 0, 'b tag was inserted')
  90. $tooltip.bootstrapTooltip('hide')
  91. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed')
  92. })
  93. QUnit.test('should respect custom classes', function (assert) {
  94. assert.expect(2)
  95. var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>')
  96. .appendTo('#qunit-fixture')
  97. .bootstrapTooltip({ template: '<div class="tooltip some-class"><div class="tooltip-arrow"/><div class="tooltip-inner"/></div>' })
  98. $tooltip.bootstrapTooltip('show')
  99. assert.ok($('.tooltip').hasClass('some-class'), 'custom class is present')
  100. $tooltip.bootstrapTooltip('hide')
  101. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed')
  102. })
  103. QUnit.test('should fire show event', function (assert) {
  104. assert.expect(1)
  105. var done = assert.async()
  106. $('<div title="tooltip title"/>')
  107. .on('show.bs.tooltip', function () {
  108. assert.ok(true, 'show event fired')
  109. done()
  110. })
  111. .bootstrapTooltip('show')
  112. })
  113. QUnit.test('should fire shown event', function (assert) {
  114. assert.expect(1)
  115. var done = assert.async()
  116. $('<div title="tooltip title"></div>')
  117. .appendTo('#qunit-fixture')
  118. .on('shown.bs.tooltip', function () {
  119. assert.ok(true, 'shown was called')
  120. done()
  121. })
  122. .bootstrapTooltip('show')
  123. })
  124. QUnit.test('should not fire shown event when show was prevented', function (assert) {
  125. assert.expect(1)
  126. var done = assert.async()
  127. $('<div title="tooltip title"/>')
  128. .on('show.bs.tooltip', function (e) {
  129. e.preventDefault()
  130. assert.ok(true, 'show event fired')
  131. done()
  132. })
  133. .on('shown.bs.tooltip', function () {
  134. assert.ok(false, 'shown event fired')
  135. })
  136. .bootstrapTooltip('show')
  137. })
  138. QUnit.test('should fire hide event', function (assert) {
  139. assert.expect(1)
  140. var done = assert.async()
  141. $('<div title="tooltip title"/>')
  142. .appendTo('#qunit-fixture')
  143. .on('shown.bs.tooltip', function () {
  144. $(this).bootstrapTooltip('hide')
  145. })
  146. .on('hide.bs.tooltip', function () {
  147. assert.ok(true, 'hide event fired')
  148. done()
  149. })
  150. .bootstrapTooltip('show')
  151. })
  152. QUnit.test('should fire hidden event', function (assert) {
  153. assert.expect(1)
  154. var done = assert.async()
  155. $('<div title="tooltip title"/>')
  156. .appendTo('#qunit-fixture')
  157. .on('shown.bs.tooltip', function () {
  158. $(this).bootstrapTooltip('hide')
  159. })
  160. .on('hidden.bs.tooltip', function () {
  161. assert.ok(true, 'hidden event fired')
  162. done()
  163. })
  164. .bootstrapTooltip('show')
  165. })
  166. QUnit.test('should not fire hidden event when hide was prevented', function (assert) {
  167. assert.expect(1)
  168. var done = assert.async()
  169. $('<div title="tooltip title"/>')
  170. .appendTo('#qunit-fixture')
  171. .on('shown.bs.tooltip', function () {
  172. $(this).bootstrapTooltip('hide')
  173. })
  174. .on('hide.bs.tooltip', function (e) {
  175. e.preventDefault()
  176. assert.ok(true, 'hide event fired')
  177. done()
  178. })
  179. .on('hidden.bs.tooltip', function () {
  180. assert.ok(false, 'hidden event fired')
  181. })
  182. .bootstrapTooltip('show')
  183. })
  184. QUnit.test('should destroy tooltip', function (assert) {
  185. assert.expect(7)
  186. var $tooltip = $('<div/>')
  187. .bootstrapTooltip()
  188. .on('click.foo', function () {})
  189. assert.ok($tooltip.data('bs.tooltip'), 'tooltip has data')
  190. assert.ok($._data($tooltip[0], 'events').mouseover && $._data($tooltip[0], 'events').mouseout, 'tooltip has hover events')
  191. assert.strictEqual($._data($tooltip[0], 'events').click[0].namespace, 'foo', 'tooltip has extra click.foo event')
  192. $tooltip.bootstrapTooltip('show')
  193. $tooltip.bootstrapTooltip('destroy')
  194. assert.ok(!$tooltip.hasClass('in'), 'tooltip is hidden')
  195. assert.ok(!$._data($tooltip[0], 'bs.tooltip'), 'tooltip does not have data')
  196. assert.strictEqual($._data($tooltip[0], 'events').click[0].namespace, 'foo', 'tooltip still has click.foo')
  197. assert.ok(!$._data($tooltip[0], 'events').mouseover && !$._data($tooltip[0], 'events').mouseout, 'tooltip does not have hover events')
  198. })
  199. QUnit.test('should show tooltip with delegate selector on click', function (assert) {
  200. assert.expect(2)
  201. var $div = $('<div><a href="#" rel="tooltip" title="Another tooltip"/></div>')
  202. .appendTo('#qunit-fixture')
  203. .bootstrapTooltip({
  204. selector: 'a[rel="tooltip"]',
  205. trigger: 'click'
  206. })
  207. $div.find('a').trigger('click')
  208. assert.ok($('.tooltip').is('.fade.in'), 'tooltip is faded in')
  209. $div.find('a').trigger('click')
  210. assert.strictEqual($('.tooltip').length, 0, 'tooltip was removed from dom')
  211. })
  212. QUnit.test('should show tooltip when toggle is called', function (assert) {
  213. assert.expect(1)
  214. $('<a href="#" rel="tooltip" title="tooltip on toggle"/>')
  215. .appendTo('#qunit-fixture')
  216. .bootstrapTooltip({ trigger: 'manual' })
  217. .bootstrapTooltip('toggle')
  218. assert.ok($('.tooltip').is('.fade.in'), 'tooltip is faded in')
  219. })
  220. QUnit.test('should hide previously shown tooltip when toggle is called on tooltip', function (assert) {
  221. assert.expect(1)
  222. $('<a href="#" rel="tooltip" title="tooltip on toggle">@ResentedHook</a>')
  223. .appendTo('#qunit-fixture')
  224. .bootstrapTooltip({ trigger: 'manual' })
  225. .bootstrapTooltip('show')
  226. $('.tooltip').bootstrapTooltip('toggle')
  227. assert.ok($('.tooltip').not('.fade.in'), 'tooltip was faded out')
  228. })
  229. QUnit.test('should place tooltips inside body when container is body', function (assert) {
  230. assert.expect(3)
  231. var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>')
  232. .appendTo('#qunit-fixture')
  233. .bootstrapTooltip({ container: 'body' })
  234. .bootstrapTooltip('show')
  235. assert.notEqual($('body > .tooltip').length, 0, 'tooltip is direct descendant of body')
  236. assert.strictEqual($('#qunit-fixture > .tooltip').length, 0, 'tooltip is not in parent')
  237. $tooltip.bootstrapTooltip('hide')
  238. assert.strictEqual($('body > .tooltip').length, 0, 'tooltip was removed from dom')
  239. })
  240. QUnit.test('should add position class before positioning so that position-specific styles are taken into account', function (assert) {
  241. assert.expect(1)
  242. var styles = '<style>'
  243. + '.tooltip.right { white-space: nowrap; }'
  244. + '.tooltip.right .tooltip-inner { max-width: none; }'
  245. + '</style>'
  246. var $styles = $(styles).appendTo('head')
  247. var $container = $('<div/>').appendTo('#qunit-fixture')
  248. var $target = $('<a href="#" rel="tooltip" title="very very very very very very very very long tooltip in one line"/>')
  249. .appendTo($container)
  250. .bootstrapTooltip({
  251. placement: 'right',
  252. viewport: null
  253. })
  254. .bootstrapTooltip('show')
  255. var $tooltip = $container.find('.tooltip')
  256. // this is some dumb hack shit because sub pixels in firefox
  257. var top = Math.round($target.offset().top + ($target[0].offsetHeight / 2) - ($tooltip[0].offsetHeight / 2))
  258. var top2 = Math.round($tooltip.offset().top)
  259. var topDiff = top - top2
  260. assert.ok(topDiff <= 1 && topDiff >= -1)
  261. $target.bootstrapTooltip('hide')
  262. $container.remove()
  263. $styles.remove()
  264. })
  265. QUnit.test('should use title attribute for tooltip text', function (assert) {
  266. assert.expect(2)
  267. var $tooltip = $('<a href="#" rel="tooltip" title="Simple tooltip"/>')
  268. .appendTo('#qunit-fixture')
  269. .bootstrapTooltip()
  270. $tooltip.bootstrapTooltip('show')
  271. assert.strictEqual($('.tooltip').children('.tooltip-inner').text(), 'Simple tooltip', 'title from title attribute is set')
  272. $tooltip.bootstrapTooltip('hide')
  273. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  274. })
  275. QUnit.test('should prefer title attribute over title option', function (assert) {
  276. assert.expect(2)
  277. var $tooltip = $('<a href="#" rel="tooltip" title="Simple tooltip"/>')
  278. .appendTo('#qunit-fixture')
  279. .bootstrapTooltip({
  280. title: 'This is a tooltip with some content'
  281. })
  282. $tooltip.bootstrapTooltip('show')
  283. assert.strictEqual($('.tooltip').children('.tooltip-inner').text(), 'Simple tooltip', 'title is set from title attribute while preferred over title option')
  284. $tooltip.bootstrapTooltip('hide')
  285. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  286. })
  287. QUnit.test('should use title option', function (assert) {
  288. assert.expect(2)
  289. var $tooltip = $('<a href="#" rel="tooltip"/>')
  290. .appendTo('#qunit-fixture')
  291. .bootstrapTooltip({
  292. title: 'This is a tooltip with some content'
  293. })
  294. $tooltip.bootstrapTooltip('show')
  295. assert.strictEqual($('.tooltip').children('.tooltip-inner').text(), 'This is a tooltip with some content', 'title from title option is set')
  296. $tooltip.bootstrapTooltip('hide')
  297. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  298. })
  299. QUnit.test('should be placed dynamically with the dynamic placement option', function (assert) {
  300. assert.expect(6)
  301. var $style = $('<style> a[rel="tooltip"] { display: inline-block; position: absolute; } </style>')
  302. var $container = $('<div/>')
  303. .css({
  304. position: 'absolute',
  305. overflow: 'hidden',
  306. width: 600,
  307. height: 400,
  308. top: 0,
  309. left: 0
  310. })
  311. .appendTo(document.body)
  312. var $topTooltip = $('<div style="left: 0; top: 0;" rel="tooltip" title="Top tooltip">Top Dynamic Tooltip</div>')
  313. .appendTo($container)
  314. .bootstrapTooltip({ placement: 'auto' })
  315. $topTooltip.bootstrapTooltip('show')
  316. assert.ok($('.tooltip').is('.bottom'), 'top positioned tooltip is dynamically positioned to bottom')
  317. $topTooltip.bootstrapTooltip('hide')
  318. assert.strictEqual($('.tooltip').length, 0, 'top positioned tooltip removed from dom')
  319. var $rightTooltip = $('<div style="right: 0;" rel="tooltip" title="Right tooltip">Right Dynamic Tooltip</div>')
  320. .appendTo($container)
  321. .bootstrapTooltip({ placement: 'right auto' })
  322. $rightTooltip.bootstrapTooltip('show')
  323. assert.ok($('.tooltip').is('.left'), 'right positioned tooltip is dynamically positioned left')
  324. $rightTooltip.bootstrapTooltip('hide')
  325. assert.strictEqual($('.tooltip').length, 0, 'right positioned tooltip removed from dom')
  326. var $leftTooltip = $('<div style="left: 0;" rel="tooltip" title="Left tooltip">Left Dynamic Tooltip</div>')
  327. .appendTo($container)
  328. .bootstrapTooltip({ placement: 'auto left' })
  329. $leftTooltip.bootstrapTooltip('show')
  330. assert.ok($('.tooltip').is('.right'), 'left positioned tooltip is dynamically positioned right')
  331. $leftTooltip.bootstrapTooltip('hide')
  332. assert.strictEqual($('.tooltip').length, 0, 'left positioned tooltip removed from dom')
  333. $container.remove()
  334. $style.remove()
  335. })
  336. QUnit.test('should position tip on top if viewport has enough space and placement is "auto top"', function (assert) {
  337. assert.expect(2)
  338. var styles = '<style>'
  339. + 'body { padding-top: 100px; }'
  340. + '#section { height: 300px; border: 1px solid red; padding-top: 50px }'
  341. + 'div[rel="tooltip"] { width: 150px; border: 1px solid blue; }'
  342. + '</style>'
  343. var $styles = $(styles).appendTo('head')
  344. var $container = $('<div id="section"/>').appendTo('#qunit-fixture')
  345. var $target = $('<div rel="tooltip" title="tip"/>')
  346. .appendTo($container)
  347. .bootstrapTooltip({
  348. placement: 'auto top',
  349. viewport: '#section'
  350. })
  351. $target.bootstrapTooltip('show')
  352. assert.ok($('.tooltip').is('.top'), 'top positioned tooltip is dynamically positioned to top')
  353. $target.bootstrapTooltip('hide')
  354. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  355. $styles.remove()
  356. })
  357. QUnit.test('should position tip on bottom if the tip\'s dimension exceeds the viewport area and placement is "auto top"', function (assert) {
  358. assert.expect(2)
  359. var styles = '<style>'
  360. + 'body { padding-top: 100px; }'
  361. + '#section { height: 300px; border: 1px solid red; }'
  362. + 'div[rel="tooltip"] { width: 150px; border: 1px solid blue; }'
  363. + '</style>'
  364. var $styles = $(styles).appendTo('head')
  365. var $container = $('<div id="section"/>').appendTo('#qunit-fixture')
  366. var $target = $('<div rel="tooltip" title="tip"/>')
  367. .appendTo($container)
  368. .bootstrapTooltip({
  369. placement: 'auto top',
  370. viewport: '#section'
  371. })
  372. $target.bootstrapTooltip('show')
  373. assert.ok($('.tooltip').is('.bottom'), 'top positioned tooltip is dynamically positioned to bottom')
  374. $target.bootstrapTooltip('hide')
  375. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  376. $styles.remove()
  377. })
  378. QUnit.test('should display the tip on top whenever scrollable viewport has enough room if the given placement is "auto top"', function (assert) {
  379. assert.expect(2)
  380. var styles = '<style>'
  381. + '#scrollable-div { height: 200px; overflow: auto; }'
  382. + '.tooltip-item { margin: 200px 0 400px; width: 150px; }'
  383. + '</style>'
  384. var $styles = $(styles).appendTo('head')
  385. var $container = $('<div id="scrollable-div"/>').appendTo('#qunit-fixture')
  386. var $target = $('<div rel="tooltip" title="tip" class="tooltip-item">Tooltip Item</div>')
  387. .appendTo($container)
  388. .bootstrapTooltip({
  389. placement: 'top auto',
  390. viewport: '#scrollable-div'
  391. })
  392. $('#scrollable-div').scrollTop(100)
  393. $target.bootstrapTooltip('show')
  394. assert.ok($('.tooltip').is('.fade.top.in'), 'has correct classes applied')
  395. $target.bootstrapTooltip('hide')
  396. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  397. $styles.remove()
  398. })
  399. QUnit.test('should display the tip on bottom whenever scrollable viewport doesn\'t have enough room if the given placement is "auto top"', function (assert) {
  400. assert.expect(2)
  401. var styles = '<style>'
  402. + '#scrollable-div { height: 200px; overflow: auto; }'
  403. + '.tooltip-item { padding: 200px 0 400px; width: 150px; }'
  404. + '</style>'
  405. var $styles = $(styles).appendTo('head')
  406. var $container = $('<div id="scrollable-div"/>').appendTo('#qunit-fixture')
  407. var $target = $('<div rel="tooltip" title="tip" class="tooltip-item">Tooltip Item</div>')
  408. .appendTo($container)
  409. .bootstrapTooltip({
  410. placement: 'top auto',
  411. viewport: '#scrollable-div'
  412. })
  413. $('#scrollable-div').scrollTop(200)
  414. $target.bootstrapTooltip('show')
  415. assert.ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied')
  416. $target.bootstrapTooltip('hide')
  417. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  418. $styles.remove()
  419. })
  420. QUnit.test('should display the tip on bottom whenever scrollable viewport has enough room if the given placement is "auto bottom"', function (assert) {
  421. assert.expect(2)
  422. var styles = '<style>'
  423. + '#scrollable-div { height: 200px; overflow: auto; }'
  424. + '.spacer { height: 400px; }'
  425. + '.spacer:first-child { height: 200px; }'
  426. + '.tooltip-item { width: 150px; }'
  427. + '</style>'
  428. var $styles = $(styles).appendTo('head')
  429. var $container = $('<div id="scrollable-div"/>').appendTo('#qunit-fixture')
  430. var $target = $('<div rel="tooltip" title="tip" class="tooltip-item">Tooltip Item</div>')
  431. .appendTo($container)
  432. .before('<div class="spacer"/>')
  433. .after('<div class="spacer"/>')
  434. .bootstrapTooltip({
  435. placement: 'bottom auto',
  436. viewport: '#scrollable-div'
  437. })
  438. $('#scrollable-div').scrollTop(200)
  439. $target.bootstrapTooltip('show')
  440. assert.ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied')
  441. $target.bootstrapTooltip('hide')
  442. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  443. $styles.remove()
  444. })
  445. QUnit.test('should display the tip on top whenever scrollable viewport doesn\'t have enough room if the given placement is "auto bottom"', function (assert) {
  446. assert.expect(2)
  447. var styles = '<style>'
  448. + '#scrollable-div { height: 200px; overflow: auto; }'
  449. + '.tooltip-item { margin-top: 400px; width: 150px; }'
  450. + '</style>'
  451. var $styles = $(styles).appendTo('head')
  452. var $container = $('<div id="scrollable-div"/>').appendTo('#qunit-fixture')
  453. var $target = $('<div rel="tooltip" title="tip" class="tooltip-item">Tooltip Item</div>')
  454. .appendTo($container)
  455. .bootstrapTooltip({
  456. placement: 'bottom auto',
  457. viewport: '#scrollable-div'
  458. })
  459. $('#scrollable-div').scrollTop(400)
  460. $target.bootstrapTooltip('show')
  461. assert.ok($('.tooltip').is('.fade.top.in'), 'has correct classes applied')
  462. $target.bootstrapTooltip('hide')
  463. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  464. $styles.remove()
  465. })
  466. QUnit.test('should adjust the tip\'s top position when up against the top of the viewport', function (assert) {
  467. assert.expect(2)
  468. var styles = '<style>'
  469. + '.tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; }'
  470. + 'a[rel="tooltip"] { position: fixed; }'
  471. + '</style>'
  472. var $styles = $(styles).appendTo('head')
  473. var $container = $('<div/>').appendTo('#qunit-fixture')
  474. var $target = $('<a href="#" rel="tooltip" title="tip" style="top: 0px; left: 0px;"/>')
  475. .appendTo($container)
  476. .bootstrapTooltip({
  477. placement: 'right',
  478. viewport: {
  479. selector: 'body',
  480. padding: 12
  481. }
  482. })
  483. $target.bootstrapTooltip('show')
  484. assert.strictEqual(Math.round($container.find('.tooltip').offset().top), 12)
  485. $target.bootstrapTooltip('hide')
  486. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  487. $styles.remove()
  488. })
  489. QUnit.test('should adjust the tip\'s top position when up against the bottom of the viewport', function (assert) {
  490. assert.expect(2)
  491. var styles = '<style>'
  492. + '.tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; }'
  493. + 'a[rel="tooltip"] { position: fixed; }'
  494. + '</style>'
  495. var $styles = $(styles).appendTo('head')
  496. var $container = $('<div/>').appendTo('#qunit-fixture')
  497. var $target = $('<a href="#" rel="tooltip" title="tip" style="bottom: 0px; left: 0px;"/>')
  498. .appendTo($container)
  499. .bootstrapTooltip({
  500. placement: 'right',
  501. viewport: {
  502. selector: 'body',
  503. padding: 12
  504. }
  505. })
  506. $target.bootstrapTooltip('show')
  507. var $tooltip = $container.find('.tooltip')
  508. assert.strictEqual(Math.round($tooltip.offset().top), Math.round($(window).height() - 12 - $tooltip[0].offsetHeight))
  509. $target.bootstrapTooltip('hide')
  510. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  511. $container.remove()
  512. $styles.remove()
  513. })
  514. QUnit.test('should adjust the tip\'s left position when up against the left of the viewport', function (assert) {
  515. assert.expect(2)
  516. var styles = '<style>'
  517. + '.tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; }'
  518. + 'a[rel="tooltip"] { position: fixed; }'
  519. + '</style>'
  520. var $styles = $(styles).appendTo('head')
  521. var $container = $('<div/>').appendTo('#qunit-fixture')
  522. var $target = $('<a href="#" rel="tooltip" title="tip" style="top: 0px; left: 0px;"/>')
  523. .appendTo($container)
  524. .bootstrapTooltip({
  525. placement: 'bottom',
  526. viewport: {
  527. selector: 'body',
  528. padding: 12
  529. }
  530. })
  531. $target.bootstrapTooltip('show')
  532. assert.strictEqual(Math.round($container.find('.tooltip').offset().left), 12)
  533. $target.bootstrapTooltip('hide')
  534. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  535. $container.remove()
  536. $styles.remove()
  537. })
  538. QUnit.test('should adjust the tip\'s left position when up against the right of the viewport', function (assert) {
  539. assert.expect(2)
  540. var styles = '<style>'
  541. + '.tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; }'
  542. + 'a[rel="tooltip"] { position: fixed; }'
  543. + '</style>'
  544. var $styles = $(styles).appendTo('head')
  545. var $container = $('<div/>').appendTo('body')
  546. var $target = $('<a href="#" rel="tooltip" title="tip" style="top: 0px; right: 0px;"/>')
  547. .appendTo($container)
  548. .bootstrapTooltip({
  549. placement: 'bottom',
  550. viewport: {
  551. selector: 'body',
  552. padding: 12
  553. }
  554. })
  555. $target.bootstrapTooltip('show')
  556. var $tooltip = $container.find('.tooltip')
  557. assert.strictEqual(Math.round($tooltip.offset().left), Math.round($(window).width() - 12 - $tooltip[0].offsetWidth))
  558. $target.bootstrapTooltip('hide')
  559. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  560. $container.remove()
  561. $styles.remove()
  562. })
  563. QUnit.test('should adjust the tip when up against the right of an arbitrary viewport', function (assert) {
  564. assert.expect(2)
  565. var styles = '<style>'
  566. + '.tooltip, .tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; }'
  567. + '.container-viewport { position: absolute; top: 50px; left: 60px; width: 300px; height: 300px; }'
  568. + 'a[rel="tooltip"] { position: fixed; }'
  569. + '</style>'
  570. var $styles = $(styles).appendTo('head')
  571. var $container = $('<div class="container-viewport"/>').appendTo(document.body)
  572. var $target = $('<a href="#" rel="tooltip" title="tip" style="top: 50px; left: 350px;"/>')
  573. .appendTo($container)
  574. .bootstrapTooltip({
  575. placement: 'bottom',
  576. viewport: '.container-viewport'
  577. })
  578. $target.bootstrapTooltip('show')
  579. var $tooltip = $container.find('.tooltip')
  580. assert.strictEqual(Math.round($tooltip.offset().left), Math.round(60 + $container.width() - $tooltip[0].offsetWidth))
  581. $target.bootstrapTooltip('hide')
  582. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  583. $container.remove()
  584. $styles.remove()
  585. })
  586. QUnit.test('should not error when trying to show an auto-placed tooltip that has been removed from the dom', function (assert) {
  587. assert.expect(1)
  588. var passed = true
  589. var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>')
  590. .appendTo('#qunit-fixture')
  591. .one('show.bs.tooltip', function () {
  592. $(this).remove()
  593. })
  594. .bootstrapTooltip({ placement: 'auto' })
  595. try {
  596. $tooltip.bootstrapTooltip('show')
  597. } catch (err) {
  598. passed = false
  599. console.log(err)
  600. }
  601. assert.ok(passed, '.tooltip(\'show\') should not throw an error if element no longer is in dom')
  602. })
  603. QUnit.test('should place tooltip on top of element', function (assert) {
  604. assert.expect(1)
  605. var done = assert.async()
  606. var containerHTML = '<div>'
  607. + '<p style="margin-top: 200px">'
  608. + '<a href="#" title="very very very very very very very long tooltip">Hover me</a>'
  609. + '</p>'
  610. + '</div>'
  611. var $container = $(containerHTML)
  612. .css({
  613. position: 'absolute',
  614. bottom: 0,
  615. left: 0,
  616. textAlign: 'right',
  617. width: 300,
  618. height: 300
  619. })
  620. .appendTo('#qunit-fixture')
  621. var $trigger = $container
  622. .find('a')
  623. .css('margin-top', 200)
  624. .bootstrapTooltip({
  625. placement: 'top',
  626. animate: false
  627. })
  628. .bootstrapTooltip('show')
  629. var $tooltip = $container.find('.tooltip')
  630. setTimeout(function () {
  631. assert.ok(Math.round($tooltip.offset().top + $tooltip.outerHeight()) <= Math.round($trigger.offset().top))
  632. done()
  633. }, 0)
  634. })
  635. QUnit.test('should place tooltip inside viewport', function (assert) {
  636. assert.expect(1)
  637. var done = assert.async()
  638. var $container = $('<div/>')
  639. .css({
  640. position: 'absolute',
  641. width: 200,
  642. height: 200,
  643. bottom: 0,
  644. left: 0
  645. })
  646. .appendTo('#qunit-fixture')
  647. $('<a href="#" title="Very very very very very very very very long tooltip">Hover me</a>')
  648. .css({
  649. position: 'absolute',
  650. top: 0,
  651. left: 0
  652. })
  653. .appendTo($container)
  654. .bootstrapTooltip({
  655. placement: 'top'
  656. })
  657. .bootstrapTooltip('show')
  658. setTimeout(function () {
  659. assert.ok($('.tooltip').offset().left >= 0)
  660. done()
  661. }, 0)
  662. })
  663. QUnit.test('should show tooltip if leave event hasn\'t occurred before delay expires', function (assert) {
  664. assert.expect(2)
  665. var done = assert.async()
  666. var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>')
  667. .appendTo('#qunit-fixture')
  668. .bootstrapTooltip({ delay: 150 })
  669. setTimeout(function () {
  670. assert.ok(!$('.tooltip').is('.fade.in'), '100ms: tooltip is not faded in')
  671. }, 100)
  672. setTimeout(function () {
  673. assert.ok($('.tooltip').is('.fade.in'), '200ms: tooltip is faded in')
  674. done()
  675. }, 200)
  676. $tooltip.trigger('mouseenter')
  677. })
  678. QUnit.test('should not show tooltip if leave event occurs before delay expires', function (assert) {
  679. assert.expect(2)
  680. var done = assert.async()
  681. var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>')
  682. .appendTo('#qunit-fixture')
  683. .bootstrapTooltip({ delay: 150 })
  684. setTimeout(function () {
  685. assert.ok(!$('.tooltip').is('.fade.in'), '100ms: tooltip not faded in')
  686. $tooltip.trigger('mouseout')
  687. }, 100)
  688. setTimeout(function () {
  689. assert.ok(!$('.tooltip').is('.fade.in'), '200ms: tooltip not faded in')
  690. done()
  691. }, 200)
  692. $tooltip.trigger('mouseenter')
  693. })
  694. QUnit.test('should not hide tooltip if leave event occurs and enter event occurs within the hide delay', function (assert) {
  695. assert.expect(3)
  696. var done = assert.async()
  697. var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>')
  698. .appendTo('#qunit-fixture')
  699. .bootstrapTooltip({ delay: { show: 0, hide: 150 }})
  700. setTimeout(function () {
  701. assert.ok($('.tooltip').is('.fade.in'), '1ms: tooltip faded in')
  702. $tooltip.trigger('mouseout')
  703. setTimeout(function () {
  704. assert.ok($('.tooltip').is('.fade.in'), '100ms: tooltip still faded in')
  705. $tooltip.trigger('mouseenter')
  706. }, 100)
  707. setTimeout(function () {
  708. assert.ok($('.tooltip').is('.fade.in'), '200ms: tooltip still faded in')
  709. done()
  710. }, 200)
  711. }, 0)
  712. $tooltip.trigger('mouseenter')
  713. })
  714. QUnit.test('should not show tooltip if leave event occurs before delay expires', function (assert) {
  715. assert.expect(2)
  716. var done = assert.async()
  717. var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>')
  718. .appendTo('#qunit-fixture')
  719. .bootstrapTooltip({ delay: 150 })
  720. setTimeout(function () {
  721. assert.ok(!$('.tooltip').is('.fade.in'), '100ms: tooltip not faded in')
  722. $tooltip.trigger('mouseout')
  723. }, 100)
  724. setTimeout(function () {
  725. assert.ok(!$('.tooltip').is('.fade.in'), '200ms: tooltip not faded in')
  726. done()
  727. }, 200)
  728. $tooltip.trigger('mouseenter')
  729. })
  730. QUnit.test('should not show tooltip if leave event occurs before delay expires, even if hide delay is 0', function (assert) {
  731. assert.expect(2)
  732. var done = assert.async()
  733. var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>')
  734. .appendTo('#qunit-fixture')
  735. .bootstrapTooltip({ delay: { show: 150, hide: 0 }})
  736. setTimeout(function () {
  737. assert.ok(!$('.tooltip').is('.fade.in'), '100ms: tooltip not faded in')
  738. $tooltip.trigger('mouseout')
  739. }, 100)
  740. setTimeout(function () {
  741. assert.ok(!$('.tooltip').is('.fade.in'), '250ms: tooltip not faded in')
  742. done()
  743. }, 250)
  744. $tooltip.trigger('mouseenter')
  745. })
  746. QUnit.test('should wait 200ms before hiding the tooltip', function (assert) {
  747. assert.expect(3)
  748. var done = assert.async()
  749. var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>')
  750. .appendTo('#qunit-fixture')
  751. .bootstrapTooltip({ delay: { show: 0, hide: 150 }})
  752. setTimeout(function () {
  753. assert.ok($tooltip.data('bs.tooltip').$tip.is('.fade.in'), '1ms: tooltip faded in')
  754. $tooltip.trigger('mouseout')
  755. setTimeout(function () {
  756. assert.ok($tooltip.data('bs.tooltip').$tip.is('.fade.in'), '100ms: tooltip still faded in')
  757. }, 100)
  758. setTimeout(function () {
  759. assert.ok(!$tooltip.data('bs.tooltip').$tip.is('.in'), '200ms: tooltip removed')
  760. done()
  761. }, 200)
  762. }, 0)
  763. $tooltip.trigger('mouseenter')
  764. })
  765. QUnit.test('should correctly position tooltips on SVG elements', function (assert) {
  766. if (!window.SVGElement) {
  767. // Skip IE8 since it doesn't support SVG
  768. assert.expect(0)
  769. return
  770. }
  771. assert.expect(2)
  772. var done = assert.async()
  773. var styles = '<style>'
  774. + '.tooltip, .tooltip *, .tooltip *:before, .tooltip *:after { box-sizing: border-box; }'
  775. + '.tooltip { position: absolute; }'
  776. + '.tooltip .tooltip-inner { width: 24px; height: 24px; font-family: Helvetica; }'
  777. + '</style>'
  778. var $styles = $(styles).appendTo('head')
  779. $('#qunit-fixture').append(
  780. '<div style="position: fixed; top: 0; left: 0;">'
  781. + ' <svg width="200" height="200">'
  782. + ' <circle cx="100" cy="100" r="10" title="m" id="theCircle" />'
  783. + ' </svg>'
  784. + '</div>')
  785. var $circle = $('#theCircle')
  786. $circle
  787. .on('shown.bs.tooltip', function () {
  788. var offset = $('.tooltip').offset()
  789. $styles.remove()
  790. assert.ok(Math.abs(offset.left - 88) <= 1, 'tooltip has correct horizontal location')
  791. $circle.bootstrapTooltip('hide')
  792. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  793. done()
  794. })
  795. .bootstrapTooltip({ container: 'body', placement: 'top', trigger: 'manual' })
  796. $circle.bootstrapTooltip('show')
  797. })
  798. QUnit.test('should correctly determine auto placement based on container rather than parent', function (assert) {
  799. assert.expect(2)
  800. var done = assert.async()
  801. var styles = '<style>'
  802. + '.tooltip, .tooltip *, .tooltip *:before, .tooltip *:after { box-sizing: border-box; }'
  803. + '.tooltip { position: absolute; display: block; font-size: 12px; line-height: 1.4; }'
  804. + '.tooltip .tooltip-inner { max-width: 200px; padding: 3px 8px; font-family: Helvetica; text-align: center; }'
  805. + '#trigger-parent {'
  806. + ' position: fixed;'
  807. + ' top: 100px;'
  808. + ' right: 17px;'
  809. + '}'
  810. + '</style>'
  811. var $styles = $(styles).appendTo('head')
  812. $('#qunit-fixture').append('<span id="trigger-parent"><a id="tt-trigger" title="If a_larger_text is written here, it won\'t fit using older broken version of BS">HOVER OVER ME</a></span>')
  813. var $trigger = $('#tt-trigger')
  814. $trigger
  815. .on('shown.bs.tooltip', function () {
  816. var $tip = $('.tooltip-inner')
  817. var tipXrightEdge = $tip.offset().left + $tip.width()
  818. var triggerXleftEdge = $trigger.offset().left
  819. assert.ok(tipXrightEdge < triggerXleftEdge, 'tooltip with auto left placement, when near the right edge of the viewport, gets left placement')
  820. $trigger.bootstrapTooltip('hide')
  821. })
  822. .on('hidden.bs.tooltip', function () {
  823. $styles.remove()
  824. $(this).remove()
  825. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  826. done()
  827. })
  828. .bootstrapTooltip({
  829. container: 'body',
  830. placement: 'auto left',
  831. trigger: 'manual'
  832. })
  833. $trigger.bootstrapTooltip('show')
  834. })
  835. QUnit.test('should not reload the tooltip on subsequent mouseenter events', function (assert) {
  836. assert.expect(1)
  837. var titleHtml = function () {
  838. var uid = $.fn.bootstrapTooltip.Constructor.prototype.getUID('tooltip')
  839. return '<p id="tt-content">' + uid + '</p><p>' + uid + '</p><p>' + uid + '</p>'
  840. }
  841. var $tooltip = $('<span id="tt-outer" rel="tooltip" data-trigger="hover" data-placement="top">some text</span>')
  842. .appendTo('#qunit-fixture')
  843. $tooltip.bootstrapTooltip({
  844. html: true,
  845. animation: false,
  846. trigger: 'hover',
  847. delay: { show: 0, hide: 500 },
  848. container: $tooltip,
  849. title: titleHtml
  850. })
  851. $('#tt-outer').trigger('mouseenter')
  852. var currentUid = $('#tt-content').text()
  853. $('#tt-content').trigger('mouseenter')
  854. assert.strictEqual(currentUid, $('#tt-content').text())
  855. })
  856. QUnit.test('should not reload the tooltip if the mouse leaves and re-enters before hiding', function (assert) {
  857. assert.expect(4)
  858. var titleHtml = function () {
  859. var uid = $.fn.bootstrapTooltip.Constructor.prototype.getUID('tooltip')
  860. return '<p id="tt-content">' + uid + '</p><p>' + uid + '</p><p>' + uid + '</p>'
  861. }
  862. var $tooltip = $('<span id="tt-outer" rel="tooltip" data-trigger="hover" data-placement="top">some text</span>')
  863. .appendTo('#qunit-fixture')
  864. $tooltip.bootstrapTooltip({
  865. html: true,
  866. animation: false,
  867. trigger: 'hover',
  868. delay: { show: 0, hide: 500 },
  869. container: $tooltip,
  870. title: titleHtml
  871. })
  872. var obj = $tooltip.data('bs.tooltip')
  873. $('#tt-outer').trigger('mouseenter')
  874. var currentUid = $('#tt-content').text()
  875. $('#tt-outer').trigger('mouseleave')
  876. assert.strictEqual(currentUid, $('#tt-content').text())
  877. assert.ok(obj.hoverState == 'out', 'the tooltip hoverState should be set to "out"')
  878. $('#tt-content').trigger('mouseenter')
  879. assert.ok(obj.hoverState == 'in', 'the tooltip hoverState should be set to "in"')
  880. assert.strictEqual(currentUid, $('#tt-content').text())
  881. })
  882. QUnit.test('should position arrow correctly when tooltip is moved to not appear offscreen', function (assert) {
  883. assert.expect(2)
  884. var done = assert.async()
  885. var styles = '<style>'
  886. + '.tooltip, .tooltip *, .tooltip *:before, .tooltip *:after { box-sizing: border-box; }'
  887. + '.tooltip { position: absolute; }'
  888. + '.tooltip-arrow { position: absolute; width: 0; height: 0; }'
  889. + '.tooltip .tooltip-inner { max-width: 200px; padding: 3px 8px; }'
  890. + '</style>'
  891. var $styles = $(styles).appendTo('head')
  892. $('<a href="#" title="tooltip title" style="position: absolute; bottom: 0; right: 0;">Foobar</a>')
  893. .appendTo('body')
  894. .on('shown.bs.tooltip', function () {
  895. var arrowStyles = $(this).data('bs.tooltip').$tip.find('.tooltip-arrow').attr('style')
  896. assert.ok(/left/i.test(arrowStyles) && !/top/i.test(arrowStyles), 'arrow positioned correctly')
  897. $(this).bootstrapTooltip('hide')
  898. })
  899. .on('hidden.bs.tooltip', function () {
  900. $styles.remove()
  901. $(this).remove()
  902. assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
  903. done()
  904. })
  905. .bootstrapTooltip({
  906. container: 'body',
  907. placement: 'top',
  908. trigger: 'manual'
  909. })
  910. .bootstrapTooltip('show')
  911. })
  912. QUnit.test('should correctly position tooltips on transformed elements', function (assert) {
  913. var styleProps = document.documentElement.style
  914. if (!('transform' in styleProps) && !('webkitTransform' in styleProps) && !('msTransform' in styleProps)) {
  915. assert.expect(0)
  916. return
  917. }
  918. assert.expect(2)
  919. var done = assert.async()
  920. var styles = '<style>'
  921. + '#qunit-fixture { top: 0; left: 0; }'
  922. + '.tooltip, .tooltip *, .tooltip *:before, .tooltip *:after { box-sizing: border-box; }'
  923. + '.tooltip { position: absolute; }'
  924. + '.tooltip .tooltip-inner { width: 24px; height: 24px; font-family: Helvetica; }'
  925. + '#target { position: absolute; top: 100px; left: 50px; width: 100px; height: 200px; -webkit-transform: rotate(270deg); -ms-transform: rotate(270deg); transform: rotate(270deg); }'
  926. + '</style>'
  927. var $styles = $(styles).appendTo('head')
  928. var $element = $('<div id="target" title="1"/>').appendTo('#qunit-fixture')
  929. $element
  930. .on('shown.bs.tooltip', function () {
  931. var offset = $('.tooltip').offset()
  932. $styles.remove()
  933. assert.ok(Math.abs(offset.left - 88) <= 1, 'tooltip has correct horizontal location')
  934. assert.ok(Math.abs(offset.top - 126) <= 1, 'tooltip has correct vertical location')
  935. $element.bootstrapTooltip('hide')
  936. done()
  937. })
  938. .bootstrapTooltip({
  939. container: 'body',
  940. placement: 'top',
  941. trigger: 'manual'
  942. })
  943. $element.bootstrapTooltip('show')
  944. })
  945. QUnit.test('should throw an error when initializing tooltip on the document object without specifying a delegation selector', function (assert) {
  946. assert.expect(1)
  947. assert.throws(function () {
  948. $(document).bootstrapTooltip({ title: 'What am I on?' })
  949. }, new Error('`selector` option must be specified when initializing tooltip on the window.document object!'))
  950. })
  951. QUnit.test('should do nothing when an attempt is made to hide an uninitialized tooltip', function (assert) {
  952. assert.expect(1)
  953. var $tooltip = $('<span data-toggle="tooltip" title="some tip">some text</span>')
  954. .appendTo('#qunit-fixture')
  955. .on('hidden.bs.tooltip shown.bs.tooltip', function () {
  956. assert.ok(false, 'should not fire any tooltip events')
  957. })
  958. .bootstrapTooltip('hide')
  959. assert.strictEqual($tooltip.data('bs.tooltip'), undefined, 'should not initialize the tooltip')
  960. })
  961. })