chromium/chrome/test/data/webui/chromeos/settings/date_time_page/timezone_subpage_test.ts

// Copyright 2020 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/lazy_load.js';

import {SettingsRadioGroupElement, TimezoneSubpageElement} from 'chrome://os-settings/lazy_load.js';
import {CrSettingsPrefs, GeolocationAccessLevel, Router, routes} from 'chrome://os-settings/os_settings.js';
import {getDeepActiveElement} from 'chrome://resources/ash/common/util.js';
import {assert} from 'chrome://resources/js/assert.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.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';

let timezoneSubpage: TimezoneSubpageElement;

async function init(): Promise<void> {
  const prefElement = document.createElement('settings-prefs');
  document.body.appendChild(prefElement);

  await CrSettingsPrefs.initialized;
  timezoneSubpage = document.createElement('timezone-subpage');
  timezoneSubpage.prefs = {
    ...prefElement.prefs,
    ash: {
      user: {
        geolocation_access_level: {
          key: 'ash.user.geolocation_access_level',
          type: chrome.settingsPrivate.PrefType.NUMBER,
          value: GeolocationAccessLevel.ALLOWED,
        },
      },
    },
  };

  document.body.appendChild(timezoneSubpage);
  await flushTasks();
}

function testTeardown() {
  timezoneSubpage.remove();
  CrSettingsPrefs.resetForTesting();
  Router.getInstance().resetRouteForTesting();
}

