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 14 <title>paper-input tests</title> 15 16 <meta charset="utf-8"> 17 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 18 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes"> 19 20 <script src="../../webcomponentsjs/webcomponents-lite.js"></script> 21 22 <script src="../../web-component-tester/browser.js"></script> 23 <script src="../../iron-test-helpers/test-helpers.js"></script> 24 <script src="../../iron-test-helpers/mock-interactions.js"></script> 25 26 <link rel="import" href="../paper-input.html"> 27 <link rel="import" href="letters-only.html"> 28 29 </head> 30 <body> 31 32 <test-fixture id="basic"> 33 <template> 34 <paper-input></paper-input> 35 </template> 36 </test-fixture> 37 38 <test-fixture id="has-tabindex"> 39 <template> 40 <paper-input tabindex="0"></paper-input> 41 </template> 42 </test-fixture> 43 44 <test-fixture id="label"> 45 <template> 46 <paper-input label="foo"></paper-input> 47 </template> 48 </test-fixture> 49 50 <test-fixture id="label-has-value"> 51 <template> 52 <paper-input label="foo" value="bar"></paper-input> 53 </template> 54 </test-fixture> 55 56 <test-fixture id="error"> 57 <template> 58 <paper-input auto-validate pattern="[0-9]*" value="foobar" error-message="error"></paper-input> 59 </template> 60 </test-fixture> 61 62 <test-fixture id="required"> 63 <template> 64 <paper-input auto-validate required error-message="error"></paper-input> 65 </template> 66 </test-fixture> 67 68 <test-fixture id="required-no-auto-validate"> 69 <template> 70 <paper-input required error-message="error"></paper-input> 71 </template> 72 </test-fixture> 73 74 <test-fixture id="required-char-counter"> 75 <template> 76 <paper-input auto-validate char-counter required error-message="error"></paper-input> 77 </template> 78 </test-fixture> 79 80 <test-fixture id="char-counter"> 81 <template> 82 <paper-input char-counter value="foobar"></paper-input> 83 </template> 84 </test-fixture> 85 86 <test-fixture id="type-number-char-counter"> 87 <template> 88 <paper-input type="number" char-counter value="1138"></paper-input> 89 </template> 90 </test-fixture> 91 92 <test-fixture id="always-float-label"> 93 <template> 94 <paper-input always-float-label label="foo"></paper-input> 95 </template> 96 </test-fixture> 97 98 <test-fixture id="placeholder"> 99 <template> 100 <paper-input label="foo" placeholder="bar"></paper-input> 101 </template> 102 </test-fixture> 103 104 <test-fixture id="date"> 105 <template> 106 <paper-input label="foo" type="date"></paper-input> 107 </template> 108 </test-fixture> 109 110 <letters-only></letters-only> 111 112 <test-fixture id="validator"> 113 <template> 114 <paper-input value="123123" validator="letters-only" auto-validate></paper-input> 115 </template> 116 </test-fixture> 117 118 <test-fixture id="multiple-inputs"> 119 <template> 120 <paper-input label="one"></paper-input> 121 <paper-input label="two"></paper-input> 122 <paper-input label="three"></paper-input> 123 <paper-input label="four"></paper-input> 124 </template> 125 </test-fixture> 126 127 <script> 128 129 suite('basic', function() { 130 131 test('setting value sets the input value', function() { 132 var input = fixture('basic'); 133 input.value = 'foobar'; 134 assert.equal(input.inputElement.value, input.value, 'inputElement.value equals input.value'); 135 }); 136 137 test('placeholder does not overlap label', function() { 138 var input = fixture('placeholder'); 139 assert.equal(input.inputElement.placeholder, input.placeholder, 'inputElement.placeholder equals input.placeholder'); 140 assert.equal(input.noLabelFloat, false); 141 var floatingLabel = Polymer.dom(Polymer.dom(input.root).querySelector('paper-input-container').root).querySelector('.label-is-floating'); 142 assert.ok(floatingLabel); 143 }); 144 145 test('special types autofloat the label', function() { 146 var input = fixture('date'); 147 // Browsers that don't support special <input> types like `date` fallback 148 // to `text`, so make sure to only test if type is still preserved after 149 // the element is attached. 150 if (input.inputElement.type === "date") { 151 assert.equal(input.alwaysFloatLabel, true); 152 var floatingLabel = Polymer.dom(Polymer.dom(input.root).querySelector('paper-input-container').root).querySelector('.label-is-floating'); 153 assert.ok(floatingLabel); 154 } 155 }); 156 157 test('always-float-label attribute works without placeholder', function() { 158 var input = fixture('always-float-label'); 159 var container = Polymer.dom(input.root).querySelector('paper-input-container'); 160 var inputContent = Polymer.dom(container.root).querySelector('.input-content'); 161 assert.isTrue(inputContent.classList.contains('label-is-floating'), 'label is floating'); 162 }); 163 164 test('error message is displayed', function() { 165 var input = fixture('error'); 166 forceXIfStamp(input); 167 var error = Polymer.dom(input.root).querySelector('paper-input-error'); 168 assert.ok(error, 'paper-input-error exists'); 169 assert.notEqual(getComputedStyle(error).display, 'none', 'error is not display:none'); 170 }); 171 172 test('empty required input shows error', function() { 173 var input = fixture('required'); 174 forceXIfStamp(input); 175 var error = Polymer.dom(input.root).querySelector('paper-input-error'); 176 assert.ok(error, 'paper-input-error exists'); 177 assert.notEqual(getComputedStyle(error).display, 'none', 'error is not display:none'); 178 }); 179 180 test('character counter is displayed', function() { 181 var input = fixture('char-counter'); 182 forceXIfStamp(input); 183 var counter = Polymer.dom(input.root).querySelector('paper-input-char-counter') 184 assert.ok(counter, 'paper-input-char-counter exists'); 185 assert.equal(counter._charCounterStr, input.value.length, 'character counter shows the value length'); 186 }); 187 188 test('character counter is correct for type=number', function() { 189 var input = fixture('type-number-char-counter'); 190 forceXIfStamp(input); 191 var counter = Polymer.dom(input.root).querySelector('paper-input-char-counter') 192 assert.ok(counter, 'paper-input-char-counter exists'); 193 assert.equal(counter._charCounterStr, input.value.toString().length, 'character counter shows the value length'); 194 }); 195 196 test('validator is used', function() { 197 var input = fixture('validator'); 198 assert.ok(input.inputElement.invalid, 'input is invalid'); 199 }); 200 201 test('caret position is preserved', function() { 202 var input = fixture('basic'); 203 var ironInput = Polymer.dom(input.root).querySelector('input[is="iron-input"]'); 204 input.value = 'nananana'; 205 ironInput.selectionStart = 2; 206 ironInput.selectionEnd = 2; 207 208 input.updateValueAndPreserveCaret('nanananabatman'); 209 210 assert.equal(ironInput.selectionStart, 2, 'selectionStart is preserved'); 211 assert.equal(ironInput.selectionEnd, 2, 'selectionEnd is preserved'); 212 }); 213 214 }); 215 216 suite('focus/blur events', function() { 217 var input; 218 219 setup(function() { 220 input = fixture('basic'); 221 }); 222 223 // At the moment, it is very hard to correctly fire exactly 224 // one focus/blur events on a paper-input. This is because 225 // when a paper-input is focused, it needs to focus 226 // its underlying native input, which will also fire a `blur` 227 // event. 228 test('focus events fired on host element', function() { 229 input.addEventListener('focus', function(event) { 230 assert(input.focused, 'input is focused'); 231 }); 232 MockInteractions.focus(input); 233 }); 234 235 test('focus events fired on host element if nested element is focused', function() { 236 input.addEventListener('focus', function(event) { 237 assert(input.focused, 'input is focused'); 238 }); 239 MockInteractions.focus(input.inputElement); 240 }); 241 242 test('blur events fired on host element', function() { 243 MockInteractions.focus(input); 244 input.addEventListener('blur', function(event) { 245 assert(!input.focused, 'input is blurred'); 246 }); 247 MockInteractions.blur(input); 248 }); 249 250 test('blur events fired on host element nested element is blurred', function() { 251 MockInteractions.focus(input); 252 input.addEventListener('blur', function(event) { 253 assert(!input.focused, 'input is blurred'); 254 }); 255 MockInteractions.blur(input.inputElement); 256 }); 257 258 test('focusing then bluring sets the focused attribute correctly', function() { 259 MockInteractions.focus(input); 260 assert(input.focused, 'input is focused'); 261 MockInteractions.blur(input); 262 assert(!input.focused, 'input is blurred'); 263 MockInteractions.focus(input.inputElement); 264 assert(input.focused, 'input is focused'); 265 MockInteractions.blur(input.inputElement); 266 assert(!input.focused, 'input is blurred'); 267 }); 268 269 test('focusing then bluring with shift-tab removes the focused attribute correctly', function() { 270 MockInteractions.focus(input); 271 assert(input.focused, 'input is focused'); 272 273 // Fake a shift-tab induced blur by forcing the flag. 274 input._shiftTabPressed = true; 275 MockInteractions.blur(input.inputElement); 276 assert(!input.focused, 'input is blurred'); 277 }); 278 }); 279 280 suite('focused styling (integration test)', function() { 281 282 test('underline is colored when input is focused', function(done) { 283 var input = fixture('basic'); 284 var container = Polymer.dom(input.root).querySelector('paper-input-container'); 285 var line = Polymer.dom(container.root).querySelector('.underline'); 286 assert.isFalse(line.classList.contains('is-highlighted'), 'line is not highlighted when input is not focused'); 287 MockInteractions.focus(input.inputElement); 288 requestAnimationFrame(function() { 289 assert.isTrue(line.classList.contains('is-highlighted'), 'line is highlighted when input is focused'); 290 done(); 291 }); 292 }); 293 294 }); 295 296 suite('validation', function() { 297 298 test('invalid attribute updated after calling validate()', function() { 299 var input = fixture('required-no-auto-validate'); 300 forceXIfStamp(input); 301 input.validate(); 302 var error = Polymer.dom(input.root).querySelector('paper-input-error'); 303 assert.ok(error, 'paper-input-error exists'); 304 assert.notEqual(getComputedStyle(error).display, 'none', 'error is not display:none'); 305 assert.isTrue(input.invalid, 'invalid is true'); 306 }); 307 308 }); 309 310 suite('a11y', function() { 311 test('has aria-labelledby, which is monotonically increasing', function() { 312 var inputs = fixture('multiple-inputs'); 313 314 // Find the first index of the input in this fixture. Since the label 315 // ids monotonically increase every time a new input is created, and 316 // this fixture isn't the first one in the document, we're going to start 317 // at an ID > 1. 318 var firstLabel = Polymer.dom(inputs[0].root).querySelector('label').id; 319 var index = parseInt(firstLabel.substr(firstLabel.lastIndexOf('-') + 1)); 320 321 for (var i = 0; i < inputs.length; i++ ) { 322 var input = inputs[i].inputElement; 323 var label = Polymer.dom(inputs[i].root).querySelector('label').id; 324 325 assert.isTrue(input.hasAttribute('aria-labelledby')); 326 assert.equal(label, 'paper-input-label-' + (index++)); 327 assert.equal(input.getAttribute('aria-labelledby'), label); 328 } 329 }); 330 331 test('has aria-describedby for error message', function() { 332 var input = fixture('required'); 333 forceXIfStamp(input); 334 assert.isTrue(input.inputElement.hasAttribute('aria-describedby')); 335 assert.equal(input.inputElement.getAttribute('aria-describedby'), Polymer.dom(input.root).querySelector('paper-input-error').id, 'aria-describedby points to the error message'); 336 }); 337 338 test('has aria-describedby for character counter', function() { 339 var input = fixture('char-counter'); 340 forceXIfStamp(input); 341 assert.isTrue(input.inputElement.hasAttribute('aria-describedby')); 342 assert.equal(input.inputElement.getAttribute('aria-describedby'), Polymer.dom(input.root).querySelector('paper-input-char-counter').id, 'aria-describedby points to the character counter'); 343 }); 344 345 test('has aria-describedby for character counter and error', function() { 346 var input = fixture('required-char-counter'); 347 forceXIfStamp(input); 348 assert.isTrue(input.inputElement.hasAttribute('aria-describedby')); 349 assert.equal(input.inputElement.getAttribute('aria-describedby'), Polymer.dom(input.root).querySelector('paper-input-error').id + ' ' + Polymer.dom(input.root).querySelector('paper-input-char-counter').id, 'aria-describedby points to the error message and character counter'); 350 }); 351 352 test('focus an input with tabindex', function(done) { 353 var input = fixture('has-tabindex'); 354 flush(function() { 355 MockInteractions.focus(input); 356 flush(function() { 357 assert.equal(input.shadowRoot ? input.shadowRoot.activeElement : 358 document.activeElement, input._focusableElement); 359 done(); 360 }); 361 }); 362 }); 363 }); 364 365 </script> 366 367 </body> 368 </html> 369