~didrocks/+junk/face-detection-15.04

« back to all changes in this revision

Viewing changes to facedetection/www/bower_components/iron-overlay-behavior/test/iron-overlay-behavior.html

  • Committer: Didier Roche
  • Date: 2016-05-10 23:09:11 UTC
  • Revision ID: didier.roche@canonical.com-20160510230911-c7xr490zrj3yrzxd
New version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
13
  <head>
 
14
 
 
15
    <title>iron-overlay-behavior tests</title>
 
16
 
 
17
    <meta charset="utf-8">
 
18
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
 
19
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
 
20
 
 
21
    <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
 
22
 
 
23
    <script src="../../web-component-tester/browser.js"></script>
 
24
    <link rel="import" href="../../iron-test-helpers/iron-test-helpers.html">
 
25
    <link rel="import" href="test-overlay.html">
 
26
    <link rel="import" href="test-overlay2.html">
 
27
    <link rel="import" href="test-buttons.html">
 
28
    <link rel="import" href="test-menu-button.html">
 
29
 
 
30
    <style is="custom-style">
 
31
      iron-overlay-backdrop {
 
32
        /* For quicker tests */
 
33
        --iron-overlay-backdrop: {
 
34
          transition: none;
 
35
        }
 
36
      }
 
37
    </style>
 
38
 
 
39
  </head>
 
40
 
 
41
  <body>
 
42
 
 
43
    <test-fixture id="basic">
 
44
      <template>
 
45
        <test-overlay>
 
46
          Basic Overlay
 
47
        </test-overlay>
 
48
      </template>
 
49
    </test-fixture>
 
50
 
 
51
    <test-fixture id="opened">
 
52
      <template>
 
53
        <test-overlay opened>
 
54
          Basic Overlay
 
55
        </test-overlay>
 
56
      </template>
 
57
    </test-fixture>
 
58
 
 
59
    <test-fixture id="autofocus">
 
60
      <template>
 
61
        <test-overlay>
 
62
          Autofocus
 
63
          <button autofocus>button</button>
 
64
        </test-overlay>
 
65
      </template>
 
66
    </test-fixture>
 
67
 
 
68
    <test-fixture id="focusables">
 
69
      <template>
 
70
        <test-overlay tabindex="-1">
 
71
          <h2>Focusables (no tabindex)</h2>
 
72
          <div>
 
73
            <input class="focusable1" placeholder="1 (nested)">
 
74
          </div>
 
75
          <button class="focusable2">1</button>
 
76
          <button disabled> disabled button</button>
 
77
          <div tabindex="-1">not focusable</div>
 
78
          <button class="focusable3">2</button>
 
79
        </test-overlay>
 
80
        <test-overlay tabindex="-1">
 
81
          <h2>Focusables (with tabindex)</h2>
 
82
          <div tabindex="-1">not focusable</div>
 
83
          <div tabindex="3" class="focusable3">3</div>
 
84
          <div tabindex="4" class="focusable4">4</div>
 
85
          <div tabindex="5" class="focusable5">5</div>
 
86
          <div>
 
87
            <div tabindex="1" class="focusable1">1 (nested)</div>
 
88
            <div tabindex="6" class="focusable6">6 (nested)</div>
 
89
          </div>
 
90
          <div tabindex="2" class="focusable2">2</div>
 
91
        </test-overlay>
 
92
      </template>
 
93
    </test-fixture>
 
94
 
 
95
    <test-fixture id="backdrop">
 
96
      <template>
 
97
        <test-overlay with-backdrop>
 
98
          Overlay with backdrop
 
99
        </test-overlay>
 
100
      </template>
 
101
    </test-fixture>
 
102
 
 
103
    <test-fixture id="multiple">
 
104
      <template>
 
105
        <test-overlay class="overlay-1">
 
106
          Test overlay 1
 
107
        </test-overlay>
 
108
        <test-overlay class="overlay-2">
 
109
          Test overlay 2
 
110
        </test-overlay>
 
111
        <test-overlay2 class="overlay-3">
 
112
          Other overlay 3
 
113
        </test-overlay2>
 
114
      </template>
 
115
    </test-fixture>
 
116
 
 
117
    <test-fixture id="composed">
 
118
      <template>
 
119
        <test-menu-button>
 
120
          Composed overlay
 
121
          <button>Button</button>
 
122
        </test-menu-button>
 
123
      </template>
 
124
    </test-fixture>
 
125
 
 
126
    <test-buttons id="buttons"></test-buttons>
 
127
    <input id="focusInput" placeholder="focus input">
 
128
 
 
129
    <script>
 
130
 
 
131
      HTMLImports.whenReady(function() {
 
132
        // Enable document-wide tap recognizer.
 
133
        Polymer.Gestures.add(document, 'tap', null);
 
134
      });
 
135
 
 
136
      function runAfterOpen(overlay, callback) {
 
137
        overlay.addEventListener('iron-overlay-opened', callback);
 
138
        overlay.open();
 
139
      }
 
140
 
 
141
      function runAfterClose(overlay, callback) {
 
142
        overlay.addEventListener('iron-overlay-closed', callback);
 
143
        overlay.close();
 
144
      }
 
