chromium/chrome/browser/resources/chromeos/accessibility/chromevox/background/input/keyboard_handler_test.js

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Include test fixture.
GEN_INCLUDE(['../../testing/chromevox_e2e_test_base.js']);

/**
 * Test fixture for ChromeVox KeyboardHandler.
 */
ChromeVoxBackgroundKeyboardHandlerTest = class extends ChromeVoxE2ETest {
  /** @override */
  async setUpDeferred() {
    await super.setUpDeferred();

    await Promise.all([
      // Alphabetical based on file path.
      importModule('ChromeVox', '/chromevox/background/chromevox.js'),
      importModule(
          'ChromeVoxRange', '/chromevox/background/chromevox_range.js'),
      importModule(
          'ChromeVoxState', '/chromevox/background/chromevox_state.js'),
      importModule(
          'BackgroundKeyboardHandler',
          '/chromevox/background/input/background_keyboard_handler.js'),
      importModule('KeyCode', '/common/key_code.js'),
    ]);

    globalThis.keyboardHandler = BackgroundKeyboardHandler.instance;
  }
};


AX_TEST_F(
    'ChromeVoxBackgroundKeyboardHandlerTest', 'SearchGetsPassedThrough',
    async function() {
      await this.runWithLoadedTree('<p>test</p>');
      // A Search keydown gets eaten.
      const searchDown = {};
      searchDown.preventDefault = this.newCallback();
      searchDown.stopPropagation = this.newCallback();
      searchDown.metaKey = true;
      keyboardHandler.onKeyDown(searchDown);
      assertEquals(1, keyboardHandler.eatenKeyDowns_.size);

      // A Search keydown does not get eaten when there's no range and there
      // was no previous range. TalkBack is handled elsewhere.
      ChromeVoxRange.set(null);
      ChromeVoxRange.instance.previous_ = null;
      const searchDown2 = {};
      searchDown2.metaKey = true;
      keyboardHandler.onKeyDown(searchDown2);
      assertEquals(1, keyboardHandler.eatenKeyDowns_.size);
    });

