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>iron-dropdown basic 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="../iron-dropdown.html"> 23 <link rel="import" href="../../test-fixture/test-fixture.html"> 24 25 </head> 26 <style> 27 body { 28 margin: 0; 29 padding: 0; 30 } 31 32 .container { 33 display: block; 34 position: relative; 35 width: 100px; 36 height: 100px; 37 background-color: yellow; 38 } 39 40 .positioned { 41 position: absolute; 42 top: 40px; 43 left: 40px; 44 } 45 46 .dropdown-content { 47 width: 50px; 48 height: 50px; 49 background-color: orange; 50 } 51 52 .big { 53 width: 3000px; 54 height: 3000px; 55 } 56 </style> 57 <body> 58 59 <test-fixture id="TrivialDropdown"> 60 <template> 61 <iron-dropdown> 62 <div class="dropdown-content"></div> 63 </iron-dropdown> 64 </template> 65 </test-fixture> 66 67 <test-fixture id="NonLockingDropdown"> 68 <template> 69 <iron-dropdown allow-outside-scroll> 70 <div class="dropdown-content">I don't lock scroll!</div> 71 </iron-dropdown> 72 </template> 73 </test-fixture> 74 75 <test-fixture id="AlignedDropdown"> 76 <template> 77 <div class="container"> 78 <iron-dropdown horizontal-align="right" vertical-align="top"> 79 <div class="dropdown-content big"></div> 80 </iron-dropdown> 81 </div> 82 </template> 83 </test-fixture> 84 85 <!-- Absolutely position the dropdown so that it has enough space to move around --> 86 <test-fixture id="OffsetDropdownTopLeft"> 87 <template> 88 <div class="container positioned"> 89 <iron-dropdown> 90 <div class="dropdown-content"></div> 91 </iron-dropdown> 92 </div> 93 </template> 94 </test-fixture> 95 96 <test-fixture id="OffsetDropdownBottomRight"> 97 <template> 98 <div class="container positioned"> 99 <iron-dropdown horizontal-align="right" vertical-align="bottom"> 100 <div class="dropdown-content"></div> 101 </iron-dropdown> 102 </div> 103 </template> 104 </test-fixture> 105 106 <test-fixture id="FocusableContentDropdown"> 107 <template> 108 <iron-dropdown> 109 <div class="dropdown-content" tabindex="0"> 110 <div class="subcontent" tabindex="0"></div> 111 </div> 112 </iron-dropdown> 113 </template> 114 </test-fixture> 115 116 <test-fixture id="RTLDropdownLeft"> 117 <template> 118 <div dir="rtl" class="container"> 119 <iron-dropdown> 120 <div class="dropdown-content"></div> 121 </iron-dropdown> 122 </div> 123 </template> 124 </test-fixture> 125 126 <test-fixture id="RTLDropdownRight"> 127 <template> 128 <div dir="rtl" class="container"> 129 <iron-dropdown horizontal-align="right"> 130 <div class="dropdown-content"></div> 131 </iron-dropdown> 132 </div> 133 </template> 134 </test-fixture> 135 136 <script> 137 function elementIsVisible(element) { 138 var contentRect = element.getBoundingClientRect(); 139 var computedStyle = window.getComputedStyle(element); 140 141 return computedStyle.display !== 'none' && 142 contentRect.width > 0 && 143 contentRect.height > 0; 144 } 145 146 function runAfterOpen(overlay, callback) { 147 overlay.addEventListener('iron-overlay-opened', callback); 148 overlay.open(); 149 } 150 151 suite('<iron-dropdown>', function() { 152 var dropdown; 153 var content; 154 155 suite('basic', function() { 156 setup(function() { 157 dropdown = fixture('TrivialDropdown'); 158 content = Polymer.dom(dropdown).querySelector('.dropdown-content'); 159 }); 160 161 test('effectively hides the dropdown content', function() { 162 expect(elementIsVisible(content)).to.be.equal(false); 163 }); 164 165 test('shows dropdown content when opened', function(done) { 166 runAfterOpen(dropdown, function () { 167 expect(elementIsVisible(content)).to.be.equal(true); 168 done(); 169 }); 170 }); 171 172 test('hides dropdown content when outside is clicked', function(done) { 173 runAfterOpen(dropdown, function () { 174 expect(elementIsVisible(content)).to.be.equal(true); 175 dropdown.addEventListener('iron-overlay-closed', function() { 176 expect(elementIsVisible(content)).to.be.equal(false); 177 done(); 178 }); 179 MockInteractions.tap(dropdown.parentNode); 180 }); 181 }); 182 183 suite('when content is focusable', function() { 184 setup(function() { 185 dropdown = fixture('FocusableContentDropdown'); 186 content = Polymer.dom(dropdown).querySelector('.dropdown-content'); 187 }); 188 test('focuses the content when opened', function(done) { 189 runAfterOpen(dropdown, function () { 190 expect(document.activeElement).to.be.equal(content); 191 done(); 192 }); 193 }); 194 195 test('focuses a configured focus target', function(done) { 196 var focusableChild = Polymer.dom(content).querySelector('div[tabindex]'); 197 dropdown.focusTarget = focusableChild; 198 199 runAfterOpen(dropdown, function () { 200 expect(document.activeElement).to.not.be.equal(content); 201 expect(document.activeElement).to.be.equal(focusableChild); 202 done(); 203 }); 204 }); 205 }); 206 }); 207 208 suite('locking scroll', function() { 209 210 setup(function() { 211 dropdown = fixture('TrivialDropdown'); 212 }); 213 214 test('should lock, only once', function(done) { 215 var openCount = 0; 216 runAfterOpen(dropdown, function() { 217 expect(Polymer.IronDropdownScrollManager._lockingElements.length) 218 .to.be.equal(1); 219 expect(Polymer.IronDropdownScrollManager.elementIsScrollLocked(document.body)) 220 .to.be.equal(true); 221 222 if(openCount === 0) { 223 // This triggers a second `pushScrollLock` with the same element, however 224 // that should not add the element to the `_lockingElements` stack twice 225 dropdown.close(); 226 dropdown.open(); 227 } else { 228 done(); 229 } 230 openCount++; 231 }); 232 }); 233 }); 234 235 suite('non locking scroll', function() { 236 237 setup(function() { 238 dropdown = fixture('NonLockingDropdown'); 239 }); 240 241 test('can be disabled with `allowOutsideScroll`', function(done) { 242 runAfterOpen(dropdown, function() { 243 expect(Polymer.IronDropdownScrollManager.elementIsScrollLocked(document.body)) 244 .to.be.equal(false); 245 done(); 246 }); 247 }); 248 }); 249 250 suite('aligned dropdown', function() { 251 var parent; 252 var parentRect; 253 var dropdownRect; 254 255 setup(function() { 256 parent = fixture('AlignedDropdown'); 257 dropdown = parent.querySelector('iron-dropdown'); 258 }); 259 260 test('can be re-aligned to the right and the top', function(done) { 261 runAfterOpen(dropdown, function () { 262 dropdownRect = dropdown.getBoundingClientRect(); 263 parentRect = parent.getBoundingClientRect(); 264 assert.equal(dropdownRect.top, parentRect.top, 'top ok'); 265 assert.equal(dropdownRect.left, 0, 'left ok'); 266 assert.equal(dropdownRect.bottom, document.documentElement.clientHeight, 'bottom ok'); 267 assert.equal(dropdownRect.right, parentRect.right, 'right ok'); 268 done(); 269 }); 270 }); 271 272 test('can be re-aligned to the bottom', function(done) { 273 dropdown.verticalAlign = 'bottom'; 274 runAfterOpen(dropdown, function () { 275 parentRect = parent.getBoundingClientRect(); 276 dropdownRect = dropdown.getBoundingClientRect(); 277 assert.equal(dropdownRect.top, 0, 'top ok'); 278 assert.equal(dropdownRect.left, 0, 'left ok'); 279 assert.equal(dropdownRect.bottom, parentRect.bottom, 'bottom ok'); 280 assert.equal(dropdownRect.right, parentRect.right, 'right ok'); 281 done(); 282 }); 283 }); 284 285 test('handles parent\'s stacking context', function(done) { 286 // This will create a new stacking context. 287 parent.style.transform = 'translateZ(0)'; 288 runAfterOpen(dropdown, function () { 289 dropdownRect = dropdown.getBoundingClientRect(); 290 parentRect = parent.getBoundingClientRect(); 291 assert.equal(dropdownRect.top, parentRect.top, 'top ok'); 292 assert.equal(dropdownRect.left, 0, 'left ok'); 293 assert.equal(dropdownRect.bottom, document.documentElement.clientHeight, 'bottom ok'); 294 assert.equal(dropdownRect.right, parentRect.right, 'right ok'); 295 done(); 296 }); 297 }); 298 }); 299 300 suite('when align is left/top, with an offset', function() { 301 var dropdownRect; 302 var offsetDropdownRect; 303 setup(function() { 304 var parent = fixture('OffsetDropdownTopLeft'); 305 dropdown = parent.querySelector('iron-dropdown'); 306 }); 307 308 test('can be offset towards the bottom right', function(done) { 309 runAfterOpen(dropdown, function () { 310 dropdownRect = dropdown.getBoundingClientRect(); 311 dropdown.verticalOffset = 10; 312 dropdown.horizontalOffset = 10; 313 // Force refit instead of waiting for requestAnimationFrame. 314 dropdown.refit(); 315 offsetDropdownRect = dropdown.getBoundingClientRect(); 316 // verticalAlign is top, so a positive offset moves down. 317 assert.equal(dropdownRect.top + 10, offsetDropdownRect.top, 'top ok'); 318 // horizontalAlign is left, so a positive offset moves to the right. 319 assert.equal(dropdownRect.left + 10, offsetDropdownRect.left, 'left ok'); 320 done(); 321 }); 322 }); 323 324 test('can be offset towards the top left', function(done) { 325 runAfterOpen(dropdown, function () { 326 dropdownRect = dropdown.getBoundingClientRect(); 327 dropdown.verticalOffset = -10; 328 dropdown.horizontalOffset = -10; 329 // Force refit instead of waiting for requestAnimationFrame. 330 dropdown.refit(); 331 offsetDropdownRect = dropdown.getBoundingClientRect(); 332 // verticalAlign is top, so a negative offset moves up. 333 assert.equal(dropdownRect.top - 10, offsetDropdownRect.top, 'top ok'); 334 // horizontalAlign is left, so a negative offset moves to the left. 335 assert.equal(dropdownRect.left - 10, offsetDropdownRect.left, 'left ok'); 336 done(); 337 }); 338 }); 339 }); 340 341 suite('when align is right/bottom, with an offset', function() { 342 var dropdownRect; 343 var offsetDropdownRect; 344 setup(function() { 345 var parent = fixture('OffsetDropdownBottomRight'); 346 dropdown = parent.querySelector('iron-dropdown'); 347 }); 348 349 test('can be offset towards the top left', function(done) { 350 runAfterOpen(dropdown, function () { 351 dropdownRect = dropdown.getBoundingClientRect(); 352 dropdown.verticalOffset = 10; 353 dropdown.horizontalOffset = 10; 354 // Force refit instead of waiting for requestAnimationFrame. 355 dropdown.refit(); 356 offsetDropdownRect = dropdown.getBoundingClientRect(); 357 // verticalAlign is bottom, so a positive offset moves up. 358 assert.equal(dropdownRect.bottom - 10, offsetDropdownRect.bottom, 'bottom ok'); 359 // horizontalAlign is right, so a positive offset moves to the left. 360 assert.equal(dropdownRect.right - 10, offsetDropdownRect.right, 'right ok'); 361 done(); 362 }); 363 }); 364 365 test('can be offset towards the bottom right', function(done) { 366 runAfterOpen(dropdown, function () { 367 dropdownRect = dropdown.getBoundingClientRect(); 368 dropdown.verticalOffset = -10; 369 dropdown.horizontalOffset = -10; 370 // Force refit instead of waiting for requestAnimationFrame. 371 dropdown.refit(); 372 offsetDropdownRect = dropdown.getBoundingClientRect(); 373 // verticalAlign is bottom, so a negative offset moves down. 374 assert.equal(dropdownRect.bottom + 10, offsetDropdownRect.bottom, 'bottom ok'); 375 // horizontalAlign is right, so a positive offset moves to the right. 376 assert.equal(dropdownRect.right + 10, offsetDropdownRect.right, 'right ok'); 377 done(); 378 }); 379 }); 380 }); 381 382 suite('RTL', function() { 383 var dropdownRect; 384 385 test('with horizontalAlign=left', function(done) { 386 var parent = fixture('RTLDropdownLeft'); 387 dropdown = parent.querySelector('iron-dropdown'); 388 runAfterOpen(dropdown, function () { 389 // In RTL, if `horizontalAlign` is "left", that's the same as 390 // being right-aligned in LTR. So the dropdown should be in the top 391 // right corner. 392 dropdownRect = dropdown.getBoundingClientRect(); 393 expect(dropdownRect.top).to.be.equal(0); 394 expect(dropdownRect.right).to.be.equal(100); 395 done(); 396 }); 397 }); 398 399 test('with horizontalAlign=right', function(done) { 400 var parent = fixture('RTLDropdownRight'); 401 dropdown = parent.querySelector('iron-dropdown'); 402 runAfterOpen(dropdown, function () { 403 // In RTL, if `horizontalAlign` is "right", that's the same as 404 // being left-aligned in LTR. So the dropdown should be in the top 405 // left corner. 406 dropdownRect = dropdown.getBoundingClientRect(); 407 expect(dropdownRect.top).to.be.equal(0); 408 expect(dropdownRect.left).to.be.equal(0); 409 done(); 410 }); 411 }); 412 }); 413 }); 414 </script> 415 </body> 416 </html> 417