145
 
 
146
      suite('basic overlay', function() {
 
147
        var overlay;
 
148
 
 
149
        setup(function() {
 
150
          overlay = fixture('basic');
 
151
        });
 
152
 
 
153
        test('overlay starts hidden', function() {
 
154
          assert.isFalse(overlay.opened, 'overlay starts closed');
 
155
          assert.equal(getComputedStyle(overlay).display, 'none', 'overlay starts hidden');
 
156
        });
 
157
 
 
158
        test('overlay open/close events', function(done) {
 
159
          var nevents = 0;
 
160
 
 
161
          overlay.addEventListener('iron-overlay-opened', function() {
 
162
            nevents += 1;
 
163
            overlay.opened = false;
 
164
          });
 
165
 
 
166
          overlay.addEventListener('iron-overlay-closed', function() {
 
167
            nevents += 1;
 
168
            assert.equal(nevents, 2, 'opened and closed events fired');
 
169
            done();
 
170
          });
 
171
 
 
172
          overlay.opened = true;
 
173
        });
 
174
 
 
175
        test('open() refits overlay only once', function(done) {
 
176
          var spy = sinon.spy(overlay, 'refit');
 
177
          runAfterOpen(overlay, function() {
 
178
            assert.equal(spy.callCount, 1, 'overlay did refit only once');
 
179
            done();
 
180
          });
 
181
        });
 
182
 
 
183
        test('open overlay refits on iron-resize', function(done) {
 
184
          runAfterOpen(overlay, function() {
 
185
            var spy = sinon.spy(overlay, 'refit');
 
186
            overlay.fire('iron-resize');
 
187
            Polymer.dom.flush();
 
188
            requestAnimationFrame(function() {
 
189
              assert.isTrue(spy.called, 'overlay did refit');
 
190
              done();
 
191
            });
 
192
          });
 
193
        });
 
194
 
 
195
        test('closed overlay does not refit on iron-resize', function(done) {
 
196
          var spy = sinon.spy(overlay, 'refit');
 
197
          overlay.fire('iron-resize');
 
198
          Polymer.dom.flush();
 
199
          requestAnimationFrame(function() {
 
200
            assert.isFalse(spy.called, 'overlay should not refit');
 
201
            done();
 
202
          });
 
203
        });
 
204
 
 
205
        test('open() triggers iron-resize', function(done) {
 
206
          var callCount = 0;
 
207
          // Ignore iron-resize triggered by window resize.
 
208
          window.addEventListener('resize', function() { callCount--; }, true);
 
209
          overlay.addEventListener('iron-resize', function() { callCount++; });
 
210
          runAfterOpen(overlay, function() {
 
211
            assert.equal(callCount, 1, 'iron-resize called once before iron-overlay-opened');
 
212
            done();
 
213
          });
 
214
        });
 
215
 
 
216
        test('close() triggers iron-resize', function(done) {
 
217
          runAfterOpen(overlay, function() {
 
218
            var spy = sinon.stub();
 
219
            overlay.addEventListener('iron-resize', spy);
 
220
            runAfterClose(overlay, function() {
 
221
              assert.equal(spy.callCount, 1, 'iron-resize called once before iron-overlay-closed');
 
222
              done();
 
223
            });
 
224
          });
 
225
        });
 
226
 
 
227
        test('closed overlay does not trigger iron-resize when its content changes', function() {
 
228
          // Ignore iron-resize triggered by window resize.
 
229
          var callCount = 0;
 
230
          window.addEventListener('resize', function() { callCount--; }, true);
 
231
          overlay.addEventListener('iron-resize', function() { callCount++; });
 
232
          Polymer.dom(overlay).appendChild(document.createElement('div'));
 
233
          Polymer.dom.flush();
 
234
          assert.equal(callCount, 0, 'iron-resize should not be called');
 
235
        });
 
236
 
 
237
        test('open overlay triggers iron-resize when its content changes', function(done) {
 
238
          runAfterOpen(overlay, function() {
 
239
            var spy = sinon.stub();
 
240
            overlay.addEventListener('iron-resize', spy);
 
241
            Polymer.dom(overlay).appendChild(document.createElement('div'));
 
242
            Polymer.dom.flush();
 
243
            assert.equal(spy.callCount, 1, 'iron-resize should be called once');
 
244
            done();
 
245
          });
 
246
        });
 
247
 
 
248
        test('close an overlay quickly after open', function(done) {
 
249
          // first, open the overlay
 
250
          overlay.open();
 
251
          overlay.async(function() {
 
252
            // during the opening transition, close the overlay
 
253
            this.close();
 
254
            // wait for any exceptions to be thrown until the transition is done
 
255
            this.async(function() {
 
256
              done();
 
257
            }, 300);
 
258
          });
 
259
        });
 
260
 
 
261
        test('clicking an overlay does not close it', function(done) {
 
262
          runAfterOpen(overlay, function() {
 
263
            var spy = sinon.stub();
 
264
            overlay.addEventListener('iron-overlay-closed', spy);
 
265
            MockInteractions.tap(overlay);
 
266
            overlay.async(function() {
 
267
              assert.isFalse(spy.called, 'iron-overlay-closed should not fire');
 
268
              done();
 
269
            }, 10);
 
270
          });
 
271
        });
 
272
 
 
273
        test('open overlay on mousedown does not close it', function(done) {
 
274
          var btn = document.createElement('button');
 
275
          btn.addEventListener('mousedown', overlay.open.bind(overlay));
 
276
          document.body.appendChild(btn);
 
277
          // It triggers mousedown, mouseup, and click.
 
278
          MockInteractions.tap(btn);
 
279
          document.body.removeChild(btn);
 
280
 
 
281
          assert.isTrue(overlay.opened, 'overlay opened');
 
282
          overlay.async(function() {
 
283
            assert.isTrue(overlay.opened, 'overlay is still open');
 
284
            done();
 
285
          }, 10);
 
286
        });
 
287
 
 
288
        test('clicking outside fires iron-overlay-canceled', function(done) {
 
289
          runAfterOpen(overlay, function() {
 
290
            overlay.addEventListener('iron-overlay-canceled', function(event) {
 
291
              assert.equal(event.detail.target, document.body, 'detail contains original click event');
 
292
              done();
 
293
            });
 
294
            MockInteractions.tap(document.body);
 
295
          });
 
296
        });
 
297
 
 
298
        test('clicking outside closes the overlay', function(done) {
 
299
          runAfterOpen(overlay, function() {
 
300
            overlay.addEventListener('iron-overlay-closed', function(event) {
 
301
              assert.isTrue(event.detail.canceled, 'overlay is canceled');
 
302
              done();
 
303
            });
 
304
            MockInteractions.tap(document.body);
 
305
          });
 
306
        });
 
307
 
 
308
        test('iron-overlay-canceled event can be prevented', function(done) {
 
309
          runAfterOpen(overlay, function() {
 
310
            overlay.addEventListener('iron-overlay-canceled', function(event) {
 
311
              event.preventDefault();
 
312
            });
 
313
            var spy = sinon.stub();
 
314
            overlay.addEventListener('iron-overlay-closed', spy);
 
315
            MockInteractions.tap(document.body);
 
316
            Polymer.Base.async(function() {
 
317
              assert.isTrue(overlay.opened, 'overlay is still open');
 
318
              assert.isFalse(spy.called, 'iron-overlay-closed not fired');
 
319
              done();
 
320
            }, 10);
 
321
          });
 
322
        });
 
323
 
 
324
        test('cancel an overlay with esc key', function(done) {
 
325
          runAfterOpen(overlay, function() {
 
326
            overlay.addEventListener('iron-overlay-canceled', function(event) {
 
327
              assert.equal(event.detail.type, 'keydown');
 
328
              done();
 
329
            });
 
330
            MockInteractions.pressAndReleaseKeyOn(document, 27);
 
331
          });
 
332
        });
 
333
 
 
334
        test('close an overlay with esc key', function(done) {
 
335
          runAfterOpen(overlay, function() {
 
336
            overlay.addEventListener('iron-overlay-closed', function(event) {
 
337
              assert.isTrue(event.detail.canceled, 'overlay is canceled');
 
338
              done();
 
339
            });
 
340
            MockInteractions.pressAndReleaseKeyOn(document, 27);
 
341
          });
 
342
        });
 
343
 
 
344
        test('no-cancel-on-outside-click property', function(done) {
 
345
          overlay.noCancelOnOutsideClick = true;
 
346
          runAfterOpen(overlay, function() {
 
347
            var spy = sinon.stub();
 
348
            overlay.addEventListener('iron-overlay-closed', spy);
 
349
            MockInteractions.tap(document.body);
 
350
            Polymer.Base.async(function() {
 
351
              assert.isFalse(spy.called, 'iron-overlay-closed should not fire');
 
352
              done();
 
353
            }, 10);
 
354
          });
 
355
        });
 
356
 
 
357
        test('no-cancel-on-esc-key property', function(done) {
 
358
          overlay.noCancelOnEscKey = true;
 
359
          runAfterOpen(overlay, function() {
 
360
            var spy = sinon.stub();
 
361
            overlay.addEventListener('iron-overlay-closed', spy);
 
362
            MockInteractions.pressAndReleaseKeyOn(document, 27);
 
363
            Polymer.Base.async(function() {
 
364
              assert.isFalse(spy.called, 'iron-overlay-cancel should not fire');
 
365
              done();
 
366
            }, 10);
 
367
          });
 
368
        });
 
369
 
 
370
        test('with-backdrop sets tabindex=-1 and removes it', function() {
 
371
          overlay.withBackdrop = true;
 
372
          assert.equal(overlay.getAttribute('tabindex'), '-1', 'tabindex is -1');
 
373
          overlay.withBackdrop = false;
 
374
          assert.isFalse(overlay.hasAttribute('tabindex'), 'tabindex removed');
 
375
        });
 
376
 
 
377
        test('with-backdrop does not override tabindex if already set', function() {
 
378
          overlay.setAttribute('tabindex', '1');
 
379
          overlay.withBackdrop = true;
 
380
          assert.equal(overlay.getAttribute('tabindex'), '1', 'tabindex is 1');
 
381
          overlay.withBackdrop = false;
 
382
          assert.equal(overlay.getAttribute('tabindex'), '1', 'tabindex is still 1');
 
383
        });
 
384
 
 
385
      });
 
