• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!doctype html>
2<!--
3@license
4Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
5This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
6The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
7The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
8Code distributed by Google as part of the polymer project is also
9subject 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('label does not receive pointer events', function() {
165        var input = fixture('always-float-label');
166        var label = Polymer.dom(input.root).querySelector('label');
167        assert.equal(getComputedStyle(label).pointerEvents, 'none');
168      });
169
170      test('error message is displayed', function() {
171        var input = fixture('error');
172        forceXIfStamp(input);
173        var error = Polymer.dom(input.root).querySelector('paper-input-error');
174        assert.ok(error, 'paper-input-error exists');
175        assert.notEqual(getComputedStyle(error).display, 'none', 'error is not display:none');
176      });
177
178      test('empty required input shows error', function() {
179        var input = fixture('required');
180        forceXIfStamp(input);
181        var error = Polymer.dom(input.root).querySelector('paper-input-error');
182        assert.ok(error, 'paper-input-error exists');
183        assert.notEqual(getComputedStyle(error).display, 'none', 'error is not display:none');
184      });
185
186      test('character counter is displayed', function() {
187        var input = fixture('char-counter');
188        forceXIfStamp(input);
189        var counter = Polymer.dom(input.root).querySelector('paper-input-char-counter')
190        assert.ok(counter, 'paper-input-char-counter exists');
191        assert.equal(counter._charCounterStr, input.value.length, 'character counter shows the value length');
192      });
193
194      test('character counter is correct for type=number', function() {
195        var input = fixture('type-number-char-counter');
196        forceXIfStamp(input);
197        var counter = Polymer.dom(input.root).querySelector('paper-input-char-counter')
198        assert.ok(counter, 'paper-input-char-counter exists');
199        assert.equal(counter._charCounterStr, input.value.toString().length, 'character counter shows the value length');
200      });
201
202      test('validator is used', function() {
203        var input = fixture('validator');
204        assert.ok(input.inputElement.invalid, 'input is invalid');
205      });
206
207      test('caret position is preserved', function() {
208        var input = fixture('basic');
209        var ironInput = Polymer.dom(input.root).querySelector('input[is="iron-input"]');
210        input.value = 'nananana';
211        ironInput.selectionStart = 2;
212        ironInput.selectionEnd = 2;
213
214        input.updateValueAndPreserveCaret('nanananabatman');
215
216        assert.equal(ironInput.selectionStart, 2, 'selectionStart is preserved');
217        assert.equal(ironInput.selectionEnd, 2, 'selectionEnd is preserved');
218      });
219
220      test('setting autofocus to true implictly acquires focus', function(done) {
221        var input = fixture('basic');
222        var inputFocusSpy = sinon.spy(input.inputElement, 'focus');
223        window.setTimeout(function() {
224          assert(inputFocusSpy.called);
225          done();
226        }, 50);
227        input.autofocus = true;
228      });
229
230      test('autofocus doesn\'t grab focus if another element already has it', function(done) {
231        var inputs = fixture('multiple-inputs');
232        var inputFocusSpies = inputs.map(function(input) {
233          return sinon.spy(input.inputElement, 'focus');
234        });
235        window.setTimeout(function() {
236          assert(inputFocusSpies[0].called, 'first autofocus input with grabbed focus');
237          assert(!inputFocusSpies[1].called, 'second autofocus input let first input keep focus');
238          done();
239        }, 50);
240        inputs[0].autofocus = true;
241        inputs[1].autofocus = true; // Shouldn't cause focus to change
242      });
243
244    });
245
246    suite('focus/blur events', function() {
247      var input;
248
249      setup(function() {
250        input = fixture('basic');
251      });
252
253      // At the moment, it is very hard to correctly fire exactly
254      // one focus/blur events on a paper-input. This is because
255      // when a paper-input is focused, it needs to focus
256      // its underlying native input, which will also fire a `blur`
257      // event.
258      test('focus events fired on host element', function() {
259        input.addEventListener('focus', function(event) {
260          assert(input.focused, 'input is focused');
261        });
262        MockInteractions.focus(input);
263      });
264
265      test('focus events fired on host element if nested element is focused', function() {
266        input.addEventListener('focus', function(event) {
267          assert(input.focused, 'input is focused');
268        });
269        MockInteractions.focus(input.inputElement);
270      });
271
272      test('blur events fired on host element', function() {
273        MockInteractions.focus(input);
274        input.addEventListener('blur', function(event) {
275          assert(!input.focused, 'input is blurred');
276        });
277        MockInteractions.blur(input);
278      });
279
280      test('blur events fired on host element nested element is blurred', function() {
281        MockInteractions.focus(input);
282        input.addEventListener('blur', function(event) {
283          assert(!input.focused, 'input is blurred');
284        });
285        MockInteractions.blur(input.inputElement);
286      });
287
288      test('focusing then bluring sets the focused attribute correctly', function() {
289        MockInteractions.focus(input);
290        assert(input.focused, 'input is focused');
291        MockInteractions.blur(input);
292        assert(!input.focused, 'input is blurred');
293        MockInteractions.focus(input.inputElement);
294        assert(input.focused, 'input is focused');
295        MockInteractions.blur(input.inputElement);
296        assert(!input.focused, 'input is blurred');
297      });
298
299      test('focusing then bluring with shift-tab removes the focused attribute correctly', function() {
300        MockInteractions.focus(input);
301        assert(input.focused, 'input is focused');
302
303        // Fake a shift-tab induced blur by forcing the flag.
304        input._shiftTabPressed = true;
305        MockInteractions.blur(input.inputElement);
306        assert(!input.focused, 'input is blurred');
307      });
308    });
309
310    suite('focused styling (integration test)', function() {
311
312      test('underline is colored when input is focused', function(done) {
313        var input = fixture('basic');
314        var container = Polymer.dom(input.root).querySelector('paper-input-container');
315        var line = Polymer.dom(container.root).querySelector('.underline');
316        assert.isFalse(line.classList.contains('is-highlighted'), 'line is not highlighted when input is not focused');
317        MockInteractions.focus(input.inputElement);
318        requestAnimationFrame(function() {
319          assert.isTrue(line.classList.contains('is-highlighted'), 'line is highlighted when input is focused');
320          done();
321        });
322      });
323
324    });
325
326    suite('validation', function() {
327
328      test('invalid attribute updated after calling validate()', function() {
329        var input = fixture('required-no-auto-validate');
330        forceXIfStamp(input);
331        input.validate();
332        var error = Polymer.dom(input.root).querySelector('paper-input-error');
333        assert.ok(error, 'paper-input-error exists');
334        assert.notEqual(getComputedStyle(error).display, 'none', 'error is not display:none');
335        assert.isTrue(input.invalid, 'invalid is true');
336      });
337
338    });
339
340    suite('a11y', function() {
341      test('has aria-labelledby, which is monotonically increasing', function() {
342        var inputs = fixture('multiple-inputs');
343
344        // Find the first index of the input in this fixture. Since the label
345        // ids monotonically increase every time a new input is created, and
346        // this fixture isn't the first one in the document, we're going to start
347        // at an ID > 1.
348        var firstLabel = Polymer.dom(inputs[0].root).querySelector('label').id;
349        var index = parseInt(firstLabel.substr(firstLabel.lastIndexOf('-') + 1));
350
351        for (var i = 0; i < inputs.length; i++ ) {
352          var input = inputs[i].inputElement;
353          var label = Polymer.dom(inputs[i].root).querySelector('label').id;
354
355          assert.isTrue(input.hasAttribute('aria-labelledby'));
356          assert.equal(label, 'paper-input-label-' + (index++));
357          assert.equal(input.getAttribute('aria-labelledby'), label);
358        }
359      });
360
361      test('has aria-describedby for error message', function() {
362        var input = fixture('required');
363        forceXIfStamp(input);
364        assert.isTrue(input.inputElement.hasAttribute('aria-describedby'));
365        assert.equal(input.inputElement.getAttribute('aria-describedby'), Polymer.dom(input.root).querySelector('paper-input-error').id, 'aria-describedby points to the error message');
366      });
367
368      test('has aria-describedby for character counter', function() {
369        var input = fixture('char-counter');
370        forceXIfStamp(input);
371        assert.isTrue(input.inputElement.hasAttribute('aria-describedby'));
372        assert.equal(input.inputElement.getAttribute('aria-describedby'), Polymer.dom(input.root).querySelector('paper-input-char-counter').id, 'aria-describedby points to the character counter');
373      });
374
375      test('has aria-describedby for character counter and error', function() {
376        var input = fixture('required-char-counter');
377        forceXIfStamp(input);
378        assert.isTrue(input.inputElement.hasAttribute('aria-describedby'));
379        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');
380      });
381
382      test('focus an input with tabindex', function(done) {
383        var input = fixture('has-tabindex');
384        flush(function() {
385          MockInteractions.focus(input);
386          flush(function() {
387            assert.equal(input.shadowRoot ? input.shadowRoot.activeElement :
388                document.activeElement, input._focusableElement);
389            done();
390          });
391        });
392      });
393    });
394
395  </script>
396
397</body>
398</html>
399