chromium/chrome/browser/resources/chromeos/accessibility/chromevox/learn_mode/learn_mode_test.js

// Copyright 2020 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 Learn Mode page.
 */
ChromeVoxLearnModeTest = class extends ChromeVoxE2ETest {
  constructor() {
    super();
    globalThis.EventType = chrome.automation.EventType;
    globalThis.Gesture = chrome.accessibilityPrivate.Gesture;

    globalThis.doKeyDown = this.doKeyDown.bind(this);
    globalThis.doKeyUp = this.doKeyUp.bind(this);
    globalThis.doLearnModeGesture = this.doLearnModeGesture.bind(this);
    globalThis.doBrailleKeyEvent = this.doBrailleKeyEvent.bind(this);
  }

  async runOnLearnModePage() {
    return new Promise(async resolve => {
      const mockFeedback = this.createMockFeedback();
      const desktop = await AsyncUtil.getDesktop();
      function listener(evt) {
        if (evt.target.docUrl.indexOf('learn_mode/learn_mode.html') === -1 ||
            !evt.target.docLoaded) {
          return;
        }
        desktop.removeEventListener(
            chrome.automation.EventType.LOAD_COMPLETE, listener);

        mockFeedback.expectSpeech(/Press a qwerty key/);
        resolve([mockFeedback, evt]);
      }

      desktop.addEventListener(
          chrome.automation.EventType.LOAD_COMPLETE, listener);
      CommandHandlerInterface.instance.onCommand('showLearnModePage');
    });
  }

  makeMockKeyEvent(params) {
    // Fake out these functions.
    params.preventDefault = () => {};
    params.stopPropagation = () => {};

    // Set defaults if not defined.
    params.repeat = params.repeat || false;

    return params;
  }

  doKeyDown(evt) {
    return async () =>
               await LearnModeBridge.onKeyDown(this.makeMockKeyEvent(evt));
  }

  doKeyUp(evt) {
    return async () =>
               await LearnModeBridge.onKeyUp(this.makeMockKeyEvent(evt));
  }

  doLearnModeGesture(gesture) {
    return async () => await LearnModeBridge.onAccessibilityGesture(gesture);
  }

  doBrailleKeyEvent(evt) {
    return async () => await LearnModeBridge.onBrailleKeyEvent(evt);
  }
};

// TODO(crbug.com/1128926, crbug.com/1172387):
// Test times out flakily.
AX_TEST_F('ChromeVoxLearnModeTest', 'DISABLED_KeyboardInput', async function() {
  const [mockFeedback, evt] = await this.runOnLearnModePage();
  // Press Search+Right.
  mockFeedback.call(doKeyDown({keyCode: KeyCode.SEARCH, metaKey: true}))
      .expectSpeechWithQueueMode('Search', QueueMode.CATEGORY_FLUSH)
      .call(doKeyDown({keyCode: KeyCode.RIGHT, metaKey: true}))
      .expectSpeechWithQueueMode('Right arrow', QueueMode.QUEUE)
      .expectSpeechWithQueueMode('Next Object', QueueMode.QUEUE)
      .call(doKeyUp({keyCode: KeyCode.RIGHT, metaKey: true}))

      // Hit 'Right' again. We should get flushed output.
      .call(doKeyDown({keyCode: KeyCode.RIGHT, metaKey: true}))
      .expectSpeechWithQueueMode('Right arrow', QueueMode.CATEGORY_FLUSH)
      .expectSpeechWithQueueMode('Next Object', QueueMode.QUEUE)
      .call(doKeyUp({keyCode: KeyCode.RIGHT, metaKey: true}));

  await mockFeedback.replay();
});

AX_TEST_F('ChromeVoxLearnModeTest', 'KeyboardInputRepeat', async function() {
  const [mockFeedback, evt] = await this.runOnLearnModePage();
  // Press Search repeatedly.
  mockFeedback.call(doKeyDown({keyCode: KeyCode.SEARCH, metaKey: true}))
      .expectSpeechWithQueueMode('Search', QueueMode.CATEGORY_FLUSH)

      // This in theory should never happen (no repeat set).
      .call(doKeyDown({keyCode: KeyCode.SEARCH, metaKey: true}))
      .expectSpeechWithQueueMode('Search', QueueMode.QUEUE)

      // Hit Search again with the right underlying data. Then hit Control to
      // generate some speech.
      .call(doKeyDown({keyCode: KeyCode.SEARCH, metaKey: true, repeat: true}))
      .call(doKeyDown({keyCode: KeyCode.CONTROL, ctrlKey: true}))
      .expectNextSpeechUtteranceIsNot('Search')
      .expectSpeechWithQueueMode('Control', QueueMode.QUEUE);

  await mockFeedback.replay();
});

