1 <!doctype html> 2 <!-- 3 @license 4 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. 5 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt 6 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt 7 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt 8 Code distributed by Google as part of the polymer project is also 9 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt 10 --> 11 <html> 12 <head> 13 <meta charset="UTF-8"> 14 <title>paper-tooltip tests</title> 15 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"> 16 17 <script src="../../webcomponentsjs/webcomponents-lite.js"></script> 18 <script src="../../web-component-tester/browser.js"></script> 19 <script src="../../test-fixture/test-fixture-mocha.js"></script> 20 <script src="../../iron-test-helpers/mock-interactions.js"></script> 21 22 <link rel="import" href="../../test-fixture/test-fixture.html"> 23 <link rel="import" href="../paper-tooltip.html"> 24 <link rel="import" href="test-button.html"> 25 26 </head> 27 <style> 28 body { 29 margin: 0; 30 padding: 0; 31 } 32 #target { 33 width: 100px; 34 height: 20px; 35 background-color: red; 36 } 37 paper-tooltip { 38 width: 70px; 39 height: 30px; 40 } 41 42 .wide { 43 width: 200px; 44 } 45 46 [hidden] { 47 display: none; 48 } 49 </style> 50 51 <body> 52 53 <test-fixture id="basic"> 54 <template> 55 <div> 56 <div id="target"></div> 57 <paper-tooltip for="target" animation-delay="0">Tooltip text</paper-tooltip> 58 </div> 59 </template> 60 </test-fixture> 61 62 <test-fixture id="fitted"> 63 <template> 64 <div> 65 <div id="target" style="position:absolute"></div> 66 <paper-tooltip for="target" class="wide" fit-to-visible-bounds>Tooltip text</paper-tooltip> 67 </div> 68 </template> 69 </test-fixture> 70 71 <test-fixture id="no-text"> 72 <template> 73 <div> 74 <div id="target"></div> 75 <paper-tooltip for="target"></paper-tooltip> 76 </div> 77 </template> 78 </test-fixture> 79 80 <test-fixture id="dynamic"> 81 <template> 82 <div> 83 <div id="target"></div> 84 <paper-tooltip>Tooltip text</paper-tooltip> 85 </div> 86 </template> 87 </test-fixture> 88 89 <test-fixture id="custom"> 90 <template> 91 <test-button></test-button> 92 </template> 93 </test-fixture> 94 95 <test-fixture id="no-offset-parent"> 96 <template> 97 <div> 98 <div id="target"></div> 99 <paper-tooltip for="target" animation-delay="0" hidden></paper-tooltip> 100 </div> 101 </template> 102 </test-fixture> 103 104 <script> 105 function isHidden(element) { 106 var rect = element.getBoundingClientRect(); 107 return (rect.width == 0 && rect.height == 0); 108 } 109 110 suite('basic', function() { 111 test('tooltip is shown when target is focused', function() { 112 var f = fixture('no-text'); 113 var target = f.querySelector('#target'); 114 var tooltip = f.querySelector('paper-tooltip'); 115 116 var actualTooltip = Polymer.dom(tooltip.root).querySelector('#tooltip'); 117 assert.isTrue(isHidden(actualTooltip)); 118 119 MockInteractions.focus(target); 120 assert.isTrue(isHidden(actualTooltip)); 121 }); 122 123 test('tooltip is not shown if empty', function() { 124 var f = fixture('basic'); 125 var target = f.querySelector('#target'); 126 var tooltip = f.querySelector('paper-tooltip'); 127 128 var actualTooltip = Polymer.dom(tooltip.root).querySelector('#tooltip'); 129 assert.isTrue(isHidden(actualTooltip)); 130 131 MockInteractions.focus(target); 132 assert.isFalse(isHidden(actualTooltip)); 133 }); 134 135 test('tooltip doesn\'t throw an exception if it has no offsetParent', function() { 136 var f = fixture('no-offset-parent'); 137 var target = f.querySelector('#target'); 138 var tooltip = f.querySelector('paper-tooltip'); 139 140 var actualTooltip = Polymer.dom(tooltip.root).querySelector('#tooltip'); 141 assert.isTrue(isHidden(actualTooltip)); 142 tooltip.updatePosition(); 143 tooltip.show(); 144 145 // Doesn't get shown since there's no position computed. 146 assert.isTrue(isHidden(actualTooltip)); 147 }); 148 149 test('tooltip is positioned correctly (bottom)', function() { 150 var f = fixture('basic'); 151 var target = f.querySelector('#target'); 152 var tooltip = f.querySelector('paper-tooltip'); 153 154 var actualTooltip = Polymer.dom(tooltip.root).querySelector('#tooltip'); 155 assert.isTrue(isHidden(actualTooltip)); 156 157 MockInteractions.focus(target); 158 assert.isFalse(isHidden(actualTooltip)); 159 160 var divRect = target.getBoundingClientRect(); 161 expect(divRect.width).to.be.equal(100); 162 expect(divRect.height).to.be.equal(20); 163 164 var contentRect = tooltip.getBoundingClientRect(); 165 expect(contentRect.width).to.be.equal(70); 166 expect(contentRect.height).to.be.equal(30); 167 168 // The target div width is 100, and the tooltip width is 70, and 169 // it's centered. The height of the target div is 20, and the 170 // tooltip is 14px below. 171 expect(contentRect.left).to.be.equal((100 - 70)/2); 172 expect(contentRect.top).to.be.equal(20 + 14); 173 174 // Also check the math, just in case. 175 expect(contentRect.left).to.be.equal((divRect.width - contentRect.width)/2); 176 expect(contentRect.top).to.be.equal(divRect.height + tooltip.offset); 177 }); 178 179 test('tooltip is positioned correctly (top)', function() { 180 var f = fixture('basic'); 181 var target = f.querySelector('#target'); 182 var tooltip = f.querySelector('paper-tooltip'); 183 tooltip.position = 'top'; 184 185 var actualTooltip = Polymer.dom(tooltip.root).querySelector('#tooltip'); 186 assert.isTrue(isHidden(actualTooltip)); 187 188 MockInteractions.focus(target); 189 assert.isFalse(isHidden(actualTooltip)); 190 191 var divRect = target.getBoundingClientRect(); 192 expect(divRect.width).to.be.equal(100); 193 expect(divRect.height).to.be.equal(20); 194 195 var contentRect = tooltip.getBoundingClientRect(); 196 expect(contentRect.width).to.be.equal(70); 197 expect(contentRect.height).to.be.equal(30); 198 199 // The target div width is 100, and the tooltip width is 70, and 200 // it's centered. The height of the tooltip is 30, and the 201 // tooltip is 14px above the target. 202 expect(contentRect.left).to.be.equal((100 - 70)/2); 203 expect(contentRect.top).to.be.equal(0 - 30 - 14); 204 205 // Also check the math, just in case. 206 expect(contentRect.left).to.be.equal((divRect.width - contentRect.width)/2); 207 expect(contentRect.top).to.be.equal(0 - contentRect.height - tooltip.offset); 208 }); 209 210 test('tooltip is positioned correctly (right)', function() { 211 var f = fixture('basic'); 212 var target = f.querySelector('#target'); 213 var tooltip = f.querySelector('paper-tooltip'); 214 tooltip.position = 'right'; 215 216 var actualTooltip = Polymer.dom(tooltip.root).querySelector('#tooltip'); 217 assert.isTrue(isHidden(actualTooltip)); 218 219 MockInteractions.focus(target); 220 assert.isFalse(isHidden(actualTooltip)); 221 222 var divRect = target.getBoundingClientRect(); 223 expect(divRect.width).to.be.equal(100); 224 expect(divRect.height).to.be.equal(20); 225 226 var contentRect = tooltip.getBoundingClientRect(); 227 expect(contentRect.width).to.be.equal(70); 228 expect(contentRect.height).to.be.equal(30); 229 230 // The target div width is 100, and the tooltip is 14px to the right. 231 // The target div height is 20, the height of the tooltip is 20px, and 232 // the tooltip is centered. 233 expect(contentRect.left).to.be.equal(100 + 14); 234 expect(contentRect.top).to.be.equal((20 - 30)/2); 235 236 // Also check the math, just in case. 237 expect(contentRect.left).to.be.equal(divRect.width + tooltip.offset); 238 expect(contentRect.top).to.be.equal((divRect.height - contentRect.height)/2); 239 }); 240 241 test('tooltip is positioned correctly (left)', function() { 242 var f = fixture('basic'); 243 var target = f.querySelector('#target'); 244 var tooltip = f.querySelector('paper-tooltip'); 245 tooltip.position = 'left'; 246 247 var actualTooltip = Polymer.dom(tooltip.root).querySelector('#tooltip'); 248 assert.isTrue(isHidden(actualTooltip)); 249 250 MockInteractions.focus(target); 251 assert.isFalse(isHidden(actualTooltip)); 252 253 var divRect = target.getBoundingClientRect(); 254 expect(divRect.width).to.be.equal(100); 255 expect(divRect.height).to.be.equal(20); 256 257 var contentRect = tooltip.getBoundingClientRect(); 258 expect(contentRect.width).to.be.equal(70); 259 expect(contentRect.height).to.be.equal(30); 260 261 // The tooltip width is 70px, and the tooltip is 14px to the left of the target. 262 // The target div height is 20, the height of the tooltip is 20px, and 263 // the tooltip is centered. 264 expect(contentRect.left).to.be.equal(0 - 70 - 14); 265 expect(contentRect.top).to.be.equal((20 - 30)/2); 266 267 // Also check the math, just in case. 268 expect(contentRect.left).to.be.equal(0 - contentRect.width - tooltip.offset); 269 expect(contentRect.top).to.be.equal((divRect.height - contentRect.height)/2); 270 }); 271 272 test('tooltip is fitted correctly if out of bounds', function() { 273 var f = fixture('fitted'); 274 var target = f.querySelector('#target'); 275 var tooltip = f.querySelector('paper-tooltip'); 276 target.style.top = 0; 277 target.style.left = 0; 278 279 var actualTooltip = Polymer.dom(tooltip.root).querySelector('#tooltip'); 280 assert.isTrue(isHidden(actualTooltip)); 281 282 MockInteractions.focus(target); 283 assert.isFalse(isHidden(actualTooltip)); 284 285 var contentRect = tooltip.getBoundingClientRect(); 286 var divRect = target.getBoundingClientRect(); 287 288 // Should be fitted on the left side. 289 expect(contentRect.left).to.be.equal(0); 290 expect(contentRect.top).to.be.equal(divRect.height + tooltip.offset); 291 }); 292 293 test('tooltip is positioned correctly after being dynamically set', function() { 294 var f = fixture('dynamic'); 295 var target = f.querySelector('#target'); 296 var tooltip = f.querySelector('paper-tooltip'); 297 298 var actualTooltip = Polymer.dom(tooltip.root).querySelector('#tooltip'); 299 assert.isTrue(isHidden(actualTooltip)); 300 301 // Skip animations in this test, which means we'll show and hide 302 // the tooltip manually, instead of calling focus and blur. 303 304 // The tooltip is shown because it's a sibling of the target, 305 // but it's positioned incorrectly 306 tooltip.toggleClass('hidden', false, actualTooltip); 307 assert.isFalse(isHidden(actualTooltip)); 308 309 var contentRect = tooltip.getBoundingClientRect(); 310 expect(contentRect.left).to.not.be.equal((100 - 70)/2); 311 312 tooltip.for = 'target'; 313 314 // The tooltip needs to hide before it gets repositioned. 315 tooltip.toggleClass('hidden', true, actualTooltip); 316 tooltip.updatePosition(); 317 tooltip.toggleClass('hidden', false, actualTooltip); 318 assert.isFalse(isHidden(actualTooltip)); 319 320 // The target div width is 100, and the tooltip width is 70, and 321 // it's centered. The height of the target div is 20, and the 322 // tooltip is 14px below. 323 contentRect = tooltip.getBoundingClientRect(); 324 expect(contentRect.left).to.be.equal((100 - 70)/2); 325 expect(contentRect.top).to.be.equal(20 + 14); 326 }); 327 328 test('tooltip is hidden after target is blurred', function(done) { 329 var f = fixture('basic'); 330 var target = f.querySelector('#target'); 331 var tooltip = f.querySelector('paper-tooltip'); 332 333 var actualTooltip = Polymer.dom(tooltip.root).querySelector('#tooltip'); 334 assert.isTrue(isHidden(actualTooltip)); 335 // Simulate but don't actually run the entry animation. 336 tooltip.toggleClass('hidden', false, actualTooltip); 337 tooltip._showing = true; 338 assert.isFalse(isHidden(actualTooltip)); 339 340 tooltip.addEventListener('neon-animation-finish', function() { 341 assert.isTrue(isHidden(actualTooltip)); 342 done(); 343 }); 344 MockInteractions.blur(target); 345 }); 346 347 test('tooltip unlistens to target on detach', function(done) { 348 var f = fixture('basic'); 349 var target = f.querySelector('#target'); 350 var tooltip = f.querySelector('paper-tooltip'); 351 352 sinon.spy(tooltip, 'show'); 353 354 MockInteractions.focus(target); 355 expect(tooltip.show.callCount).to.be.equal(1); 356 357 MockInteractions.focus(target); 358 expect(tooltip.show.callCount).to.be.equal(2); 359 360 f.removeChild(tooltip); 361 362 setTimeout(function() { 363 // No more listener means no more calling show. 364 MockInteractions.focus(target); 365 expect(tooltip.show.callCount).to.be.equal(2); 366 done(); 367 }, 200); 368 }); 369 }); 370 371 suite('tooltip is inside a custom element', function() { 372 var f, tooltip, target; 373 374 setup(function() { 375 f = fixture('custom'); 376 target = f.$.button; 377 tooltip = f.$.buttonTooltip; 378 }); 379 380 test('tooltip is shown when target is focused', function() { 381 var actualTooltip = Polymer.dom(tooltip.root).querySelector('#tooltip'); 382 assert.isTrue(isHidden(actualTooltip)); 383 384 MockInteractions.focus(target); 385 assert.isFalse(isHidden(actualTooltip)); 386 }); 387 388 test('tooltip is positioned correctly', function() { 389 var actualTooltip = Polymer.dom(tooltip.root).querySelector('#tooltip'); 390 assert.isTrue(isHidden(actualTooltip)); 391 392 MockInteractions.focus(target); 393 assert.isFalse(isHidden(actualTooltip)); 394 395 var divRect = target.getBoundingClientRect(); 396 expect(divRect.width).to.be.equal(100); 397 expect(divRect.height).to.be.equal(20); 398 399 var contentRect = tooltip.getBoundingClientRect(); 400 expect(contentRect.width).to.be.equal(70); 401 expect(contentRect.height).to.be.equal(30); 402 403 // The target div width is 100, and the tooltip width is 70, and 404 // it's centered. The height of the target div is 20, and the 405 // tooltip is 14px below. 406 expect(contentRect.left).to.be.equal((100 - 70)/2); 407 expect(contentRect.top).to.be.equal(20 + 14); 408 409 // Also check the math, just in case. 410 expect(contentRect.left).to.be.equal((divRect.width - contentRect.width)/2); 411 expect(contentRect.top).to.be.equal(divRect.height + tooltip.offset); 412 }); 413 }); 414 415 suite('a11y', function() { 416 test('has aria role "tooltip"', function() { 417 var f = fixture('basic'); 418 var tooltip = f.querySelector('paper-tooltip'); 419 420 assert.isTrue(tooltip.getAttribute('role') == 'tooltip'); 421 }); 422 423 var ignoredRules = ['roleTooltipRequiresDescribedby']; 424 425 a11ySuite('basic', ignoredRules); 426 a11ySuite('fitted', ignoredRules); 427 a11ySuite('no-text', ignoredRules); 428 a11ySuite('dynamic', ignoredRules); 429 a11ySuite('custom', ignoredRules); 430 }); 431 </script> 432 </body> 433 </html> 434