386
 
 
387
      suite('keyboard event listener', function() {
 
388
        var overlay;
 
389
 
 
390
        var preventKeyDown = function(event) {
 
391
          event.preventDefault();
 
392
          event.stopPropagation();
 
393
        }
 
394
 
 
395
        suiteSetup(function() {
 
396
          // Worst case scenario: listener with useCapture = true that prevents & stops propagation
 
397
          // added before the overlay is initialized.
 
398
          document.addEventListener('keydown', preventKeyDown, true);
 
399
        });
 
400
 
 
401
        setup(function() {
 
402
          overlay = fixture('basic');
 
403
        });
 
404
 
 
405
        suiteTeardown(function() {
 
406
          document.removeEventListener('keydown', preventKeyDown, true);
 
407
        });
 
408
 
 
409
        test('cancel an overlay with esc key even if event is prevented by other listeners', function(done) {
 
410
          runAfterOpen(overlay, function() {
 
411
            overlay.addEventListener('iron-overlay-canceled', function(event) {
 
412
              done();
 
413
            });
 
414
            MockInteractions.pressAndReleaseKeyOn(document, 27);
 
415
          });
 
416
        });
 
417
      });
 
418
 
 
419
      suite('opened overlay', function() {
 
420
        var overlay;
 
421
 
 
422
        setup(function() {
 
423
          overlay = fixture('opened');
 
424
        });
 
425
 
 
426
        test('overlay open by default', function(done) {
 
427
          overlay.addEventListener('iron-overlay-opened', function() {
 
428
            assert.isTrue(overlay.opened, 'overlay starts opened');
 
429
            assert.notEqual(getComputedStyle(overlay).display, 'none', 'overlay starts showing');
 
430
            done();
 
431
          });
 
432
        });
 
433
 
 
434
        test('overlay positioned & sized properly', function(done) {
 
435
          overlay.addEventListener('iron-overlay-opened', function() {
 
436
            var s = getComputedStyle(overlay);
 
437
            assert.closeTo(parseFloat(s.left), (window.innerWidth - overlay.offsetWidth) / 2, 1, 'centered horizontally');
 
438
            assert.closeTo(parseFloat(s.top), (window.innerHeight - overlay.offsetHeight) / 2, 1, 'centered vertically');
 
439
            done();
 
440
          });
 
441
        });
 
442
      });
 