AX_TEST_F('ChromeVoxLearnModeTest', 'Gesture', async function() {
  const [mockFeedback, evt] = await this.runOnLearnModePage();
  await LearnModeBridge.clearTouchExploreOutputTime();
  mockFeedback.call(doLearnModeGesture(Gesture.SWIPE_RIGHT1))
      .expectSpeechWithQueueMode(
          'Swipe one finger right', QueueMode.CATEGORY_FLUSH)
      .expectSpeechWithQueueMode('Next Object', QueueMode.QUEUE)

      .call(doLearnModeGesture(Gesture.SWIPE_LEFT1))
      .expectSpeechWithQueueMode(
          'Swipe one finger left', QueueMode.CATEGORY_FLUSH)
      .expectSpeechWithQueueMode('Previous Object', QueueMode.QUEUE)

      .call(doLearnModeGesture(Gesture.TOUCH_EXPLORE))
      .expectSpeechWithQueueMode('Touch explore', QueueMode.CATEGORY_FLUSH)

      // Test for inclusion of commandDescriptionMsgId when provided.
      .call(doLearnModeGesture(Gesture.SWIPE_RIGHT2))
      .expectSpeechWithQueueMode(
          'Swipe two fingers right', QueueMode.CATEGORY_FLUSH)
      .expectSpeechWithQueueMode('Enter', QueueMode.QUEUE);

  await mockFeedback.replay();
});

AX_TEST_F('ChromeVoxLearnModeTest', 'Braille', async function() {
  const [mockFeedback, evt] = await this.runOnLearnModePage();
  // Hit the left panning hardware key on a braille display.
  mockFeedback.call(doBrailleKeyEvent({command: BrailleKeyCommand.PAN_LEFT}))
      .expectSpeechWithQueueMode('Pan backward', QueueMode.CATEGORY_FLUSH)
      .expectBraille('Pan backward')

      // Hit the backspace chord on a Perkins braille keyboard (aka dot 7).
      .call(doBrailleKeyEvent(
          {command: BrailleKeyCommand.CHORD, brailleDots: 0b1000000}))
      .expectSpeechWithQueueMode('Backspace', QueueMode.CATEGORY_FLUSH)
      .expectBraille('Backspace')

      // Hit a 'd' chord (Perkins keys dot 1-4-5).
      .call(doBrailleKeyEvent(
          {command: BrailleKeyCommand.CHORD, brailleDots: 0b011001}))
      .expectSpeechWithQueueMode('dots 1-4-5 chord', QueueMode.CATEGORY_FLUSH)
      .expectBraille('dots 1-4-5 chord');

  await mockFeedback.replay();
});

AX_TEST_F('ChromeVoxLearnModeTest', 'HardwareFunctionKeys', async function() {
  const [mockFeedback, evt] = await this.runOnLearnModePage();
  mockFeedback.call(doKeyDown({keyCode: KeyCode.BRIGHTNESS_UP}))
      .expectSpeechWithQueueMode('Brightness up', QueueMode.CATEGORY_FLUSH)
      .call(doKeyUp({keyCode: KeyCode.BRIGHTNESS_UP}))

      .call(doKeyDown({keyCode: KeyCode.SEARCH, metaKey: true}))
      .expectSpeechWithQueueMode('Search', QueueMode.CATEGORY_FLUSH)
      .call(doKeyDown({keyCode: KeyCode.BRIGHTNESS_UP, metaKey: true}))
      .expectSpeechWithQueueMode('Brightness up', QueueMode.QUEUE)
      .expectSpeechWithQueueMode('Toggle screen on or off', QueueMode.QUEUE)
      .call(doKeyUp({keyCode: KeyCode.BRIGHTNESS_UP, metaKey: true}))

      // Search+Volume Down has no associated command.
      .call(doKeyDown({keyCode: KeyCode.VOLUME_DOWN, metaKey: true}))
      .expectSpeechWithQueueMode('volume down', QueueMode.CATEGORY_FLUSH)
      .call(doKeyUp({keyCode: KeyCode.VOLUME_DOWN, metaKey: true}))

      // Search+Volume Mute does though.
      .call(doKeyDown({keyCode: KeyCode.VOLUME_MUTE, metaKey: true}))
      .expectSpeechWithQueueMode('volume mute', QueueMode.CATEGORY_FLUSH)
      .expectSpeechWithQueueMode('Toggle speech on or off', QueueMode.QUEUE);

  await mockFeedback.replay();
});

AX_TEST_F(
    'ChromeVoxLearnModeTest', 'CommandHandlersDisabled', async function() {
      const [mockFeedback, evt] = await this.runOnLearnModePage();
      await LearnModeBridge.ready();
      assertTrue(BrailleCommandHandler.instance.bypassed_);
      assertTrue(GestureCommandHandler.instance.bypassed_);
      await mockFeedback.replay();
    });