chromium/chrome/test/data/webui/chromeos/settings/device_page/per_device_touchpad_subsection_test.ts

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

import 'chrome://os-settings/os_settings.js';

import {CrToggleElement, FakeInputDeviceSettingsProvider, fakeTouchpads, Router, routes, setInputDeviceSettingsProviderForTesting, SettingsDropdownMenuElement, SettingsPerDeviceTouchpadSubsectionElement, SettingsSliderElement, SettingsToggleButtonElement, SimulateRightClickModifier} from 'chrome://os-settings/os_settings.js';
import {assert} from 'chrome://resources/js/assert.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {pressAndReleaseKeyOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
import {isVisible} from 'chrome://webui-test/test_util.js';

const TOUCHPAD_SPEED_SETTING_ID = 405;

suite('<settings-per-device-touchpad-subsection>', () => {
  let subsection: SettingsPerDeviceTouchpadSubsectionElement;
  let provider: FakeInputDeviceSettingsProvider;

  setup(async () => {
    loadTimeData.overrideValues({
      enableAltClickAndSixPackCustomization: true,
    });
    provider = new FakeInputDeviceSettingsProvider();
    provider.setFakeTouchpads(fakeTouchpads);
    setInputDeviceSettingsProviderForTesting(provider);
    subsection =
        document.createElement('settings-per-device-touchpad-subsection');
    assert(subsection);
    subsection.set('touchpad', {...fakeTouchpads[0]});
    document.body.appendChild(subsection);
    await flushTasks();
  });

  teardown(() => {
    subsection.remove();
  });

  function simulateDropdownChange(modifier: SimulateRightClickModifier) {
    subsection.set('simulateRightClickPref.value', modifier);
    return flushTasks();
  }

  /**
   * Test that API are updated when touchpad settings change.
   */
  test('Update API when touchpad settings change', async () => {
    const enableTapToClickButton =
        subsection.shadowRoot!.querySelector<SettingsToggleButtonElement>(
            '#enableTapToClick');
    assert(enableTapToClickButton);
    enableTapToClickButton.click();
    await flushTasks();
    let updatedTouchpads = await provider.getConnectedTouchpadSettings();
    assertEquals(
        updatedTouchpads[0]!.settings.tapToClickEnabled,
        enableTapToClickButton.pref!.value);

    const enableTapDraggingButton =
        subsection.shadowRoot!.querySelector<SettingsToggleButtonElement>(
            '#enableTapDragging');
    assert(enableTapDraggingButton);
    enableTapDraggingButton.click();
    await flushTasks();
    updatedTouchpads = await provider.getConnectedTouchpadSettings();
    assertEquals(
        updatedTouchpads[0]!.settings.tapDraggingEnabled,
        enableTapDraggingButton.pref!.value);

    const touchpadAccelerationButton =
        subsection.shadowRoot!.querySelector<SettingsToggleButtonElement>(
            '#touchpadAcceleration');
    assert(touchpadAccelerationButton);
    touchpadAccelerationButton.click();
    await flushTasks();
    updatedTouchpads = await provider.getConnectedTouchpadSettings();
    assertEquals(
        updatedTouchpads[0]!.settings.accelerationEnabled,
        touchpadAccelerationButton.pref!.value);

    const touchpadSensitivitySlider =
        subsection.shadowRoot!.querySelector<SettingsSliderElement>(
            '#touchpadSensitivity');
    assert(touchpadSensitivitySlider);
    pressAndReleaseKeyOn(
        touchpadSensitivitySlider.shadowRoot!.querySelector('cr-slider')!, 39,
        [], 'ArrowRight');
    await flushTasks();
    updatedTouchpads = await provider.getConnectedTouchpadSettings();
    assertEquals(
        updatedTouchpads[0]!.settings.sensitivity,
        touchpadSensitivitySlider.pref!.value);

    const touchpadHapticClickSensitivitySlider =
        subsection.shadowRoot!.querySelector<SettingsSliderElement>(
            '#touchpadHapticClickSensitivity');
    assert(touchpadHapticClickSensitivitySlider);
    pressAndReleaseKeyOn(
        touchpadHapticClickSensitivitySlider.shadowRoot!.querySelector(
            'cr-slider')!,
        39, [], 'ArrowRight');
    await flushTasks();
    updatedTouchpads = await provider.getConnectedTouchpadSettings();
    assertEquals(
        updatedTouchpads[0]!.settings.hapticSensitivity,
        touchpadHapticClickSensitivitySlider.pref!.value);

    const touchpadHapticFeedbackToggleButton =
        subsection.shadowRoot!.querySelector<CrToggleElement>(
            '#touchpadHapticFeedbackToggle');
    touchpadHapticFeedbackToggleButton!.click();
    await flushTasks();
    updatedTouchpads = await provider.getConnectedTouchpadSettings();
    assertEquals(
        updatedTouchpads[0]!.settings.hapticEnabled,
        touchpadHapticFeedbackToggleButton!.checked);

    const touchpadReverseScrollToggleButton =
        subsection.shadowRoot!.querySelector<CrToggleElement>(
            '#enableReverseScrollingToggle');
    touchpadReverseScrollToggleButton!.click();
    await flushTasks();
    updatedTouchpads = await provider.getConnectedTouchpadSettings();
    assertEquals(
        updatedTouchpads[0]!.settings.reverseScrolling,
        touchpadReverseScrollToggleButton!.checked);
  });

  /**
   * Test that touchpad settings data are from the touchpad provider.
   */
  test('Verify touchpad settings data', async () => {
    let enableTapToClickButton =
        subsection.shadowRoot!.querySelector<SettingsToggleButtonElement>(
            '#enableTapToClick');
    assertEquals(
        fakeTouchpads[0]!.settings.tapToClickEnabled,
        enableTapToClickButton!.pref!.value);
    let enableTapDraggingButton =
        subsection.shadowRoot!.querySelector<SettingsToggleButtonElement>(
            '#enableTapDragging');
    assertEquals(
        fakeTouchpads[0]!.settings.tapDraggingEnabled,
        enableTapDraggingButton!.pref!.value);
    let touchpadAcceleration =
        subsection.shadowRoot!.querySelector<SettingsToggleButtonElement>(
            '#touchpadAcceleration');
    assertEquals(
        fakeTouchpads[0]!.settings.accelerationEnabled,
        touchpadAcceleration!.pref!.value);
    let touchpadSensitivitySlider =
        subsection.shadowRoot!.querySelector<SettingsSliderElement>(
            '#touchpadSensitivity');
    assertEquals(
        fakeTouchpads[0]!.settings.sensitivity,
        touchpadSensitivitySlider!.pref!.value);
    let touchpadHapticClickSensitivitySlider =
        subsection.shadowRoot!.querySelector<SettingsSliderElement>(
            '#touchpadHapticClickSensitivity');
    assertTrue(isVisible(touchpadHapticClickSensitivitySlider));
    assertEquals(
        fakeTouchpads[0]!.settings.hapticSensitivity,
        touchpadHapticClickSensitivitySlider!.pref!.value);
    let touchpadHapticFeedbackToggleButton =
        subsection.shadowRoot!.querySelector<CrToggleElement>(
            '#touchpadHapticFeedbackToggle');
    assertTrue(isVisible(touchpadHapticFeedbackToggleButton));
    assertEquals(
        fakeTouchpads[0]!.settings.hapticEnabled,
        touchpadHapticFeedbackToggleButton!.checked);
    assertEquals(
        fakeTouchpads[0]!.settings.reverseScrolling,
        subsection.get('reverseScrollValue'));

    subsection.set('touchpad', fakeTouchpads[1]);

    await flushTasks();
    enableTapToClickButton =
        subsection.shadowRoot!.querySelector('#enableTapToClick');
    assertEquals(
        fakeTouchpads[1]!.settings.tapToClickEnabled,
        enableTapToClickButton!.pref!.value);
    enableTapDraggingButton =
        subsection.shadowRoot!.querySelector('#enableTapDragging');
    assertEquals(
        fakeTouchpads[1]!.settings.tapDraggingEnabled,
        enableTapDraggingButton!.pref!.value);
    touchpadAcceleration =
        subsection.shadowRoot!.querySelector('#touchpadAcceleration');
    assertEquals(
        fakeTouchpads[1]!.settings.accelerationEnabled,
        touchpadAcceleration!.pref!.value);
    touchpadSensitivitySlider =
        subsection.shadowRoot!.querySelector('#touchpadSensitivity');
    assertEquals(
        fakeTouchpads[1]!.settings.sensitivity,
        touchpadSensitivitySlider!.pref!.value);
    touchpadHapticClickSensitivitySlider =
        subsection.shadowRoot!.querySelector('#touchpadHapticClickSensitivity');
    assertFalse(isVisible(touchpadHapticClickSensitivitySlider));
    touchpadHapticFeedbackToggleButton =
        subsection.shadowRoot!.querySelector('#touchpadHapticFeedbackToggle');
    assertFalse(isVisible(touchpadHapticFeedbackToggleButton));
    assertEquals(
        fakeTouchpads[1]!.settings.reverseScrolling,
        subsection.get('reverseScrollValue'));
  });

  /**
   * Test haptic settings are correctly show or hidden based on the touchpad is
   * haptic or not.
   */
  test('Verify haptic settings visibility', async () => {
    // Change the isHaptic state to true.
    subsection.set('touchpad.isHaptic', true);
    await flushTasks();
    // Verify haptic click sensitivity slider is visible in the page.
    let hapticClickSensitivitySlider =
        subsection.shadowRoot!.querySelector<SettingsSliderElement>(
            '#touchpadHapticClickSensitivity');
    assertTrue(isVisible(hapticClickSensitivitySlider));

    // Verify haptic feedback toggle button is visible in the page.
    let hapticFeedbackToggleButton =
        subsection.shadowRoot!.querySelector('#touchpadHapticFeedbackToggle');
    assertTrue(isVisible(hapticFeedbackToggleButton));

    // Change the isHaptic state to false.
    subsection.set('touchpad.isHaptic', false);
    await flushTasks();
    // Verify haptic click sensitivity slider is not visible in the page.
    hapticClickSensitivitySlider =
        subsection.shadowRoot!.querySelector('#touchpadHapticClickSensitivity');
    assertFalse(isVisible(hapticClickSensitivitySlider));

    // Verify haptic feedback toggle button is not visible in the page.
    hapticFeedbackToggleButton =
        subsection.shadowRoot!.querySelector('#touchpadHapticFeedbackToggle');
    assertFalse(isVisible(hapticFeedbackToggleButton));
  });

  /**
   * Verify entering the page with search tags matched will auto focus the
   * searched element.
   */
  test('Deep linking mixin focus on the first searched element', async () => {
    const touchpadSensitivitySlider =
        subsection.shadowRoot!.querySelector<SettingsSliderElement>(
            '#touchpadSensitivity');
    subsection.set('touchpadIndex', 0);
    // Enter the page from auto repeat search tag.
    const url = new URLSearchParams(
        'search=touchpad+speed&settingId=' +
        encodeURIComponent(TOUCHPAD_SPEED_SETTING_ID));

    await Router.getInstance().navigateTo(
        routes.PER_DEVICE_TOUCHPAD,
        /* dynamicParams= */ url, /* removeSearch= */ true);

    assert(touchpadSensitivitySlider);
    await waitAfterNextRender(touchpadSensitivitySlider);
    assertEquals(
        touchpadSensitivitySlider, subsection.shadowRoot!.activeElement);
  });

  /**
   * Verify entering the page with search tags matched wll not auto focus the
   * searched element if it's not the first keyboard displayed.
   */
  test('Deep linkng mixin does not focus on second element', async () => {
    const touchpadSensitivitySlider =
        subsection.shadowRoot!.querySelector<SettingsSliderElement>(
            '#touchpadSensitivity');
    subsection.set('touchpadIndex', 1);
    // Enter the page from auto repeat search tag.
    const url = new URLSearchParams(
        'search=touchpad+speed&settingId=' +
        encodeURIComponent(TOUCHPAD_SPEED_SETTING_ID));

    await Router.getInstance().navigateTo(
        routes.PER_DEVICE_TOUCHPAD,
        /* dynamicParams= */ url, /* removeSearch= */ true);
    await flushTasks();

    assert(touchpadSensitivitySlider);
    assertEquals(null, subsection.shadowRoot!.activeElement);
  });

  test('Simulate right click dropdown', async () => {
    assertTrue(isVisible(
        subsection.shadowRoot!.querySelector('#simulateRightClickContainer')));
    const simulateRightClickDropdown =
        subsection.shadowRoot!.querySelector<SettingsDropdownMenuElement>(
            '#simulateRightClickDropdown');
    assertTrue(!!simulateRightClickDropdown);
    // Dropdown has the correct default value.
    assertEquals(
        Number(simulateRightClickDropdown.$.dropdownMenu.value),
        SimulateRightClickModifier.kNone);
    await simulateDropdownChange(SimulateRightClickModifier.kAlt);
    assertEquals(
        Number(simulateRightClickDropdown.$.dropdownMenu.value),
        SimulateRightClickModifier.kAlt);
  });
});