443
 
 
444
      suite('focus handling', function() {
 
445
        var overlay;
 
446
 
 
447
        setup(function() {
 
448
          overlay = fixture('autofocus');
 
449
        });
 
450
 
 
451
        test('node with autofocus is focused', function(done) {
 
452
          runAfterOpen(overlay, function() {
 
453
            assert.equal(Polymer.dom(overlay).querySelector('[autofocus]'), document.activeElement, '<button autofocus> is focused');
 
454
            done();
 
455
          });
 
456
        });
 
457
 
 
458
        test('no-auto-focus will not focus node with autofocus', function(done) {
 
459
          overlay.noAutoFocus = true;
 
460
          runAfterOpen(overlay, function() {
 
461
            assert.notEqual(Polymer.dom(overlay).querySelector('[autofocus]'), document.activeElement, '<button autofocus> not focused after opened');
 
462
            done();
 
463
          });
 
464
          // In Safari the element with autofocus will immediately receive focus when displayed for the first time http://jsbin.com/woroci/2/
 
465
          // Ensure this is not the case for overlay.
 
466
          assert.notEqual(Polymer.dom(overlay).querySelector('[autofocus]'), document.activeElement, '<button autofocus> not immediately focused');
 
467
        });
 
468
 
 
469
        test('no-cancel-on-outside-click property; focus stays on overlay when click outside', function(done) {
 
470
          overlay.noCancelOnOutsideClick = true;
 
471
          runAfterOpen(overlay, function() {
 
472
            MockInteractions.tap(document.body);
 
473
            Polymer.Base.async(function() {
 
474
              assert.equal(Polymer.dom(overlay).querySelector('[autofocus]'), document.activeElement, '<button autofocus> is focused');
 
475
              done();
 
476
            }, 10);
 
477
          });
 
478
        });
 
479
 
 
480
        test('with-backdrop traps the focus within the overlay', function(done) {
 
481
          var focusSpy = sinon.stub();
 
482
          var button = document.createElement('button');
 
483
          document.body.appendChild(button);
 
484
          button.addEventListener('focus', focusSpy, true);
 
485
 
 
486
          overlay.withBackdrop = true;
 
487
          runAfterOpen(overlay, function() {
 
488
            // Try to steal the focus
 
489
            MockInteractions.focus(button);
 
490
            assert.equal(Polymer.dom(overlay).querySelector('[autofocus]'), document.activeElement, '<button autofocus> is focused');
 
491
            assert.equal(focusSpy.callCount, 0, 'button in body did not get the focus');
 
492
            document.body.removeChild(button);
 
493
            done();
 
494
          });
 
495
        });
 
496
 
 
497
      });
 
498
 
 
499
      suite('focusable nodes', function() {
 
500
        var overlay, overlayWithTabIndex;
 
501
 
 
502
        setup(function() {
 
503
          var f = fixture('focusables');
 
504
          overlay = f[0];
 
505
          overlayWithTabIndex = f[1];
 
506
        });
 
507
 
 
508
        test('_focusableNodes returns nodes that are focusable', function() {
 
509
          var focusableNodes = overlay._focusableNodes;
 
510
          assert.equal(focusableNodes.length, 3, '3 nodes are focusable');
 
511
          assert.equal(focusableNodes[0], Polymer.dom(overlay).querySelector('.focusable1'));
 
512
          assert.equal(focusableNodes[1], Polymer.dom(overlay).querySelector('.focusable2'));
 
513
          assert.equal(focusableNodes[2], Polymer.dom(overlay).querySelector('.focusable3'));
 
514
        });
 
515
 
 
516
        test('_focusableNodes includes overlay if it has a valid tabindex', function() {
 
517
          overlay.setAttribute('tabindex', '0');
 
518
          var focusableNodes = overlay._focusableNodes;
 
519
          assert.equal(focusableNodes.length, 4, '4 focusable nodes');
 
520
          assert.notEqual(focusableNodes.indexOf(overlay), -1, 'overlay is included');
 
521
        });
 
522
 
 
523
        test('_focusableNodes respects the tabindex order', function() {
 
524
          var focusableNodes = overlayWithTabIndex._focusableNodes;
 
525
          assert.equal(focusableNodes.length, 6, '6 nodes are focusable');
 
526
          assert.equal(focusableNodes[0], Polymer.dom(overlayWithTabIndex).querySelector('.focusable1'));
 
527
          assert.equal(focusableNodes[1], Polymer.dom(overlayWithTabIndex).querySelector('.focusable2'));
 
528
          assert.equal(focusableNodes[2], Polymer.dom(overlayWithTabIndex).querySelector('.focusable3'));
 
529
          assert.equal(focusableNodes[3], Polymer.dom(overlayWithTabIndex).querySelector('.focusable4'));
 
530
          assert.equal(focusableNodes[4], Polymer.dom(overlayWithTabIndex).querySelector('.focusable5'));
 
531
          assert.equal(focusableNodes[5], Polymer.dom(overlayWithTabIndex).querySelector('.focusable6'));
 
532
        });
 
533
 
 
534
        test('with-backdrop: TAB & Shift+TAB wrap focus', function(done) {
 
535
          overlay.withBackdrop = true;
 
536
          var focusableNodes = overlay._focusableNodes;
 
537
          runAfterOpen(overlay, function() {
 
538
            Polymer.Base.async(function() {
 
539
              // Go to last element.
 
540
              MockInteractions.focus(focusableNodes[focusableNodes.length-1]);
 
541
              // Simulate TAB & focus out of overlay.
 
542
              MockInteractions.pressAndReleaseKeyOn(document, 9);
 
543
              MockInteractions.focus(document.body);
 
544
 
 
545
              assert.equal(focusableNodes[0], document.activeElement, 'focus wrapped to first focusable');
 
546
              // Simulate Shift+TAB & focus out of overlay.
 
547
              MockInteractions.pressAndReleaseKeyOn(document, 9, ['shift']);
 
548
              MockInteractions.focus(document.body);
 
549
              assert.equal(focusableNodes[focusableNodes.length-1], document.activeElement, 'focus wrapped to last focusable');
 
550
              done();
 
551
            }, 1);
 
552
          });
 
553
        });
 
554
 
 
555
        test('with-backdrop: TAB & Shift+TAB wrap focus respecting tabindex', function(done) {
 
556
          overlayWithTabIndex.withBackdrop = true;
 
557
          var focusableNodes = overlayWithTabIndex._focusableNodes;
 
558
          runAfterOpen(overlayWithTabIndex, function() {
 
559
            Polymer.Base.async(function() {
 
560
              // Go to last element.
 
561
              MockInteractions.focus(focusableNodes[focusableNodes.length-1]);
 
562
              // Simulate TAB & focus out of overlay.
 
563
              MockInteractions.pressAndReleaseKeyOn(document, 9);
 
564
              MockInteractions.focus(document.body);
 
565
              assert.equal(focusableNodes[0], document.activeElement, 'focus wrapped to first focusable');
 
566
              // Simulate Shift+TAB & focus out of overlay.
 
567
              MockInteractions.pressAndReleaseKeyOn(document, 9, ['shift']);
 
568
              MockInteractions.focus(document.body);
 
569
              assert.equal(focusableNodes[focusableNodes.length-1], document.activeElement, 'focus wrapped to last focusable');
 
570
              done();
 
571
            }, 1);
 
572
          });
 
573
        });
 
574
 
 
575
      });
 
