chromium/chrome/test/data/webui/cr_elements/cr_profile_avatar_selector_test.ts

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

// clang-format off
import 'chrome://resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js';

import type {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js';
import type {CrProfileAvatarSelectorElement} from 'chrome://resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js';
import {getDeepActiveElement} from 'chrome://resources/js/util.js';
import {keyDownOn, pressAndReleaseKeyOn} from 'chrome://webui-test/keyboard_mock_interactions.js';
import {assertEquals, assertFalse, assertNull, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {eventToPromise, microtasksFinished} from 'chrome://webui-test/test_util.js';
// clang-format on

/** @fileoverview Suite of tests for cr-profile-avatar-selector. */
suite('cr-profile-avatar-selector', function() {
  let avatarSelector: CrProfileAvatarSelectorElement;

  function createElement(): CrProfileAvatarSelectorElement {
    const avatarSelector = document.createElement('cr-profile-avatar-selector');
    avatarSelector.avatars = [
      {
        url: 'chrome://avatar1.png',
        label: 'avatar1',
        index: 1,
        selected: false,
        isGaiaAvatar: false,
      },
      {
        url: 'chrome://avatar2.png',
        label: 'avatar2',
        index: 2,
        selected: false,
        isGaiaAvatar: false,
      },
      {
        url: 'chrome://avatar3.png',
        label: 'avatar3',
        index: 3,
        selected: false,
        isGaiaAvatar: false,
      },
    ];
    return avatarSelector;
  }

  function getGridItems() {
    return avatarSelector.shadowRoot!.querySelectorAll<CrButtonElement>(
        '.avatar');
  }

  function verifyTabIndex(
      items: NodeListOf<CrButtonElement>, tabIndexArr: number[]) {
    assertEquals(items.length, tabIndexArr.length);
    for (let i = 0; i < items.length; i++) {
      assertEquals(items[i]!.tabIndex, tabIndexArr[i]);
    }
  }

  setup(function() {
    avatarSelector = createElement();
    document.body.appendChild(avatarSelector);
  });

  teardown(function() {
    avatarSelector.remove();
  });

  test('Displays avatars', function() {
    assertEquals(3, getGridItems().length);
  });

  test('No avatar is initially selected', function() {
    assertNull(avatarSelector.selectedAvatar);
    getGridItems().forEach(function(item) {
      assertFalse(item.parentElement!.classList.contains('iron-selected'));
    });
  });

  test('No avatar initially selected', async function() {
    const items = getGridItems();
    assertEquals(items.length, 3);
    // First element of the grid should get the focus on 'tab' key.
    verifyTabIndex(items, [0, -1, -1]);

    // Tab key should not move the focus.
    items[0]!.focus();
    pressAndReleaseKeyOn(items[0]!, 9);
    assertEquals(getDeepActiveElement(), items[0]);

    keyDownOn(items[0]!, 39, [], 'ArrowRight');
    assertEquals(getDeepActiveElement(), items[1]);

    items[1]!.click();
    await microtasksFinished();
    assertTrue(items[1]!.parentElement!.classList.contains('iron-selected'));
    verifyTabIndex(items, [-1, 0, -1]);
  });

  test('Avatar already selected', async function() {
    let items = getGridItems();
    verifyTabIndex(items, [0, -1, -1]);
    avatarSelector.avatars = [
      {
        url: 'chrome://avatar1.png',
        label: 'avatar1',
        index: 1,
        selected: false,
        isGaiaAvatar: false,
      },
      {
        url: 'chrome://avatar2.png',
        label: 'avatar2',
        index: 2,
        selected: true,
        isGaiaAvatar: false,
      },
    ];
    await microtasksFinished();
    items = getGridItems();
    assertTrue(items[1]!.parentElement!.classList.contains('iron-selected'));
    verifyTabIndex(items, [-1, 0]);

    items[0]!.click();
    await microtasksFinished();
    assertTrue(items[0]!.parentElement!.classList.contains('iron-selected'));
    verifyTabIndex(items, [0, -1]);
  });

  test('Avatar selected by setting selectedAvatar', async function() {
    const items = getGridItems();
    verifyTabIndex(items, [0, -1, -1]);
    avatarSelector.selectedAvatar = avatarSelector.avatars[1]!;
    await microtasksFinished();
    verifyTabIndex(getGridItems(), [-1, 0, -1]);

    items[0]!.click();
    await microtasksFinished();
    assertTrue(items[0]!.parentElement!.classList.contains('iron-selected'));
    verifyTabIndex(items, [0, -1, -1]);
  });

  test('Can select avatar', async function() {
    const items = getGridItems();

    // Simulate tapping the third avatar.
    items[2]!.click();
    await microtasksFinished();
    assertEquals('chrome://avatar3.png', avatarSelector.selectedAvatar!.url);
    assertFalse(items[0]!.parentElement!.classList.contains('iron-selected'));
    assertFalse(items[1]!.parentElement!.classList.contains('iron-selected'));
    assertTrue(items[2]!.parentElement!.classList.contains('iron-selected'));
  });

  test('selected-avatar-changed fires', async function() {
    const items = getGridItems();
    items[2]!.click();
    const e = await eventToPromise('selected-avatar-changed', avatarSelector);
    assertEquals(avatarSelector.avatars[2], e.detail.value);
  });

  test('sets ignoreModifiedKeyEvents', async function() {
    const grid = avatarSelector.shadowRoot!.querySelector('cr-grid');
    assertTrue(!!grid);

    assertFalse(avatarSelector.ignoreModifiedKeyEvents);
    assertFalse(grid.ignoreModifiedKeyEvents);

    avatarSelector.ignoreModifiedKeyEvents = true;
    await microtasksFinished();
    assertTrue(grid.ignoreModifiedKeyEvents);
  });
});