chromium/chrome/test/data/webui/bookmarks/dialog_focus_manager_test.ts

// 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.

import type {BookmarksCommandManagerElement, BookmarksItemElement, BookmarksListElement} from 'chrome://bookmarks/bookmarks.js';
import {DialogFocusManager, MenuSource} from 'chrome://bookmarks/bookmarks.js';
import {getDeepActiveElement} from 'chrome://resources/js/util.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {keyDownOn} from 'chrome://webui-test/keyboard_mock_interactions.js';
import {eventToPromise} from 'chrome://webui-test/test_util.js';

import {TestCommandManager} from './test_command_manager.js';
import {TestStore} from './test_store.js';
import {createFolder, createItem, getAllFoldersOpenState, replaceBody, testTree} from './test_util.js';


suite('DialogFocusManager', function() {
  let list: BookmarksListElement;
  let store: TestStore;
  let items: NodeListOf<BookmarksItemElement>;
  let commandManager: BookmarksCommandManagerElement;
  let dialogFocusManager: DialogFocusManager;

  function keydown(el: HTMLElement, key: string) {
    keyDownOn(el, 0, [], key);
  }

  setup(function() {
    const nodes = testTree(createFolder('1', [
      createItem('2'),
      createItem('3'),
      createItem('4'),
      createItem('5'),
      createItem('6'),
      createFolder('7', []),
    ]));
    store = new TestStore({
      nodes: nodes,
      folderOpenState: getAllFoldersOpenState(nodes),
      selectedFolder: '1',
    });
    store.setReducersEnabled(true);
    store.replaceSingleton();

    list = document.createElement('bookmarks-list');
    list.style.height = '100%';
    list.style.width = '100%';
    list.style.position = 'absolute';
    replaceBody(list);
    flush();
    items = list.shadowRoot!.querySelectorAll('bookmarks-item');

    commandManager = new TestCommandManager().getCommandManager();
    document.body.appendChild(commandManager);

    dialogFocusManager = new DialogFocusManager();
    DialogFocusManager.setInstance(dialogFocusManager);
  });

  test('restores focus on dialog dismissal', async function() {
    const focusedItem = items[0]!;
    focusedItem.focus();
    assertEquals(focusedItem, getDeepActiveElement());

    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
    const dropdown = commandManager.$.dropdown.getIfExists()!;

    assertTrue(dropdown.open);
    assertNotEquals(focusedItem, getDeepActiveElement());

    keydown(dropdown, 'Escape');
    assertFalse(dropdown.open);

    await eventToPromise('close', dropdown);

    assertEquals(focusedItem, getDeepActiveElement());
  });

  test('restores focus after stacked dialogs', async () => {
    const focusedItem = items[0]!;
    focusedItem.focus();
    assertEquals(focusedItem, getDeepActiveElement());

    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
    const dropdown = commandManager.$.dropdown.getIfExists();
    assertTrue(!!dropdown);

    const editDialog = commandManager.$.editDialog.get();
    editDialog.showEditDialog(store.data.nodes['2']!);
    dropdown.close();
    assertNotEquals(focusedItem, getDeepActiveElement());

    await eventToPromise('close', dropdown);
    editDialog.$.dialog.cancel();
    assertNotEquals(focusedItem, getDeepActiveElement());

    await eventToPromise('close', editDialog);
    assertEquals(focusedItem, getDeepActiveElement());
  });

  test('restores focus after multiple shows of same dialog', async () => {
    let focusedItem = items[0]!;
    focusedItem.focus();
    assertEquals(focusedItem, getDeepActiveElement());

    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
    assertNotEquals(focusedItem, getDeepActiveElement());
    const dropdown = commandManager.$.dropdown.getIfExists()!;
    dropdown.close();

    focusedItem = items[3]!;
    focusedItem.focus();
    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);

    await eventToPromise('close', dropdown);
    assertTrue(dropdown.open);
    assertNotEquals(focusedItem, getDeepActiveElement());
    dropdown.close();

    await eventToPromise('close', dropdown);
    assertEquals(focusedItem, getDeepActiveElement());
  });
});