chromium/chrome/test/data/webui/settings/memory_page_test.ts

// Copyright 2024 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://settings/settings.js';

import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import type {CrCollapseElement, SettingsRadioGroupElement} from 'chrome://settings/lazy_load.js';
import type {SettingsMemoryPageElement} from 'chrome://settings/settings.js';
import {MEMORY_SAVER_MODE_AGGRESSIVENESS_PREF, MEMORY_SAVER_MODE_PREF, MemorySaverModeAggressiveness, MemorySaverModeState, PerformanceMetricsProxyImpl} from 'chrome://settings/settings.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';

import {TestPerformanceMetricsProxy} from './test_performance_metrics_proxy.js';

const memorySaverModeMockPrefs = {
  high_efficiency_mode: {
    state: {
      type: chrome.settingsPrivate.PrefType.NUMBER,
      value: MemorySaverModeState.DISABLED,
    },
    aggressiveness: {
      type: chrome.settingsPrivate.PrefType.NUMBER,
      value: MemorySaverModeAggressiveness.MEDIUM,
    },
  },
};

suite('MemorySaver', function() {
  let memoryPage: SettingsMemoryPageElement;
  let performanceMetricsProxy: TestPerformanceMetricsProxy;

  setup(function() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;

    performanceMetricsProxy = new TestPerformanceMetricsProxy();
    PerformanceMetricsProxyImpl.setInstance(performanceMetricsProxy);

    memoryPage = document.createElement('settings-memory-page');
    memoryPage.set('prefs', {
      performance_tuning: {
        ...memorySaverModeMockPrefs,
      },
    });
    document.body.appendChild(memoryPage);
    flush();
  });

  test('testMemorySaverModeEnabled', function() {
    memoryPage.setPrefValue(
        MEMORY_SAVER_MODE_PREF, MemorySaverModeState.ENABLED);
    assertTrue(memoryPage.$.toggleButton.checked);
  });

  test('testMemorySaverModeDisabled', function() {
    memoryPage.setPrefValue(
        MEMORY_SAVER_MODE_PREF, MemorySaverModeState.DISABLED);
    assertFalse(memoryPage.$.toggleButton.checked);
  });

  test('testMemorySaverModeChangeState', async function() {
    memoryPage.setPrefValue(
        MEMORY_SAVER_MODE_PREF, MemorySaverModeState.DISABLED);

    memoryPage.$.toggleButton.click();
    let state = await performanceMetricsProxy.whenCalled(
        'recordMemorySaverModeChanged');
    assertEquals(state, MemorySaverModeState.ENABLED);
    assertEquals(
        memoryPage.getPref(MEMORY_SAVER_MODE_PREF).value,
        MemorySaverModeState.ENABLED);

    performanceMetricsProxy.reset();
    memoryPage.$.toggleButton.click();
    state = await performanceMetricsProxy.whenCalled(
        'recordMemorySaverModeChanged');
    assertEquals(state, MemorySaverModeState.DISABLED);
    assertEquals(
        memoryPage.getPref(MEMORY_SAVER_MODE_PREF).value,
        MemorySaverModeState.DISABLED);
  });
});