576
 
 
577
      suite('Polymer.IronOverlayManager.deepActiveElement', function() {
 
578
 
 
579
        test('handles document.body', function () {
 
580
          document.body.focus();
 
581
          assert.equal(Polymer.IronOverlayManager.deepActiveElement, document.body);
 
582
        });
 
583
 
 
584
        test('handles light dom', function () {
 
585
          var focusable = document.getElementById('focusInput');
 
586
          focusable.focus();
 
587
          assert.equal(Polymer.IronOverlayManager.deepActiveElement, focusable, 'input is handled');
 
588
          focusable.blur();
 
589
        });
 
590
 
 
591
        test('handles shadow dom', function () {
 
592
          var focusable = document.getElementById('buttons').$.button0;
 
593
          focusable.focus();
 
594
          assert.equal(Polymer.IronOverlayManager.deepActiveElement, focusable);
 
595
          focusable.blur();
 
596
        });
 
597
 
 
598
      });
 
599
 
 
600
      suite('restore-focus-on-close', function() {
 
601
 
 
602
        var overlay;
 
603
        setup(function () {
 
604
          overlay = fixture('autofocus');
 
605
          overlay.restoreFocusOnClose = true;
 
606
        });
 
607
 
 
608
        teardown(function () {
 
609
          // No matter what, return the focus to body!
 
610
          document.body.focus();
 
611
        });
 
612
 
 
613
        test('does not return focus on close by default (restore-focus-on-close=false)', function(done) {
 
614
          overlay.restoreFocusOnClose = false;
 
615
          var focusable = document.getElementById('focusInput');
 
616
          focusable.focus();
 
617
          runAfterOpen(overlay, function() {
 
618
            runAfterClose(overlay, function() {
 
619
              assert.notEqual(Polymer.IronOverlayManager.deepActiveElement, focusable, 'focus is not restored to focusable');
 
620
              done();
 
621
            });
 
622
          });
 
623
        });
 
624
 
 
625
        test('overlay returns focus on close', function(done) {
 
626
          var focusable = document.getElementById('focusInput');
 
627
          focusable.focus();
 
628
          runAfterOpen(overlay, function() {
 
629
            runAfterClose(overlay, function() {
 
630
              assert.equal(Polymer.IronOverlayManager.deepActiveElement, focusable, 'focus restored to focusable');
 
631
              done();
 
632
            });
 
633
          });
 
634
        });
 
635
 
 
636
        test('overlay returns focus on close (ShadowDOM)', function(done) {
 
637
          var focusable = document.getElementById('buttons').$.button0;
 
638
          focusable.focus();
 
639
          runAfterOpen(overlay, function() {
 
640
            runAfterClose(overlay, function() {
 
641
              assert.equal(Polymer.IronOverlayManager.deepActiveElement, focusable, 'focus restored to focusable');
 
642
              done();
 
643
            });
 
644
          });
 
645
        });
 
646
 
 
647
        test('overlay does not return focus to elements contained in another overlay', function(done) {
 
648
          var overlay2 = fixture('basic');
 
649
          // So it doesn't interfere with focus changes.
 
650
          overlay2.noAutoFocus = true;
 
651
          var focusable = document.createElement('input');
 
652
          runAfterOpen(overlay2,function () {
 
653
            Polymer.dom(overlay2).appendChild(focusable);
 
654
            focusable.focus();
 
655
            runAfterOpen(overlay, function() {
 
656
              runAfterClose(overlay, function() {
 
657
                assert.notEqual(Polymer.IronOverlayManager.deepActiveElement, focusable, 'focus not restored to focusable inside overlay2');
 
658
                done();
 
659
              });
 
660
            });
 
661
          });
 
662
        });
 
663
 
 
664
        test('overlay does not return focus to elements that are not in the body anymore', function(done) {
 
665
          var focusable = document.createElement('input');
 
666
          document.body.appendChild(focusable);
 
667
          focusable.focus();
 
668
          var focusSpy = sinon.spy(focusable, 'focus');
 
669
          runAfterOpen(overlay, function() {
 
670
            document.body.removeChild(focusable);
 
671
            runAfterClose(overlay, function() {
 
672
              assert.isFalse(focusSpy.called, 'focus not called');
 
673
              done();
 
674
            });
 
675
          });
 
676
        });
 
677
 
 
678
      });
 
