chromium/chrome/browser/resources/chromeos/accessibility/chromevox/panel/menu_manager_test.js

// Copyright 2023 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(['panel_test_base.js']);

/** Test fixture for MenuManager. */
ChromeVoxMenuManagerTest = class extends ChromeVoxPanelTestBase {
  getMenuManager() {
    return this.getPanel().instance.getMenuManagerForTesting();
  }
};

AX_TEST_F('ChromeVoxMenuManagerTest', 'ActiveMenu', async function() {
  await this.runWithLoadedTree('');
  new PanelCommand(PanelCommandType.OPEN_MENUS).send();
  await this.waitForMenu('panel_search_menu');

  const menuManager = this.getMenuManager();
  const searchMenu = menuManager.activeMenu_;
  const chromevoxMenu = menuManager.getSelectedMenu('panel_menu_chromevox');
  assertEquals('panel_menu_chromevox', chromevoxMenu.menuMsg);

  // Set a pending callback so we can tell if it was cleared.
  this.getPanel().instance.setPendingCallback(() => {});
  assertNotNullNorUndefined(this.getPanel().instance.pendingCallback_);

  menuManager.activateMenu(chromevoxMenu);
  assertEquals(chromevoxMenu, menuManager.activeMenu_);
  assertEquals(-1, searchMenu.activeIndex_);
  // Confirm the pending callback was cleared.
  assertNullOrUndefined(this.getPanel().instance.pendingCallback_);
});

AX_TEST_F('ChromeVoxMenuManagerTest', 'AddMenu', async function() {
  await this.runWithLoadedTree('');
  new PanelCommand(PanelCommandType.OPEN_MENUS).send();
  await this.waitForMenu('panel_search_menu');
  const searchMenu = this.getMenuManager().activeMenu_;

  // Msgs.getMsg() throws an error if the message is not a translated string.
  // Mock it out to avoid the error.
  this.getPanelWindow().Msgs.getMsg = () => '';

  // Confirm that |fake_menu| is not in the set of menus.
  assertFalse(
      this.getMenuManager().menus_.some(menu => menu.menuMsg === 'fake_menu'));

  const fakeMenu = this.getMenuManager().addMenu('fake_menu');
  assertEquals('fake_menu', fakeMenu.menuMsg);
  // Confirm that |fake_menu| is now in the menu list.
  assertTrue(
      this.getMenuManager().menus_.some(menu => menu.menuMsg === 'fake_menu'));
});

AX_TEST_F('ChromeVoxMenuManagerTest', 'AddNodeMenu', async function() {
  await this.runWithLoadedTree('');
  new PanelCommand(PanelCommandType.OPEN_MENUS).send();
  await this.waitForMenu('panel_search_menu');

  // Msgs.getMsg() throws an error if the message is not a translated string.
  // Mock it out to avoid the error.
  this.getPanelWindow().Msgs.getMsg = () => '';

  const data = {menuId: 6, titleId: 'fake_node'};
  this.getMenuManager().addNodeMenu(data);
  const fakeMenu = this.getMenuManager().getSelectedMenu('fake_node');

  // Ensure we didn't receive the default menu.
  assertEquals('fake_node', fakeMenu.menuMsg);
  assertEquals(fakeMenu, this.getMenuManager().nodeMenuDictionary_[6]);
});

AX_TEST_F('ChromeVoxMenuManagerTest', 'AdvanceActiveMenuBy', async function() {
  await this.runWithLoadedTree('');
  new PanelCommand(PanelCommandType.OPEN_MENUS).send();
  await this.waitForMenu('panel_search_menu');

  const menuManager = this.getMenuManager();
  const activeIndex = () =>
      menuManager.menus_.findIndex(menu => menu === menuManager.activeMenu_);
  assertEquals(0, activeIndex());

  // Forward with an active menu.
  menuManager.advanceActiveMenuBy(2);
  assertEquals(2, activeIndex());

  // Backward with an active menu.
  menuManager.advanceActiveMenuBy(-1);
  assertEquals(1, activeIndex());

  // Wrap around backwards.
  menuManager.advanceActiveMenuBy(-3);
  assertEquals(menuManager.menus_.length - 2, activeIndex());

  // Wrap around forwards.
  menuManager.advanceActiveMenuBy(4);
  assertEquals(2, activeIndex());

  // Forward with no active menu.
  menuManager.activeMenu_ = null;
  assertEquals(-1, activeIndex());

  menuManager.advanceActiveMenuBy(1);
  assertEquals(0, activeIndex());

  // Backward with no active menu.
  menuManager.activeMenu_ = null;
  assertEquals(-1, activeIndex());

  menuManager.advanceActiveMenuBy(-1);
  assertEquals(menuManager.menus_.length - 1, activeIndex());
});