AX_TEST_F(
    'ChromeVoxBackgroundKeyboardHandlerTest', 'PassThroughMode',
    async function() {
      await this.runWithLoadedTree('<p>test</p>');
      assertFalse(BackgroundKeyboardHandler.passThroughModeEnabled_);
      assertEquals('no_pass_through', keyboardHandler.passThroughState_);
      assertEquals(0, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size);

      // Send the pass through command: Search+Shift+Escape.
      const search =
          TestUtils.createMockKeyEvent(KeyCode.SEARCH, {metaKey: true});
      keyboardHandler.onKeyDown(search);
      assertEquals(1, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size);
      assertEquals('no_pass_through', keyboardHandler.passThroughState_);
      assertFalse(BackgroundKeyboardHandler.passThroughModeEnabled_);

      const searchShift = TestUtils.createMockKeyEvent(
          KeyCode.SHIFT, {metaKey: true, shiftKey: true});
      keyboardHandler.onKeyDown(searchShift);
      assertEquals(2, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size);
      assertEquals('no_pass_through', keyboardHandler.passThroughState_);
      assertFalse(BackgroundKeyboardHandler.passThroughModeEnabled_);

      const searchShiftEsc = TestUtils.createMockKeyEvent(
          KeyCode.ESCAPE, {metaKey: true, shiftKey: true});
      keyboardHandler.onKeyDown(searchShiftEsc);
      assertEquals(3, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size);
      assertEquals(
          'pending_pass_through_keyups', keyboardHandler.passThroughState_);
      assertTrue(BackgroundKeyboardHandler.passThroughModeEnabled_);

      keyboardHandler.onKeyUp(searchShiftEsc);
      assertEquals(2, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size);
      assertEquals(
          'pending_pass_through_keyups', keyboardHandler.passThroughState_);
      assertTrue(BackgroundKeyboardHandler.passThroughModeEnabled_);

      const searchShiftUp = TestUtils.createMockKeyEvent(
          KeyCode.SHIFT, {metaKey: true, shiftKey: false});
      keyboardHandler.onKeyUp(searchShiftUp);
      assertEquals(1, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size);
      assertEquals(
          'pending_pass_through_keyups', keyboardHandler.passThroughState_);
      assertTrue(BackgroundKeyboardHandler.passThroughModeEnabled_);

      const searchUp =
          TestUtils.createMockKeyEvent(KeyCode.SEARCH, {metaKey: false});
      keyboardHandler.onKeyUp(searchUp);
      assertEquals(0, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size);
      assertEquals(
          'pending_shortcut_keyups', keyboardHandler.passThroughState_);
      assertTrue(BackgroundKeyboardHandler.passThroughModeEnabled_);

      // Now, the next series of key downs should be passed through.
      // Try Search+Ctrl+M.
      keyboardHandler.onKeyDown(search);
      assertEquals(0, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(1, keyboardHandler.passedThroughKeyDowns_.size);
      assertEquals(
          'pending_shortcut_keyups', keyboardHandler.passThroughState_);
      assertTrue(BackgroundKeyboardHandler.passThroughModeEnabled_);

      const searchCtrl = TestUtils.createMockKeyEvent(
          KeyCode.CONTROL, {metaKey: true, ctrlKey: true});
      keyboardHandler.onKeyDown(searchCtrl);
      assertEquals(0, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(2, keyboardHandler.passedThroughKeyDowns_.size);
      assertEquals(
          'pending_shortcut_keyups', keyboardHandler.passThroughState_);
      assertTrue(BackgroundKeyboardHandler.passThroughModeEnabled_);

      const searchCtrlM = TestUtils.createMockKeyEvent(
          KeyCode.M, {metaKey: true, ctrlKey: true});
      keyboardHandler.onKeyDown(searchCtrlM);
      assertEquals(0, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(3, keyboardHandler.passedThroughKeyDowns_.size);
      assertEquals(
          'pending_shortcut_keyups', keyboardHandler.passThroughState_);
      assertTrue(BackgroundKeyboardHandler.passThroughModeEnabled_);

      keyboardHandler.onKeyUp(searchCtrlM);
      assertEquals(0, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(2, keyboardHandler.passedThroughKeyDowns_.size);
      assertEquals(
          'pending_shortcut_keyups', keyboardHandler.passThroughState_);
      assertTrue(BackgroundKeyboardHandler.passThroughModeEnabled_);

      keyboardHandler.onKeyUp(searchCtrl);
      assertEquals(0, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(1, keyboardHandler.passedThroughKeyDowns_.size);
      assertEquals(
          'pending_shortcut_keyups', keyboardHandler.passThroughState_);
      assertTrue(BackgroundKeyboardHandler.passThroughModeEnabled_);

      keyboardHandler.onKeyUp(search);
      assertEquals(0, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size);
      assertEquals('no_pass_through', keyboardHandler.passThroughState_);
      assertFalse(BackgroundKeyboardHandler.passThroughModeEnabled_);
    });

AX_TEST_F(
    'ChromeVoxBackgroundKeyboardHandlerTest', 'PassThroughModeOff',
    async function() {
      await this.runWithLoadedTree('<p>test</p>');
      function assertNoPassThrough() {
        assertFalse(BackgroundKeyboardHandler.passThroughModeEnabled_);
        assertEquals('no_pass_through', keyboardHandler.passThroughState_);
        assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size);
      }

      // Send some random keys; ensure the pass through state variables never
      // change.
      const search =
          TestUtils.createMockKeyEvent(KeyCode.SEARCH, {metaKey: true});
      keyboardHandler.onKeyDown(search);
      assertNoPassThrough();

      const searchShift = TestUtils.createMockKeyEvent(
          KeyCode.SHIFT, {metaKey: true, shiftKey: true});
      keyboardHandler.onKeyDown(searchShift);
      assertNoPassThrough();

      const searchShiftM = TestUtils.createMockKeyEvent(
          KeyCode.M, {metaKey: true, shiftKey: true});
      keyboardHandler.onKeyDown(searchShiftM);
      assertNoPassThrough();

      keyboardHandler.onKeyUp(searchShiftM);
      assertNoPassThrough();

      keyboardHandler.onKeyUp(searchShift);
      assertNoPassThrough();

      keyboardHandler.onKeyUp(search);
      assertNoPassThrough();

      keyboardHandler.onKeyDown(TestUtils.createMockKeyEvent(KeyCode.A));
      assertNoPassThrough();

      keyboardHandler.onKeyDown(
          TestUtils.createMockKeyEvent(KeyCode.A, {altKey: true}));
      assertNoPassThrough();

      keyboardHandler.onKeyUp(
          TestUtils.createMockKeyEvent(KeyCode.A, {altKey: true}));
      assertNoPassThrough();
    });

AX_TEST_F(
    'ChromeVoxBackgroundKeyboardHandlerTest', 'UnexpectedKeyDownUpPairs',
    async function() {
      await this.runWithLoadedTree('<p>test</p>');
      // Send a few key downs.
      const search =
          TestUtils.createMockKeyEvent(KeyCode.SEARCH, {metaKey: true});
      keyboardHandler.onKeyDown(search);
      assertEquals(1, keyboardHandler.eatenKeyDowns_.size);

      const searchShift = TestUtils.createMockKeyEvent(
          KeyCode.SHIFT, {metaKey: true, shiftKey: true});
      keyboardHandler.onKeyDown(searchShift);
      assertEquals(2, keyboardHandler.eatenKeyDowns_.size);

      const searchShiftM = TestUtils.createMockKeyEvent(
          KeyCode.M, {metaKey: true, shiftKey: true});
      keyboardHandler.onKeyDown(searchShiftM);
      assertEquals(3, keyboardHandler.eatenKeyDowns_.size);

      // Now, send a key down, but no modifiers set, which is impossible to
      // actually press. This key is not eaten.
      const m = TestUtils.createMockKeyEvent(KeyCode.M, {});
      keyboardHandler.onKeyDown(m);
      assertEquals(0, keyboardHandler.eatenKeyDowns_.size);

      // To demonstrate eaten keys still work, send Search by itself, which is
      // always eaten.
      keyboardHandler.onKeyDown(search);
      assertEquals(1, keyboardHandler.eatenKeyDowns_.size);
    });

AX_TEST_F(
    'ChromeVoxBackgroundKeyboardHandlerTest',
    'UnexpectedKeyDownUpPairsPassThrough', async function() {
      await this.runWithLoadedTree('<p>test</p>');
      // Force pass through mode.
      BackgroundKeyboardHandler.passThroughModeEnabled_ = true;

      // Send a few key downs (which are passed through).
      const search =
          TestUtils.createMockKeyEvent(KeyCode.SEARCH, {metaKey: true});
      keyboardHandler.onKeyDown(search);
      assertEquals(0, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(1, keyboardHandler.passedThroughKeyDowns_.size);

      const searchShift = TestUtils.createMockKeyEvent(
          KeyCode.SHIFT, {metaKey: true, shiftKey: true});
      keyboardHandler.onKeyDown(searchShift);
      assertEquals(0, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(2, keyboardHandler.passedThroughKeyDowns_.size);

      const searchShiftM = TestUtils.createMockKeyEvent(
          KeyCode.M, {metaKey: true, shiftKey: true});
      keyboardHandler.onKeyDown(searchShiftM);
      assertEquals(0, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(3, keyboardHandler.passedThroughKeyDowns_.size);

      // Now, send a key down, but no modifiers set, which is impossible to
      // actually press. This is passed through, so the count resets to 1.
      const m = TestUtils.createMockKeyEvent(KeyCode.M, {});
      keyboardHandler.onKeyDown(m);
      assertEquals(0, keyboardHandler.eatenKeyDowns_.size);
      assertEquals(1, keyboardHandler.passedThroughKeyDowns_.size);
    });