679
 
 
680
      suite('overlay with backdrop', function() {
 
681
        var overlay;
 
682
 
 
683
        setup(function() {
 
684
          overlay = fixture('backdrop');
 
685
        });
 
686
 
 
687
        test('backdrop is opened when overlay is opened', function(done) {
 
688
          assert.isDefined(overlay.backdropElement, 'backdrop is defined');
 
689
          runAfterOpen(overlay, function() {
 
690
            assert.isTrue(overlay.backdropElement.opened, 'backdrop is opened');
 
691
            assert.isDefined(overlay.backdropElement.parentNode, 'backdrop is inserted in the DOM');
 
692
            done();
 
693
          });
 
694
        });
 
695
 
 
696
        test('backdrop appears behind the overlay', function(done) {
 
697
          runAfterOpen(overlay, function() {
 
698
            styleZ = parseInt(window.getComputedStyle(overlay).zIndex, 10);
 
699
            backdropStyleZ = parseInt(window.getComputedStyle(overlay.backdropElement).zIndex, 10);
 
700
            assert.isTrue(styleZ > backdropStyleZ, 'overlay has higher z-index than backdrop');
 
701
            done();
 
702
          });
 
703
        });
 
704
 
 
705
        test('backdrop is removed when overlay is closed', function(done) {
 
706
          runAfterOpen(overlay, function() {
 
707
            runAfterClose(overlay, function() {
 
708
              assert.isFalse(overlay.backdropElement.opened, 'backdrop is closed');
 
709
              assert.isNotOk(overlay.backdropElement.parentNode, 'backdrop is removed from the DOM');
 
710
              assert.lengthOf(document.querySelectorAll('iron-overlay-backdrop'), 0, 'no backdrop elements on body');
 
711
              done();
 
712
            });
 
713
          });
 
714
        });
 
715
 
 
716
        test('backdrop is removed when the element is removed from DOM', function(done) {
 
717
          runAfterOpen(overlay, function() {
 
718
            Polymer.dom(overlay).parentNode.removeChild(overlay);
 
719
            // Ensure detached is executed.
 
720
            Polymer.dom.flush();
 
721
            assert.isFalse(overlay.backdropElement.opened, 'backdrop is closed');
 
722
            assert.isNotOk(overlay.backdropElement.parentNode, 'backdrop is removed from the DOM');
 
723
            assert.lengthOf(document.querySelectorAll('iron-overlay-backdrop'), 0, 'no backdrop elements on body');
 
724
            assert.isNotOk(overlay._manager.currentOverlay(), 'currentOverlay ok');
 
725
            done();
 
726
          });
 
727
        });
 
728
 
 
729
        test('manager.getBackdrops() immediately updated on opened changes', function() {
 
730
          overlay.opened = true;
 
731
          assert.equal(Polymer.IronOverlayManager.getBackdrops().length, 1, 'overlay added to manager backdrops');
 
732
          overlay.opened = false;
 
733
          assert.equal(Polymer.IronOverlayManager.getBackdrops().length, 0, 'overlay removed from manager backdrops');
 
734
        });
 
735
 
 
736
        test('updating with-backdrop to false closes backdrop', function(done) {
 
737
          runAfterOpen(overlay, function() {
 
738
            overlay.withBackdrop = false;
 
739
            assert.isFalse(overlay.backdropElement.opened, 'backdrop is closed');
 
740
            assert.isNotObject(overlay.backdropElement.parentNode, 'backdrop is removed from document');
 
741
            done();
 
742
          });
 
743
        });
 
744
 
 
745
        test('backdrop is removed when toggling overlay opened', function(done) {
 
746
          overlay.open();
 
747
          assert.isOk(overlay.backdropElement.parentNode, 'backdrop is immediately inserted in the document');
 
748
          runAfterClose(overlay, function() {
 
749
            assert.isFalse(overlay.backdropElement.opened, 'backdrop is closed');
 
750
            assert.isNotOk(overlay.backdropElement.parentNode, 'backdrop is removed from document');
 
751
            done();
 
752
          });
 
753
        });
 
754
      });
 
755
 
 
756
      suite('multiple overlays', function() {
 
757
        var overlay1, overlay2;
 
758
 
 
759
        setup(function() {
 
760
          var f = fixture('multiple');
 
761
          overlay1 = f[0];
 
762
          overlay2 = f[1];
 
763
        });
 
764
 
 
765
        test('new overlays appear on top', function(done) {
 
766
          runAfterOpen(overlay1, function() {
 
767
            runAfterOpen(overlay2, function() {
 
768
              var styleZ = parseInt(window.getComputedStyle(overlay1).zIndex, 10);
 
769
              var styleZ1 = parseInt(window.getComputedStyle(overlay2).zIndex, 10);
 
770
              assert.isTrue(styleZ1 > styleZ, 'overlay2 has higher z-index than overlay1');
 
771
              done();
 
772
            });
 
773
          });
 
774
        });
 
775
 
 
776
        test('ESC closes only the top overlay', function(done) {
 
777
          runAfterOpen(overlay1, function() {
 
778
            runAfterOpen(overlay2, function() {
 
779
              MockInteractions.pressAndReleaseKeyOn(document, 27);
 
780
              assert.isFalse(overlay2.opened, 'overlay2 was closed');
 
781
              assert.isTrue(overlay1.opened, 'overlay1 is still opened');
 
782
              done();
 
783
            });
 
784
          });
 
785
        });
 
786
 
 
787
        test('close an overlay in proximity to another overlay', function(done) {
 
788
          // Open and close a separate overlay.
 
789
          overlay1.open();
 
790
          overlay1.close();
 
791
 
 
792
          // Open the overlay we care about.
 
793
          overlay2.open();
 
794
 
 
795
          // Immediately close the first overlay.
 
796
          // Wait for infinite recursion, otherwise we win.
 
797
          runAfterClose(overlay2, function() {
 
798
            done();
 
799
          })
 
800
        });
 
801
 
 
802
      });
 
803
 
 
804
      suite('Manager overlays in sync', function() {
 
805
        var overlay1, overlay2;
 
806
        var overlays;
 
807
 
 
808
        setup(function() {
 
809
          var f = fixture('multiple');
 
810
          overlay1 = f[0];
 
811
          overlay2 = f[1];
 
812
          overlays = Polymer.IronOverlayManager._overlays;
 
813
        });
 
814
 
 
815
        test('no duplicates after attached', function(done) {
 
816
          overlay1 = document.createElement('test-overlay');
 
817
          overlay1.addEventListener('iron-overlay-opened',function() {
 
818
            assert.equal(overlays.length, 1, 'correct count after open and attached');
 
819
            document.body.removeChild(overlay1);
 
820
            done();
 
821
          });
 
822
          overlay1.opened = true;
 
823
          assert.equal(overlays.length, 1, 'immediately updated');
 
824
          document.body.appendChild(overlay1);
 
825
        });
 
826
 
 
827
        test('open twice handled', function() {
 
828
          overlay1.open();
 
829
          assert.equal(overlays.length, 1, '1 overlay after open');
 
830
          overlay1.open();
 
831
          assert.equal(overlays.length, 1, '1 overlay after second open');
 
832
        });
 
833
 
 
834
        test('close handled', function() {
 
835
          overlay1.open();
 
836
          overlay1.close();
 
837
          assert.equal(overlays.length, 0, '0 overlays after close');
 
838
        });
 
839
 
 
840
        test('open/close brings overlay on top', function() {
 
841
          overlay1.open();
 
842
          overlay2.open();
 
843
          assert.equal(overlays.indexOf(overlay1), 0, 'overlay1 at index 0');
 
844
          assert.equal(overlays.indexOf(overlay2), 1, 'overlay2 at index 1');
 
845
          overlay1.close();
 
846
          overlay1.open();
 
847
          assert.equal(overlays.indexOf(overlay1), 1, 'overlay1 moved at index 1');
 
848
          assert.isAbove(parseInt(overlay1.style.zIndex), parseInt(overlay2.style.zIndex), 'overlay1 on top of overlay2');
 
849
        });
 
850
      });
 
