Home | History | Annotate | Download | only in test
      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   <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
     15   <title>iron-a11y-keys</title>
     16 
     17   <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
     18   <script src="../../web-component-tester/browser.js"></script>
     19   <script src="../../iron-test-helpers/mock-interactions.js"></script>
     20 
     21   <link rel="import" href="../../polymer/polymer.html">
     22   <link rel="import" href="../iron-a11y-keys-behavior.html">
     23 </head>
     24 <body>
     25   <test-fixture id="BasicKeys">
     26     <template>
     27       <x-a11y-basic-keys></x-a11y-basic-keys>
     28     </template>
     29   </test-fixture>
     30 
     31   <test-fixture id="NonPropagatingKeys">
     32     <template>
     33       <x-a11y-basic-keys stop-keyboard-event-propagation></x-a11y-basic-keys>
     34     </template>
     35   </test-fixture>
     36 
     37   <test-fixture id="ComboKeys">
     38     <template>
     39       <x-a11y-combo-keys></x-a11y-combo-keys>
     40     </template>
     41   </test-fixture>
     42 
     43   <test-fixture id="AlternativeEventKeys">
     44     <template>
     45       <x-a11y-alternate-event-keys></x-a11y-alternate-event-keys>
     46     </template>
     47   </test-fixture>
     48 
     49   <test-fixture id="BehaviorKeys">
     50     <template>
     51       <x-a11y-behavior-keys></x-a11y-behavior-keys>
     52     </template>
     53   </test-fixture>
     54 
     55   <test-fixture id="PreventKeys">
     56     <template>
     57       <x-a11y-prevent-keys></x-a11y-prevent-keys>
     58     </template>
     59   </test-fixture>
     60 
     61   <script>
     62 suite('Polymer.IronA11yKeysBehavior', function() {
     63   var keys;
     64 
     65   suiteSetup(function() {
     66     var KeysTestBehavior = [Polymer.IronA11yKeysBehavior, {
     67       properties: {
     68         keyCount: {
     69           type: Number,
     70           value: 0
     71         }
     72       },
     73 
     74       _keyHandler: function(event) {
     75         this.keyCount++;
     76         this.lastEvent = event;
     77       },
     78 
     79       // Same as _keyHandler, used to distinguish who's called before who.
     80       _keyHandler2: function(event) {
     81         this.keyCount++;
     82         this.lastEvent = event;
     83       },
     84 
     85       _preventDefaultHandler: function(event) {
     86         event.preventDefault();
     87         this.keyCount++;
     88         this.lastEvent = event;
     89       }
     90     }];
     91 
     92     Polymer({
     93       is: 'x-a11y-basic-keys',
     94 
     95       behaviors: [
     96         KeysTestBehavior
     97       ],
     98 
     99       keyBindings: {
    100         'space': '_keyHandler',
    101         '@': '_keyHandler',
    102         'esc': '_keyHandler'
    103       }
    104     });
    105 
    106     Polymer({
    107       is: 'x-a11y-combo-keys',
    108 
    109       behaviors: [
    110         KeysTestBehavior
    111       ],
    112 
    113       keyBindings: {
    114         'enter': '_keyHandler2',
    115         'ctrl+shift+a shift+enter': '_keyHandler'
    116       }
    117     });
    118 
    119     Polymer({
    120       is: 'x-a11y-alternate-event-keys',
    121 
    122       behaviors: [
    123         KeysTestBehavior
    124       ],
    125 
    126       keyBindings: {
    127         'space:keyup': '_keyHandler'
    128       }
    129     });
    130 
    131     var XA11yBehavior = {
    132       keyBindings: {
    133         'enter': '_keyHandler'
    134       }
    135     };
    136 
    137     Polymer({
    138       is: 'x-a11y-behavior-keys',
    139 
    140       behaviors: [
    141         KeysTestBehavior,
    142         XA11yBehavior
    143       ],
    144 
    145       keyBindings: {
    146         'enter': '_keyHandler'
    147       }
    148     });
    149 
    150     Polymer({
    151       is: 'x-a11y-prevent-keys',
    152 
    153       behaviors: [
    154         KeysTestBehavior,
    155         XA11yBehavior
    156       ],
    157 
    158       keyBindings: {
    159         'space a': '_keyHandler',
    160         'enter shift+a': '_preventDefaultHandler'
    161       }
    162     });
    163   });
    164 
    165   suite('basic keys', function() {
    166     setup(function() {
    167       keys = fixture('BasicKeys');
    168     });
    169 
    170     test('trigger the handler when the specified key is pressed', function() {
    171       MockInteractions.pressSpace(keys);
    172 
    173       expect(keys.keyCount).to.be.equal(1);
    174     });
    175 
    176     test('keyEventTarget can be null, and disables listeners', function() {
    177       keys.keyEventTarget = null;
    178       MockInteractions.pressSpace(keys);
    179 
    180       expect(keys.keyCount).to.be.equal(0);
    181     });
    182 
    183     test('trigger the handler when the specified key is pressed together with a modifier', function() {
    184       var event = new CustomEvent('keydown');
    185       event.ctrlKey = true;
    186       event.keyCode = event.code = 32;
    187       keys.dispatchEvent(event);
    188       expect(keys.keyCount).to.be.equal(1);
    189     });
    190 
    191     test('handles special character @', function() {
    192       MockInteractions.pressAndReleaseKeyOn(keys, undefined, [], '@');
    193 
    194       expect(keys.keyCount).to.be.equal(1);
    195     });
    196 
    197     test('handles variations of Esc key', function() {
    198       MockInteractions.pressAndReleaseKeyOn(keys, undefined, [], 'Esc');
    199       expect(keys.keyCount).to.be.equal(1);
    200 
    201       MockInteractions.pressAndReleaseKeyOn(keys, undefined, [], 'Escape');
    202       expect(keys.keyCount).to.be.equal(2);
    203 
    204       MockInteractions.pressAndReleaseKeyOn(keys, 27, [], '');
    205       expect(keys.keyCount).to.be.equal(3);
    206     });
    207 
    208     test('do not trigger the handler for non-specified keys', function() {
    209       MockInteractions.pressEnter(keys);
    210 
    211       expect(keys.keyCount).to.be.equal(0);
    212     });
    213 
    214     test('can have bindings added imperatively', function() {
    215       keys.addOwnKeyBinding('enter', '_keyHandler');
    216 
    217       MockInteractions.pressEnter(keys);
    218       expect(keys.keyCount).to.be.equal(1);
    219 
    220       MockInteractions.pressSpace(keys);
    221       expect(keys.keyCount).to.be.equal(2);
    222     });
    223 
    224     test('can remove imperatively added bindings', function() {
    225       keys.addOwnKeyBinding('enter', '_keyHandler');
    226       keys.removeOwnKeyBindings();
    227 
    228       MockInteractions.pressEnter(keys);
    229       expect(keys.keyCount).to.be.equal(0);
    230 
    231       MockInteractions.pressSpace(keys);
    232       expect(keys.keyCount).to.be.equal(1);
    233     });
    234 
    235     test('allows propagation beyond the key combo handler', function() {
    236       var keySpy = sinon.spy();
    237       document.addEventListener('keydown', keySpy);
    238 
    239       MockInteractions.pressEnter(keys);
    240 
    241       expect(keySpy.callCount).to.be.equal(1);
    242     });
    243 
    244     suite('edge cases', function() {
    245       test('knows that `spacebar` is the same as `space`', function() {
    246         var event = new CustomEvent('keydown');
    247         event.key = 'spacebar';
    248         expect(keys.keyboardEventMatchesKeys(event, 'space')).to.be.equal(true);
    249       });
    250 
    251       test('handles `+`', function() {
    252         var event = new CustomEvent('keydown');
    253         event.key = '+';
    254         expect(keys.keyboardEventMatchesKeys(event, '+')).to.be.equal(true);
    255       });
    256 
    257       test('handles `:`', function() {
    258         var event = new CustomEvent('keydown');
    259         event.key = ':';
    260         expect(keys.keyboardEventMatchesKeys(event, ':')).to.be.equal(true);
    261       });
    262 
    263       test('handles ` ` (space)', function() {
    264         var event = new CustomEvent('keydown');
    265         event.key = ' ';
    266         expect(keys.keyboardEventMatchesKeys(event, 'space')).to.be.equal(true);
    267       });
    268     });
    269 
    270     suite('matching keyboard events to keys', function() {
    271       test('can be done imperatively', function() {
    272         var event = new CustomEvent('keydown');
    273         event.keyCode = 65;
    274         expect(keys.keyboardEventMatchesKeys(event, 'a')).to.be.equal(true);
    275       });
    276 
    277       test('can be done with a provided keyboardEvent', function() {
    278         var event;
    279         MockInteractions.pressSpace(keys);
    280         event = keys.lastEvent;
    281 
    282         expect(event.detail.keyboardEvent).to.be.okay;
    283         expect(keys.keyboardEventMatchesKeys(event, 'space')).to.be.equal(true);
    284       });
    285 
    286       test('can handle variations in arrow key names', function() {
    287         var event = new CustomEvent('keydown');
    288         event.key = 'up';
    289         expect(keys.keyboardEventMatchesKeys(event, 'up')).to.be.equal(true);
    290         event.key = 'ArrowUp';
    291         expect(keys.keyboardEventMatchesKeys(event, 'up')).to.be.equal(true);
    292       });
    293     });
    294 
    295     suite('matching keyboard events to top row and number pad digit keys', function() {
    296       test('top row can be done imperatively', function() {
    297         var event = new CustomEvent('keydown');
    298         event.keyCode = 49;
    299         expect(keys.keyboardEventMatchesKeys(event, '1')).to.be.equal(true);
    300       });
    301 
    302       test('number pad digits can be done imperatively', function() {
    303         var event = new CustomEvent('keydown');
    304         event.keyCode = 97;
    305         expect(keys.keyboardEventMatchesKeys(event, '1')).to.be.equal(true);
    306       });
    307     });
    308   });
    309 
    310   suite('combo keys', function() {
    311     setup(function() {
    312       keys = fixture('ComboKeys');
    313     });
    314 
    315     test('trigger the handler when the combo is pressed', function() {
    316       var event = new CustomEvent('keydown');
    317 
    318       event.ctrlKey = true;
    319       event.shiftKey = true;
    320       event.keyCode = event.code = 65;
    321 
    322       keys.dispatchEvent(event);
    323 
    324       expect(keys.keyCount).to.be.equal(1);
    325     });
    326 
    327     test('check if KeyBoardEvent.key is alpha-numberic', function() {
    328       var event = new CustomEvent('keydown');
    329 
    330       event.ctrlKey = true;
    331       event.shiftKey = true;
    332       event.key = '';
    333       event.keyCode = event.code = 65;
    334 
    335       keys.dispatchEvent(event);
    336 
    337       expect(keys.keyCount).to.be.equal(1);
    338     });
    339 
    340     test('trigger also bindings without modifiers', function() {
    341       var event = new CustomEvent('keydown');
    342       // Combo `shift+enter`.
    343       event.shiftKey = true;
    344       event.keyCode = event.code = 13;
    345       keys.dispatchEvent(event);
    346       expect(keys.keyCount).to.be.equal(2);
    347     });
    348 
    349     test('give precendence to combos with modifiers', function() {
    350       var enterSpy = sinon.spy(keys, '_keyHandler2');
    351       var shiftEnterSpy = sinon.spy(keys, '_keyHandler');
    352       var event = new CustomEvent('keydown');
    353       // Combo `shift+enter`.
    354       event.shiftKey = true;
    355       event.keyCode = event.code = 13;
    356       keys.dispatchEvent(event);
    357       expect(enterSpy.called).to.be.true;
    358       expect(shiftEnterSpy.called).to.be.true;
    359       expect(enterSpy.calledAfter(shiftEnterSpy)).to.be.true;
    360     });
    361 
    362   });
    363 
    364   suite('alternative event keys', function() {
    365     setup(function() {
    366       keys = fixture('AlternativeEventKeys');
    367     });
    368 
    369     test('trigger on the specified alternative keyboard event', function() {
    370       MockInteractions.keyDownOn(keys, 32);
    371 
    372       expect(keys.keyCount).to.be.equal(0);
    373 
    374       MockInteractions.keyUpOn(keys, 32);
    375 
    376       expect(keys.keyCount).to.be.equal(1);
    377     });
    378   });
    379 
    380   suite('behavior keys', function() {
    381     setup(function() {
    382       keys = fixture('BehaviorKeys');
    383     });
    384 
    385     test('bindings in other behaviors are transitive', function() {
    386       MockInteractions.pressEnter(keys);
    387       expect(keys.keyCount).to.be.equal(2);
    388     });
    389   });
    390 
    391   suite('stopping propagation automatically', function() {
    392     setup(function() {
    393       keys = fixture('NonPropagatingKeys');
    394     });
    395 
    396     test('does not propagate key events beyond the combo handler', function() {
    397       var keySpy = sinon.spy();
    398 
    399       document.addEventListener('keydown', keySpy);
    400 
    401       MockInteractions.pressEnter(keys);
    402 
    403       expect(keySpy.callCount).to.be.equal(0);
    404     });
    405   });
    406 
    407   suite('prevent default behavior of event', function() {
    408     setup(function() {
    409       keys = fixture('PreventKeys');
    410     });
    411 
    412     test('`defaultPrevented` is correctly set', function() {
    413       MockInteractions.pressEnter(keys);
    414       expect(keys.lastEvent.defaultPrevented).to.be.equal(true);
    415     });
    416 
    417     test('only 1 handler is invoked', function() {
    418       var aSpy = sinon.spy(keys, '_keyHandler');
    419       var shiftASpy = sinon.spy(keys, '_preventDefaultHandler');
    420       var event = new CustomEvent('keydown', {
    421         cancelable: true
    422       });
    423       // Combo `shift+a`.
    424       event.shiftKey = true;
    425       event.keyCode = event.code = 65;
    426       keys.dispatchEvent(event);
    427 
    428       expect(keys.keyCount).to.be.equal(1);
    429       expect(shiftASpy.called).to.be.true;
    430       expect(aSpy.called).to.be.false;
    431     });
    432   });
    433 
    434   suite('remove key behavior with null target', function () {
    435     test('add and remove a iron-a11y-keys-behavior', function () {
    436       var element = document.createElement('x-a11y-basic-keys');
    437       element.keyEventTarget = null;
    438       document.body.appendChild(element);
    439       document.body.removeChild(element);
    440     });
    441   });
    442 
    443 });
    444   </script>
    445 </body>
    446 </html>
    447