suite('<timezone-subpage> with logged-in user', () => {
  setup(async () => {
    loadTimeData.overrideValues({canSetSystemTimezone: true});
    await init();
  });

  teardown(() => {
    testTeardown();
  });

  test('timezone radio group is enabled', async () => {
    // Enable automatic timezone.
    timezoneSubpage.setPrefValue(
        'generated.resolve_timezone_by_geolocation_on_off', true);
    await flushTasks();

    const timezoneRadioGroup =
        timezoneSubpage.shadowRoot!.querySelector<SettingsRadioGroupElement>(
            '#timeZoneRadioGroup');
    assert(timezoneRadioGroup);
    assertFalse(timezoneRadioGroup.disabled);
  });

  test('Timezone autodetect by geolocation radio', async () => {
    const timezoneRadioGroup =
        timezoneSubpage.shadowRoot!.querySelector<SettingsRadioGroupElement>(
            '#timeZoneRadioGroup');
    assert(timezoneRadioGroup);

    // Resolve timezone by geolocation is on.
    timezoneSubpage.setPrefValue(
        'generated.resolve_timezone_by_geolocation_on_off', true);
    await flushTasks();
    assertEquals('true', timezoneRadioGroup.selected);

    // Resolve timezone by geolocation is off.
    timezoneSubpage.setPrefValue(
        'generated.resolve_timezone_by_geolocation_on_off', false);
    await flushTasks();
    assertEquals('false', timezoneRadioGroup.selected);

    // Set timezone autodetect on by clicking the 'on' radio.
    const timezoneAutodetectOn =
        timezoneSubpage.shadowRoot!.querySelector<HTMLElement>(
            '#timeZoneAutoDetectOn');
    assert(timezoneAutodetectOn);
    timezoneAutodetectOn.click();
    assertTrue(timezoneSubpage
                   .getPref('generated.resolve_timezone_by_geolocation_on_off')
                   .value);

    // Turn timezone autodetect off by clicking the 'off' radio.
    const timezoneAutodetectOff =
        timezoneSubpage.shadowRoot!.querySelector<HTMLElement>(
            '#timeZoneAutoDetectOff');
    assert(timezoneAutodetectOff);
    timezoneAutodetectOff.click();
    assertFalse(timezoneSubpage
                    .getPref('generated.resolve_timezone_by_geolocation_on_off')
                    .value);
  });

  test('Deep link to time zone setter on subpage', async () => {
    // Resolve timezone by geolocation is on.
    timezoneSubpage.setPrefValue(
        'generated.resolve_timezone_by_geolocation_on_off', true);

    const params = new URLSearchParams();
    params.append('settingId', '1001');
    Router.getInstance().navigateTo(routes.DATETIME_TIMEZONE_SUBPAGE, params);

    const deepLinkElement =
        timezoneSubpage.shadowRoot!.querySelector('#timeZoneAutoDetectOn')!
            .shadowRoot!.querySelector<HTMLElement>('#button');
    assert(deepLinkElement);
    await waitAfterNextRender(deepLinkElement);
    assertEquals(
        deepLinkElement, getDeepActiveElement(),
        'Auto set time zone toggle should be focused for settingId=1001.');
  });

  test(
      'automatic timezone shows geolocation warning when location is disabled',
      async () => {
        const timezoneRadioGroup =
            timezoneSubpage.shadowRoot!
                .querySelector<SettingsRadioGroupElement>(
                    '#timeZoneRadioGroup');
        assert(timezoneRadioGroup);

        // Enable automatic timezone.
        timezoneSubpage.setPrefValue(
            'generated.resolve_timezone_by_geolocation_on_off', true);

        // Geolocation is allowed by default, the warning text should be hidden.
        assertFalse(isVisible(
            timezoneSubpage.shadowRoot!.querySelector('#warningText')));

        // Disable geolocation permission and check warning is shown.
        timezoneSubpage.setPrefValue(
            'ash.user.geolocation_access_level',
            GeolocationAccessLevel.DISALLOWED);
        await flushTasks();

        const warningText =
            timezoneSubpage.shadowRoot!.querySelector('#warningText');
        assertTrue(!!warningText);
        // Check that warning contains the link anchor.
        assertTrue(
            warningText?.getAttribute('warning-text-with-anchor')
                ?.includes('<a href="#">') ??
            false);
      });

  test(
      'time zone shows warning w/o hyperlink when location is managed',
      async () => {
        const timezoneRadioGroup =
            timezoneSubpage.shadowRoot!
                .querySelector<SettingsRadioGroupElement>(
                    '#timeZoneRadioGroup');
        assert(timezoneRadioGroup);

        // Enable automatic timezone.
        timezoneSubpage.setPrefValue(
            'generated.resolve_timezone_by_geolocation_on_off', true);
        // Geolocation is allowed by default, the warning text should be hidden.
        assertFalse(isVisible(
            timezoneSubpage.shadowRoot!.querySelector('#warningText')));

        // Set the geolocation pref to forced off, to replicate the policy
        // value.
        timezoneSubpage.setPrefValue(
            'ash.user.geolocation_access_level',
            GeolocationAccessLevel.DISALLOWED);
        timezoneSubpage.prefs.ash.user.geolocation_access_level.enforcement =
            chrome.settingsPrivate.Enforcement.ENFORCED;
        timezoneSubpage.notifyPath(
            'prefs.ash.user.geolocation_access_level.enforcement',
            chrome.settingsPrivate.Enforcement.ENFORCED);
        await flushTasks();

        const warningText =
            timezoneSubpage.shadowRoot!.querySelector('#warningText');
        assertTrue(!!warningText);
        // Check that the warning doesn't have clickable section to launch the
        // dialog.
        assertFalse(
            warningText?.getAttribute('warning-text-with-anchor')
                ?.includes('<a href="#">') ??
            false);
      });
});

suite('<timezone-subpage> with user who can not set system timezone', () => {
  setup(async () => {
    loadTimeData.overrideValues({canSetSystemTimezone: false});
    await init();
  });

  teardown(() => {
    testTeardown();
  });

  test('timezone radio group is disabled', async () => {
    // Enable automatic timezone.
    timezoneSubpage.setPrefValue(
        'generated.resolve_timezone_by_geolocation_on_off', true);
    await flushTasks();

    const timezoneRadioGroup =
        timezoneSubpage.shadowRoot!.querySelector<SettingsRadioGroupElement>(
            '#timeZoneRadioGroup');
    assert(timezoneRadioGroup);
    assertTrue(timezoneRadioGroup.disabled);
  });
});