851
 
 
852
      suite('z-ordering', function() {
 
853
 
 
854
        var originalMinimumZ;
 
855
        var overlay1, overlay2;
 
856
 
 
857
        setup(function() {
 
858
          var f = fixture('multiple');
 
859
          overlay1 = f[0];
 
860
          overlay2 = f[1];
 
861
          originalMinimumZ = Polymer.IronOverlayManager._minimumZ;
 
862
        });
 
863
 
 
864
        teardown(function() {
 
865
          Polymer.IronOverlayManager._minimumZ = originalMinimumZ;
 
866
        });
 
867
 
 
868
        // for iframes
 
869
        test('default z-index is greater than 100', function(done) {
 
870
          runAfterOpen(overlay1, function() {
 
871
            var styleZ = parseInt(window.getComputedStyle(overlay1).zIndex, 10);
 
872
            assert.isTrue(styleZ > 100, 'overlay1 z-index is <= 100');
 
873
            done();
 
874
          });
 
875
        });
 
876
 
 
877
        test('ensureMinimumZ() effects z-index', function(done) {
 
878
          Polymer.IronOverlayManager.ensureMinimumZ(1000);
 
879
 
 
880
          runAfterOpen(overlay1, function() {
 
881
            var styleZ = parseInt(window.getComputedStyle(overlay1).zIndex, 10);
 
882
            assert.isTrue(styleZ > 1000, 'overlay1 z-index is <= 1000');
 
883
            done();
 
884
          });
 
885
        });
 
886
 
 
887
        test('ensureMinimumZ() never decreases the minimum z-index', function(done) {
 
888
          Polymer.IronOverlayManager.ensureMinimumZ(1000);
 
889
          Polymer.IronOverlayManager.ensureMinimumZ(500);
 
890
 
 
891
          runAfterOpen(overlay1, function() {
 
892
            var styleZ = parseInt(window.getComputedStyle(overlay1).zIndex, 10);
 
893
            assert.isTrue(styleZ > 1000, 'overlay1 z-index is <= 1000');
 
894
            done();
 
895
          });
 
896
        });
 
897
 
 
898
      });
 
899
 
 
900
      suite('multiple overlays with backdrop', function() {
 
901
        var overlay1, overlay2, overlay3;
 
902
 
 
903
        setup(function() {
 
904
          var f = fixture('multiple');
 
905
          overlay1 = f[0];
 
906
          overlay2 = f[1];
 
907
          overlay3 = f[2];
 
908
          overlay1.withBackdrop = overlay2.withBackdrop = overlay3.withBackdrop = true;
 
909
        });
 
910
 
 
911
        test('multiple overlays share the same backdrop', function() {
 
912
          assert.isTrue(overlay1.backdropElement === overlay2.backdropElement, 'overlay1 and overlay2 have the same backdrop element');
 
913
          assert.isTrue(overlay1.backdropElement === overlay3.backdropElement, 'overlay1 and overlay3 have the same backdrop element');
 
914
        });
 
915
 
 
916
        test('only one iron-overlay-backdrop in the DOM', function() {
 
917
          // Open them all.
 
918
          overlay1.opened = overlay2.opened = overlay3.opened = true;
 
919
          assert.lengthOf(document.querySelectorAll('iron-overlay-backdrop'), 1, 'only one backdrop element in the DOM');
 
920
        });
 
921
 
 
922
        test('iron-overlay-backdrop is removed from the DOM when all overlays with backdrop are closed', function(done) {
 
923
          // Open & close them all.
 
924
          overlay1.opened = overlay2.opened = overlay3.opened = true;
 
925
          overlay1.opened = overlay2.opened = overlay3.opened = false;
 
926
          Polymer.Base.async(function() {
 
927
            assert.lengthOf(document.querySelectorAll('iron-overlay-backdrop'), 0, 'backdrop element removed from the DOM');
 
928
            done();
 
929
          }, 100);
 
930
        });
 
931
 
 
932
        test('newest overlay appear on top', function(done) {
 
933
          runAfterOpen(overlay1, function() {
 
934
            runAfterOpen(overlay2, function() {
 
935
              var styleZ = parseInt(window.getComputedStyle(overlay1).zIndex, 10);
 
936
              var style1Z = parseInt(window.getComputedStyle(overlay2).zIndex, 10);
 
937
              var bgStyleZ = parseInt(window.getComputedStyle(overlay1.backdropElement).zIndex, 10);
 
938
              assert.isTrue(style1Z > styleZ, 'overlay2 has higher z-index than overlay1');
 
939
              assert.isTrue(styleZ > bgStyleZ, 'overlay1 has higher z-index than backdrop');
 
940
              done();
 
941
            });
 
942
          });
 
943
        });
 
944
 
 
945
        test('click events handled only by top overlay', function(done) {
 
946
          var btn = document.createElement('button');
 
947
          btn.addEventListener('tap', overlay2.close.bind(overlay2));
 
948
          Polymer.dom(overlay2).appendChild(btn);
 
949
          runAfterOpen(overlay1, function() {
 
950
            runAfterOpen(overlay2, function() {
 
951
              MockInteractions.tap(btn);
 
952
              assert.isFalse(overlay2.opened, 'overlay2 closed');
 
953
              assert.isTrue(overlay1.opened, 'overlay1 still opened');
 
954
              done();
 
955
            });
 
956
          });
 
957
        });
 
958
 
 
959
        test('updating with-backdrop updates z-index', function(done) {
 
960
          runAfterOpen(overlay1, function() {
 
961
            runAfterOpen(overlay2, function() {
 
962
              overlay1.withBackdrop = false;
 
963
              var styleZ = parseInt(window.getComputedStyle(overlay1).zIndex, 10);
 
964
              var style1Z = parseInt(window.getComputedStyle(overlay2).zIndex, 10);
 
965
              var bgStyleZ = parseInt(window.getComputedStyle(overlay1.backdropElement).zIndex, 10);
 
966
              assert.isTrue(style1Z > bgStyleZ, 'overlay2 has higher z-index than backdrop');
 
967
              assert.isTrue(styleZ < bgStyleZ, 'overlay1 has lower z-index than backdrop');
 
968
              done();
 
969
            });
 
970
          });
 
971
        });
 
972
 
 
973
      });
 