suite('MemorySaverAggressiveness', function() {
  let memoryPage: SettingsMemoryPageElement;
  let performanceMetricsProxy: TestPerformanceMetricsProxy;
  let conservativeButton: HTMLElement;
  let mediumButton: HTMLElement;
  let aggressiveButton: HTMLElement;
  let radioGroup: SettingsRadioGroupElement;
  let radioGroupCollapse: CrCollapseElement;

  /**
   * Used to get elements from the performance page that may or may not exist,
   * such as those inside a dom-if.
   * TODO(charlesmeng): remove once MemorySaverModeAggressiveness flag is
   * cleaned up, since elements can then be selected with $ interface
   */
  function getMemoryPageElement<T extends HTMLElement = HTMLElement>(
      id: string): T {
    const el = memoryPage.shadowRoot!.querySelector<T>(`#${id}`);
    assertTrue(!!el);
    assertTrue(el instanceof HTMLElement);
    return el;
  }

  setup(function() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;

    performanceMetricsProxy = new TestPerformanceMetricsProxy();
    PerformanceMetricsProxyImpl.setInstance(performanceMetricsProxy);

    memoryPage = document.createElement('settings-memory-page');
    memoryPage.set('prefs', {
      performance_tuning: {
        ...memorySaverModeMockPrefs,
      },
    });
    document.body.appendChild(memoryPage);
    flush();

    conservativeButton = getMemoryPageElement('conservativeButton');
    mediumButton = getMemoryPageElement('mediumButton');
    aggressiveButton = getMemoryPageElement('aggressiveButton');
    radioGroup = getMemoryPageElement('radioGroup');
    radioGroupCollapse = getMemoryPageElement('radioGroupCollapse');
  });

  test('testMemorySaverModeDisabled', function() {
    memoryPage.setPrefValue(
        MEMORY_SAVER_MODE_PREF, MemorySaverModeState.DISABLED);
    assertFalse(memoryPage.$.toggleButton.checked);
    assertFalse(radioGroupCollapse.opened);
  });

  test('testMemorySaverModeEnabled', function() {
    memoryPage.setPrefValue(
        MEMORY_SAVER_MODE_PREF, MemorySaverModeState.ENABLED);
    assertTrue(memoryPage.$.toggleButton.checked);
    assertTrue(radioGroupCollapse.opened);
    assertEquals(
        String(MemorySaverModeAggressiveness.MEDIUM), radioGroup.selected);
  });

  test('testMemorySaverModeChangeState', async function() {
    async function testMemorySaverModeChangeState(
        expectedState: MemorySaverModeState) {
      performanceMetricsProxy.reset();
      memoryPage.$.toggleButton.click();

      const state = await performanceMetricsProxy.whenCalled(
          'recordMemorySaverModeChanged');
      assertEquals(state, expectedState);
      assertEquals(
          memoryPage.getPref(MEMORY_SAVER_MODE_PREF).value, expectedState);
    }

    async function testMemorySaverModeChangeAggressiveness(
        button: HTMLElement,
        expectedAggressiveness: MemorySaverModeAggressiveness) {
      performanceMetricsProxy.reset();
      button.click();

      const aggressiveness = await performanceMetricsProxy.whenCalled(
          'recordMemorySaverModeAggressivenessChanged');
      assertEquals(aggressiveness, expectedAggressiveness);
      assertEquals(
          memoryPage.getPref(MEMORY_SAVER_MODE_AGGRESSIVENESS_PREF).value,
          expectedAggressiveness);
    }

    memoryPage.setPrefValue(
        MEMORY_SAVER_MODE_PREF, MemorySaverModeState.DISABLED);
    memoryPage.setPrefValue(
        MEMORY_SAVER_MODE_AGGRESSIVENESS_PREF,
        MemorySaverModeAggressiveness.MEDIUM);

    await testMemorySaverModeChangeState(MemorySaverModeState.ENABLED);

    await testMemorySaverModeChangeAggressiveness(
        aggressiveButton, MemorySaverModeAggressiveness.AGGRESSIVE);

    await testMemorySaverModeChangeAggressiveness(
        conservativeButton, MemorySaverModeAggressiveness.CONSERVATIVE);

    await testMemorySaverModeChangeAggressiveness(
        mediumButton, MemorySaverModeAggressiveness.MEDIUM);

    await testMemorySaverModeChangeState(MemorySaverModeState.DISABLED);
  });

  test('testMemorySaverModeAggressiveness', function() {
    function assertMemorySaverModeAggressivenessPolicyIndicatorExists(
        mode: MemorySaverModeAggressiveness, el: HTMLElement) {
      memoryPage.setPrefValue(MEMORY_SAVER_MODE_AGGRESSIVENESS_PREF, mode);
      flush();
      assertTrue(!!el.shadowRoot!.querySelector('cr-policy-pref-indicator'));
    }

    memoryPage.setPrefValue(
        MEMORY_SAVER_MODE_PREF, MemorySaverModeState.ENABLED);
    memoryPage.set(`prefs.${MEMORY_SAVER_MODE_AGGRESSIVENESS_PREF}`, {
      enforcement: chrome.settingsPrivate.Enforcement.ENFORCED,
      controlledBy: chrome.settingsPrivate.ControlledBy.USER_POLICY,
      type: chrome.settingsPrivate.PrefType.NUMBER,
      value: MemorySaverModeAggressiveness.MEDIUM,
    });

    assertMemorySaverModeAggressivenessPolicyIndicatorExists(
        MemorySaverModeAggressiveness.CONSERVATIVE, conservativeButton);

    assertMemorySaverModeAggressivenessPolicyIndicatorExists(
        MemorySaverModeAggressiveness.MEDIUM, mediumButton);

    assertMemorySaverModeAggressivenessPolicyIndicatorExists(
        MemorySaverModeAggressiveness.AGGRESSIVE, aggressiveButton);
  });
});