AX_TEST_F('ChromeVoxMenuManagerTest', 'ClearMenus', async function() {
  await this.runWithLoadedTree('');
  new PanelCommand(PanelCommandType.OPEN_MENUS).send();
  await this.waitForMenu('panel_search_menu');

  const panelDoc = this.getPanelWindow().document;
  const menuBar = panelDoc.getElementById('menu-bar');
  assertNotEquals(0, menuBar.children.length);
  assertEquals('', this.getMenuManager().lastMenu_);
  assertNotEquals(null, this.getMenuManager().activeMenu_);

  this.getMenuManager().clearMenus();

  assertEquals(0, menuBar.children.length);
  assertEquals('panel_search_menu', this.getMenuManager().lastMenu_);
  assertEquals(null, this.getMenuManager().activeMenu_);
});

AX_TEST_F('ChromeVoxMenuManagerTest', 'DenySignedOut', async function() {
  await this.runWithLoadedTree('');
  new PanelCommand(PanelCommandType.OPEN_MENUS).send();
  await this.waitForMenu('panel_search_menu');

  const menuManager = this.getMenuManager();
  const someItemsAreDisabled = () =>
      menuManager.menus_.some(menu => menu.items.some(item => !item.enabled_));

  assertFalse(someItemsAreDisabled());
  menuManager.denySignedOut();
  assertTrue(someItemsAreDisabled());
});

AX_TEST_F('ChromeVoxMenuManagerTest', 'FindEnabledMenuIndex', async function() {
  await this.runWithLoadedTree('');
  new PanelCommand(PanelCommandType.OPEN_MENUS).send();
  await this.waitForMenu('panel_search_menu');

  const menuManager = this.getMenuManager();

  // Try forward and backward when all menus are enabled.
  let index = menuManager.findEnabledMenuIndex(0, 1);
  assertEquals(0, index);

  index = menuManager.findEnabledMenuIndex(1, -1);
  assertEquals(1, index);

  // Try forward and backward when no menus are enabled.
  menuManager.menus_.forEach(menu => menu.enabled_ = false);

  index = menuManager.findEnabledMenuIndex(2, 1);
  assertEquals(-1, index);

  index = menuManager.findEnabledMenuIndex(2, -1);
  assertEquals(-1, index);

  // Try forward and backward when one menu is enabled in that direction.
  menuManager.menus_[2].enabled_ = true;

  index = menuManager.findEnabledMenuIndex(0, 1);
  assertEquals(2, index);

  index = menuManager.findEnabledMenuIndex(menuManager.menus_.length - 1, -1);
  assertEquals(2, index);

  // Try forward and backward when there is one enabled menu, but in the
  // opposite direction.
  index = menuManager.findEnabledMenuIndex(3, 1);
  assertEquals(-1, index);

  index = menuManager.findEnabledMenuIndex(1, -1);
  assertEquals(-1, index);
});

AX_TEST_F('ChromeVoxMenuManagerTest', 'GetSortedKeyBindings', async function() {
  await this.runWithLoadedTree('');
  new PanelCommand(PanelCommandType.OPEN_MENUS).send();
  await this.waitForMenu('panel_search_menu');

  const keymapBindings = KeyMap.get().bindings();
  const sortedKeyBindings = await this.getMenuManager().getSortedKeyBindings();
  assertEquals(keymapBindings.length, sortedKeyBindings.length);

  for (const binding of sortedKeyBindings) {
    assertNotEquals('', binding.command);
    assertEquals('string', typeof binding.keySeq);
    assertEquals('string', typeof binding.title);
    assertTrue(keymapBindings.some(
        keyBinding => binding.sequence.equals(keyBinding.sequence)));
  }
});

AX_TEST_F('ChromeVoxMenuManagerTest', 'OnSearchBarQuery', async function() {
  await this.runWithLoadedTree('');
  new PanelCommand(PanelCommandType.OPEN_MENUS).send();
  await this.waitForMenu('panel_search_menu');

  const searchMenu = this.getMenuManager().searchMenu_;

  const expectSearchMenuCleared =
      this.prepareToExpectMethodCall(searchMenu, 'clear');
  const expectActivateMenu =
      this.prepareToExpectMethodCall(this.getMenuManager(), 'activateMenu');

  this.getMenuManager().onSearchBarQuery({target: {value: 'a'}});
  await this.waitForPendingMethods();
  expectSearchMenuCleared();
  expectActivateMenu();
  assertNotEquals(0, searchMenu.items.length);
});