974
 
 
975
      suite('overlay in composed tree', function() {
 
976
        test('click on overlay content does not close it', function(done) {
 
977
          var composed = fixture('composed');
 
978
          // Opens overlay.
 
979
          MockInteractions.tap(composed.$.trigger);
 
980
          composed.$.dropdown.addEventListener('iron-overlay-opened', function() {
 
981
            // Tap on button inside overlay.
 
982
            MockInteractions.tap(Polymer.dom(composed).querySelector('button'));
 
983
            Polymer.Base.async(function(){
 
984
              assert.isTrue(composed.$.dropdown.opened, 'overlay still opened');
 
985
              done();
 
986
            }, 1);
 
987
          });
 
988
        });
 
989
 
 
990
      });
 
991
 
 
992
      suite('always-on-top', function() {
 
993
        var overlay1, overlay2;
 
994
 
 
995
        setup(function() {
 
996
          var f = fixture('multiple');
 
997
          overlay1 = f[0];
 
998
          overlay2 = f[1];
 
999
          overlay1.alwaysOnTop = true;
 
1000
        });
 
1001
 
 
1002
        test('stays on top', function(done) {
 
1003
          runAfterOpen(overlay1, function() {
 
1004
            runAfterOpen(overlay2, function() {
 
1005
              var zIndex1 = parseInt(window.getComputedStyle(overlay1).zIndex, 10);
 
1006
              var zIndex2 = parseInt(window.getComputedStyle(overlay2).zIndex, 10);
 
1007
              assert.isAbove(zIndex1, zIndex2, 'overlay1 on top');
 
1008
              assert.equal(Polymer.IronOverlayManager.currentOverlay(), overlay1, 'currentOverlay ok');
 
1009
              done();
 
1010
            });
 
1011
          });
 
1012
        });
 
1013
 
 
1014
        test('stays on top also if another overlay is with-backdrop', function(done) {
 
1015
          overlay2.withBackdrop = true;
 
1016
          runAfterOpen(overlay1, function() {
 
1017
            runAfterOpen(overlay2, function() {
 
1018
              var zIndex1 = parseInt(window.getComputedStyle(overlay1).zIndex, 10);
 
1019
              var zIndex2 = parseInt(window.getComputedStyle(overlay2).zIndex, 10);
 
1020
              assert.isAbove(zIndex1, zIndex2, 'overlay1 on top');
 
1021
              assert.equal(Polymer.IronOverlayManager.currentOverlay(), overlay1, 'currentOverlay ok');
 
1022
              done();
 
1023
            });
 
1024
          });
 
1025
        });
 
1026
 
 
1027
        test('last overlay with always-on-top wins', function(done) {
 
1028
          overlay2.alwaysOnTop = true;
 
1029
          runAfterOpen(overlay1, function() {
 
1030
            runAfterOpen(overlay2, function() {
 
1031
              var zIndex1 = parseInt(window.getComputedStyle(overlay1).zIndex, 10);
 
1032
              var zIndex2 = parseInt(window.getComputedStyle(overlay2).zIndex, 10);
 
1033
              assert.isAbove(zIndex2, zIndex1, 'overlay2 on top');
 
1034
              assert.equal(Polymer.IronOverlayManager.currentOverlay(), overlay2, 'currentOverlay ok');
 
1035
              done();
 
1036
            });
 
1037
          });
 
1038
        });
 
1039
 
 
1040
      });
 
1041
 
 
1042
      suite('animations', function() {
 
1043
 
 
1044
        test('overlay animations correctly triggered', function(done) {
 
1045
          var overlay = fixture('basic');
 
1046
          overlay.animated = true;
 
1047
          overlay.open();
 
1048
          overlay.addEventListener('simple-overlay-open-animation-start', function() {
 
1049
            // Since animated overlay will transition center + 300px to center,
 
1050
            // we should not find the element at the center when the open animation starts.
 
1051
            var centerElement = document.elementFromPoint(window.innerWidth/2, window.innerHeight/2);
 
1052
            assert.notEqual(centerElement, overlay, 'overlay should not be centered already');
 
1053
            done();
 
1054
          });
 
1055
        });
 
1056
 
 
1057
      });
 
1058
 
 
1059
      suite('a11y', function() {
 
1060
 
 
1061
        test('overlay has aria-hidden=true when opened', function() {
 
1062
          var overlay = fixture('basic');
 
1063
          assert.equal(overlay.getAttribute('aria-hidden'), 'true', 'overlay has aria-hidden="true"');
 
1064
          overlay.open();
 
1065
          assert.isFalse(overlay.hasAttribute('aria-hidden'), 'overlay does not have aria-hidden attribute');
 
1066
          overlay.close();
 
1067
          assert.equal(overlay.getAttribute('aria-hidden'), 'true', 'overlay has aria-hidden="true"');
 
1068
        });
 
1069
 
 
1070
      });
 
1071
    </script>
 
1072
 
 
1073
  </body>
 
1074
 
 
1075
</html>