| // Copyright 2015 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://settings/settings.js'; |
| |
| import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; |
| import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; |
| import type {SettingsToggleButtonElement} from 'chrome://settings/settings.js'; |
| import {DEFAULT_CHECKED_VALUE, DEFAULT_UNCHECKED_VALUE} from 'chrome://settings/settings.js'; |
| import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; |
| import {eventToPromise} from 'chrome://webui-test/test_util.js'; |
| // clang-format on |
| |
| /** @fileoverview Suite of tests for settings-toggle-button. */ |
| suite('SettingsToggleButton', () => { |
| let testElement: SettingsToggleButtonElement; |
| |
| // Initialize a checked control before each test. |
| setup(() => { |
| /** |
| * Pref value used in tests, should reflect the 'checked' attribute. |
| * Create a new pref for each test() to prevent order (state) |
| * dependencies between tests. |
| * @type {chrome.settingsPrivate.PrefObject} |
| */ |
| const pref = { |
| key: 'test', |
| type: chrome.settingsPrivate.PrefType.BOOLEAN, |
| value: true, |
| }; |
| document.body.innerHTML = window.trustedTypes!.emptyHTML; |
| testElement = document.createElement('settings-toggle-button'); |
| testElement.set('pref', pref); |
| document.body.appendChild(testElement); |
| }); |
| |
| test('value changes on click', () => { |
| assertTrue(testElement.checked); |
| assertTrue(testElement.pref!.value); |
| |
| testElement.click(); |
| assertFalse(testElement.checked); |
| assertFalse(testElement.pref!.value); |
| |
| testElement.click(); |
| assertTrue(testElement.checked); |
| assertTrue(testElement.pref!.value); |
| }); |
| |
| test('fires a change event', (done) => { |
| testElement.addEventListener('change', () => { |
| assertFalse(testElement.checked); |
| done(); |
| }); |
| assertTrue(testElement.checked); |
| testElement.click(); |
| }); |
| |
| test('fires a change event for label', (done) => { |
| testElement.addEventListener('change', () => { |
| assertFalse(testElement.checked); |
| done(); |
| }); |
| assertTrue(testElement.checked); |
| testElement.$.labelWrapper.click(); |
| }); |
| |
| test('fires a change event for toggle', (done) => { |
| testElement.addEventListener('change', () => { |
| assertFalse(testElement.checked); |
| done(); |
| }); |
| assertTrue(testElement.checked); |
| testElement.$.control.click(); |
| }); |
| |
| test('fires a single change event per tap', async () => { |
| let counter = 0; |
| testElement.addEventListener('change', () => { |
| ++counter; |
| }); |
| let whenFired = eventToPromise('change', testElement); |
| |
| testElement.click(); |
| await whenFired; |
| assertEquals(1, counter); |
| |
| whenFired = eventToPromise('change', testElement); |
| testElement.$.labelWrapper.click(); |
| await whenFired; |
| assertEquals(2, counter); |
| |
| whenFired = eventToPromise('change', testElement); |
| testElement.$.control.click(); |
| await whenFired; |
| assertEquals(3, counter); |
| }); |
| |
| test('does not change when disabled', () => { |
| testElement.checked = false; |
| testElement.setAttribute('disabled', ''); |
| assertTrue(testElement.disabled); |
| assertTrue(testElement.$.control.disabled); |
| |
| testElement.click(); |
| assertFalse(testElement.checked); |
| assertFalse(testElement.$.control.checked); |
| }); |
| |
| test('inverted', () => { |
| testElement.inverted = true; |
| testElement.set('pref', { |
| key: 'test', |
| type: chrome.settingsPrivate.PrefType.BOOLEAN, |
| value: true, |
| }); |
| |
| assertTrue(testElement.pref!.value); |
| assertFalse(testElement.checked); |
| |
| testElement.click(); |
| assertFalse(testElement.pref!.value); |
| assertTrue(testElement.checked); |
| |
| testElement.click(); |
| assertTrue(testElement.pref!.value); |
| assertFalse(testElement.checked); |
| }); |
| |
| test('numerical pref', () => { |
| const prefNum = { |
| key: 'test', |
| type: chrome.settingsPrivate.PrefType.NUMBER, |
| value: DEFAULT_CHECKED_VALUE, |
| }; |
| |
| testElement.set('pref', prefNum); |
| assertTrue(testElement.checked); |
| |
| testElement.click(); |
| assertFalse(testElement.checked); |
| assertEquals(DEFAULT_UNCHECKED_VALUE, prefNum.value); |
| |
| testElement.click(); |
| assertTrue(testElement.checked); |
| assertEquals(DEFAULT_CHECKED_VALUE, prefNum.value); |
| }); |
| |
| test('numerical pref with custom values', () => { |
| const UNCHECKED_VALUE_1 = 1; |
| const UNCHECKED_VALUE_2 = 2; |
| const CHECKED_VALUE = 3; |
| |
| const prefNum = { |
| key: 'test', |
| type: chrome.settingsPrivate.PrefType.NUMBER, |
| value: UNCHECKED_VALUE_2, |
| }; |
| |
| testElement.numericUncheckedValues = [UNCHECKED_VALUE_1, UNCHECKED_VALUE_2]; |
| testElement.numericCheckedValue = CHECKED_VALUE; |
| |
| // Test initial 'off' case. |
| testElement.set('pref', prefNum); |
| assertFalse(testElement.checked); |
| assertEquals(UNCHECKED_VALUE_2, prefNum.value); |
| |
| // Test 'off' -> 'on' case. |
| testElement.click(); |
| assertTrue(testElement.checked); |
| assertEquals(CHECKED_VALUE, prefNum.value); |
| |
| // Test 'on' -> 'off' case. |
| testElement.click(); |
| assertFalse(testElement.checked); |
| assertEquals(UNCHECKED_VALUE_1, prefNum.value); |
| }); |
| |
| const UNKNOWN_VALUE = 3; |
| |
| test('numerical pref with unknown initial value', () => { |
| const CUSTOM_UNCHECKED_VALUE = 5; |
| const CUSTOM_CHECKED_VALUE = 2; |
| |
| const prefNum = { |
| key: 'test', |
| type: chrome.settingsPrivate.PrefType.NUMBER, |
| value: UNKNOWN_VALUE, |
| }; |
| |
| testElement.numericUncheckedValues = [CUSTOM_UNCHECKED_VALUE]; |
| testElement.numericCheckedValue = CUSTOM_CHECKED_VALUE; |
| |
| testElement.set('pref', prefNum); |
| |
| // Unknown value should still count as checked. |
| assertTrue(testElement.checked); |
| |
| // The control should not clobber an existing unknown value. |
| assertEquals(UNKNOWN_VALUE, prefNum.value); |
| |
| // Unchecking should still send the unchecked value to prefs. |
| testElement.click(); |
| assertFalse(testElement.checked); |
| assertEquals(CUSTOM_UNCHECKED_VALUE, prefNum.value); |
| |
| // Checking should still send the normal checked value to prefs. |
| testElement.click(); |
| assertTrue(testElement.checked); |
| assertEquals(CUSTOM_CHECKED_VALUE, prefNum.value); |
| }); |
| |
| test('shows controlled indicator when pref is controlled', () => { |
| assertFalse( |
| !!testElement.shadowRoot!.querySelector('cr-policy-pref-indicator')); |
| |
| const pref = { |
| key: 'test', |
| type: chrome.settingsPrivate.PrefType.NUMBER, |
| value: UNKNOWN_VALUE, |
| enforcement: chrome.settingsPrivate.Enforcement.ENFORCED, |
| controlledBy: chrome.settingsPrivate.ControlledBy.EXTENSION, |
| }; |
| |
| testElement.set('pref', pref); |
| flush(); |
| |
| assertTrue( |
| !!testElement.shadowRoot!.querySelector('cr-policy-pref-indicator')); |
| }); |
| |
| test('no indicator with no-extension-indicator flag', () => { |
| assertFalse( |
| !!testElement.shadowRoot!.querySelector('cr-policy-pref-indicator')); |
| |
| testElement.noExtensionIndicator = true; |
| const pref = { |
| key: 'test', |
| type: chrome.settingsPrivate.PrefType.NUMBER, |
| value: UNKNOWN_VALUE, |
| enforcement: chrome.settingsPrivate.Enforcement.ENFORCED, |
| controlledBy: chrome.settingsPrivate.ControlledBy.EXTENSION, |
| }; |
| |
| testElement.set('pref', pref); |
| flush(); |
| |
| assertFalse( |
| !!testElement.shadowRoot!.querySelector('cr-policy-pref-indicator')); |
| }); |
| |
| test('user control disabled pref', () => { |
| const pref = { |
| key: 'test', |
| type: chrome.settingsPrivate.PrefType.BOOLEAN, |
| value: false, |
| userControlDisabled: true, |
| }; |
| |
| assertFalse(testElement.$.control.disabled); |
| testElement.set('pref', pref); |
| flush(); |
| assertTrue(testElement.$.control.disabled); |
| }); |
| |
| test('click on learn more link should not toggle the button', () => { |
| let learnMoreLink = |
| testElement.shadowRoot!.querySelector<HTMLElement>('#learn-more'); |
| assertFalse(!!learnMoreLink); |
| testElement.set('learnMoreUrl', 'www.google.com'); |
| flush(); |
| |
| learnMoreLink = |
| testElement.shadowRoot!.querySelector<HTMLElement>('#learn-more'); |
| assertTrue(!!learnMoreLink); |
| |
| assertTrue(testElement.checked); |
| flush(); |
| |
| learnMoreLink!.click(); |
| assertTrue(testElement.checked); |
| }); |
| |
| test('learn more link should indicate it opens in new tab', () => { |
| testElement.set('learnMoreUrl', 'www.google.com'); |
| flush(); |
| const learnMoreLink = |
| testElement.shadowRoot!.querySelector<HTMLElement>('#learn-more'); |
| assertTrue(!!learnMoreLink); |
| assertEquals( |
| learnMoreLink.getAttribute('aria-description'), |
| loadTimeData.getString('opensInNewTab')); |
| }); |
| |
| test('set label text should update aria-label of toggle', () => { |
| const testLabelText = 'test label text'; |
| testElement.setAttribute('label', testLabelText); |
| |
| const crToggle = testElement.shadowRoot!.querySelector('#control'); |
| assertTrue(!!crToggle); |
| assertEquals(crToggle!.getAttribute('aria-label'), testLabelText); |
| |
| const testLabelTextAlt = 'test label text alt'; |
| testElement.setAttribute('label', testLabelTextAlt); |
| assertEquals(crToggle!.getAttribute('aria-label'), testLabelTextAlt); |
| }); |
| |
| test('set aria-label attribute should override aria-label of toggle', () => { |
| const testLabelText = 'test label text'; |
| testElement.setAttribute('label', testLabelText); |
| |
| const crToggle = testElement.shadowRoot!.querySelector('#control'); |
| assertTrue(!!crToggle); |
| assertEquals(crToggle!.getAttribute('aria-label'), testLabelText); |
| |
| const testAriaLabel = 'test aria label'; |
| testElement.setAttribute('aria-label', testAriaLabel); |
| assertEquals(crToggle!.getAttribute('aria-label'), testAriaLabel); |
| }); |
| |
| test('sub label with action link should have proper role', () => { |
| testElement.subLabelWithLink = `<a is="action-link"></a>`; |
| flush(); |
| |
| const subLabelTextWithLink = |
| testElement.shadowRoot!.querySelector<HTMLElement>( |
| '#sub-label-text-with-link'); |
| assertTrue(!!subLabelTextWithLink); |
| |
| const actionLink = subLabelTextWithLink!.querySelector('a'); |
| assertTrue(!!actionLink); |
| assertEquals(actionLink.getAttribute('role'), 'link'); |
| }); |
| |
| test('sub label should be able to have aria-label', () => { |
| testElement.subLabelWithLink = `<a aria-label="Label"></a>`; |
| flush(); |
| |
| const subLabelTextWithLink = |
| testElement.shadowRoot!.querySelector<HTMLElement>( |
| '#sub-label-text-with-link'); |
| assertTrue(!!subLabelTextWithLink); |
| |
| const actionLink = subLabelTextWithLink.querySelector('a'); |
| assertTrue(!!actionLink); |
| assertEquals(actionLink.getAttribute('aria-label'), 'Label'); |
| }); |
| |
| // <if expr="chromeos_ash"> |
| test('click on sub label link should not toggle the button', () => { |
| let subLabelTextWithLink = |
| testElement.shadowRoot!.querySelector('#sub-label-text-with-link'); |
| assertFalse(!!subLabelTextWithLink); |
| testElement.set('subLabelWithLink', `<a href="#"></a>`); |
| flush(); |
| |
| subLabelTextWithLink = |
| testElement.shadowRoot!.querySelector('#sub-label-text-with-link'); |
| assertTrue(!!subLabelTextWithLink); |
| const link = subLabelTextWithLink.querySelector('a'); |
| assertTrue(!!link); |
| |
| assertTrue(testElement.checked); |
| flush(); |
| |
| link.click(); |
| assertTrue(testElement.checked); |
| }); |
| |
| test('click on sub label with link text should toggle the button', () => { |
| let subLabelTextWithLink = |
| testElement.shadowRoot!.querySelector<HTMLElement>( |
| '#sub-label-text-with-link'); |
| assertFalse(!!subLabelTextWithLink); |
| testElement.set('subLabelWithLink', `<a href="#"></a>`); |
| flush(); |
| |
| subLabelTextWithLink = testElement.shadowRoot!.querySelector<HTMLElement>( |
| '#sub-label-text-with-link'); |
| assertTrue(!!subLabelTextWithLink); |
| |
| assertTrue(testElement.checked); |
| flush(); |
| |
| subLabelTextWithLink!.click(); |
| assertFalse(testElement.checked); |
| }); |
| // </if> |
| }); |