| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // clang-format off |
| // #import {LanguagesBrowserProxyImpl, LanguagesMetricsProxyImpl, LanguagesPageInteraction} from 'chrome://os-settings/chromeos/lazy_load.js'; |
| // #import {CrSettingsPrefs, Router, routes} from 'chrome://os-settings/chromeos/os_settings.js'; |
| // #import {keyDownOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js'; |
| // #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; |
| // #import {getFakeLanguagePrefs} from './fake_language_settings_private.js' |
| // #import {FakeSettingsPrivate} from '../fake_settings_private.js'; |
| // #import {TestLanguagesBrowserProxy} from './test_os_languages_browser_proxy.m.js'; |
| // #import {TestLanguagesMetricsProxy} from './test_os_languages_metrics_proxy.m.js'; |
| // #import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js'; |
| // #import {fakeDataBind} from '../../test_util.m.js'; |
| // #import {getDeepActiveElement} from 'chrome://resources/js/util.m.js'; |
| // #import {waitAfterNextRender} from 'chrome://test/test_util.m.js'; |
| // clang-format on |
| |
| suite('input page', () => { |
| /** @type {!SettingsInputPageElement} */ |
| let inputPage; |
| /** @type {!settings.LanguagesMetricsProxy} */ |
| let metricsProxy; |
| /** @type {!settings.LanguagesBrowserProxy} */ |
| let browserProxy; |
| /** @type {!LanguagesHelper} */ |
| let languageHelper; |
| |
| suiteSetup(() => { |
| CrSettingsPrefs.deferInitialization = true; |
| loadTimeData.overrideValues({imeOptionsInSettings: true}); |
| }); |
| |
| setup(() => { |
| document.body.innerHTML = ''; |
| const prefElement = document.createElement('settings-prefs'); |
| const settingsPrivate = |
| new settings.FakeSettingsPrivate(settings.getFakeLanguagePrefs()); |
| prefElement.initialize(settingsPrivate); |
| |
| /** |
| * Prefs listener to emulate SpellcheckService listeners. |
| * As we use a mocked prefs object in tests, we also need to mock the |
| * behavior of SpellcheckService as it relies on a C++ PrefChangeRegistrar |
| * to listen to pref changes - which do not work when the prefs are mocked. |
| * @param {!Array<!chrome.settingsPrivate.PrefObject>} prefs |
| */ |
| function spellCheckServiceListener(prefs) { |
| for (const pref of prefs) { |
| switch (pref.key) { |
| case 'spellcheck.dictionaries': |
| // Emulate SpellcheckService::OnSpellCheckDictionariesChanged: |
| // If there are no dictionaries, set browser.enable_spellchecking |
| // to false. |
| if (pref.value.length === 0) { |
| settingsPrivate.setPref( |
| 'browser.enable_spellchecking', false, '', () => {}); |
| } |
| break; |
| |
| case 'intl.accept_languages': |
| // Emulate SpellcheckService::OnAcceptLanguagesChanged: |
| // Filter spellcheck.dictionaries and remove all dictionaries not |
| // in intl.accept_languages. We won't "normalize" it here as it is |
| // extremely difficult to do in JavaScript, and should not matter |
| // for tests. |
| // Disabled for LSV2 Update 2. |
| if (inputPage.languageSettingsV2Update2Enabled_) { |
| break; |
| } |
| |
| // Normally, getting prefs is an asynchronous action with callbacks, |
| // but we can cheat in tests using FakeSettingsPrivate. |
| const dictionaries = |
| settingsPrivate.prefs['spellcheck.dictionaries'].value; |
| const acceptLanguages = new Set(pref.value.split(',')); |
| |
| const filteredDictionaries = dictionaries.filter( |
| dictionary => acceptLanguages.has(dictionary)); |
| settingsPrivate.setPref( |
| 'spellcheck.dictionaries', filteredDictionaries, '', () => {}); |
| break; |
| } |
| } |
| } |
| |
| // Listen to prefs changes using settingsPrivate.onPrefsChanged. |
| // While prefElement (<settings-prefs>) is normally a synchronous wrapper |
| // around the asynchronous settingsPrivate, the two's prefs are always |
| // synchronously kept in sync both ways in tests. |
| // However, it's possible that a settingsPrivate.onPrefsChanged listener |
| // receives a change before prefElement does if the change is made by |
| // settingsPrivate, so prefer to use settingsPrivate getters/setters |
| // whenever possible. |
| settingsPrivate.onPrefsChanged.addListener(spellCheckServiceListener); |
| |
| document.body.appendChild(prefElement); |
| |
| return CrSettingsPrefs.initialized.then(() => { |
| // Set up test browser proxy. |
| browserProxy = new settings.TestLanguagesBrowserProxy(); |
| settings.LanguagesBrowserProxyImpl.instance_ = browserProxy; |
| |
| // Sets up test metrics proxy. |
| metricsProxy = new settings.TestLanguagesMetricsProxy(); |
| settings.LanguagesMetricsProxyImpl.instance_ = metricsProxy; |
| |
| // Set up fake languageSettingsPrivate API. |
| const languageSettingsPrivate = browserProxy.getLanguageSettingsPrivate(); |
| languageSettingsPrivate.setSettingsPrefs(prefElement); |
| |
| // Instantiate the data model with data bindings for prefs. |
| const settingsLanguages = document.createElement('settings-languages'); |
| settingsLanguages.prefs = prefElement.prefs; |
| test_util.fakeDataBind(prefElement, settingsLanguages, 'prefs'); |
| document.body.appendChild(settingsLanguages); |
| |
| // Create page with data bindings for prefs and data model. |
| inputPage = document.createElement('os-settings-input-page'); |
| inputPage.prefs = prefElement.prefs; |
| test_util.fakeDataBind(prefElement, inputPage, 'prefs'); |
| inputPage.languages = settingsLanguages.languages; |
| test_util.fakeDataBind(settingsLanguages, inputPage, 'languages'); |
| inputPage.languageHelper = settingsLanguages.languageHelper; |
| test_util.fakeDataBind(settingsLanguages, inputPage, 'language-helper'); |
| languageHelper = inputPage.languageHelper; |
| document.body.appendChild(inputPage); |
| }); |
| }); |
| |
| teardown(function() { |
| settings.Router.getInstance().resetRouteForTesting(); |
| }); |
| |
| suite('input method list', () => { |
| test('displays correctly', () => { |
| const inputMethodsList = inputPage.$$('#inputMethodsList'); |
| assertTrue(!!inputMethodsList); |
| |
| // The test input methods should appear. |
| const items = inputMethodsList.querySelectorAll('.list-item'); |
| // Two items for input methods and one item for add input methods. |
| assertEquals(3, items.length); |
| assertEquals( |
| 'US keyboard', |
| items[0].querySelector('.display-name').textContent.trim()); |
| assertTrue(!!items[0].querySelector('.internal-wrapper')); |
| assertFalse(!!items[0].querySelector('.external-wrapper')); |
| assertFalse(!!items[0].querySelector('.icon-clear').disabled); |
| assertEquals( |
| 'US Dvorak keyboard', |
| items[1].querySelector('.display-name').textContent.trim()); |
| assertTrue(!!items[1].querySelector('.external-wrapper')); |
| assertFalse(!!items[1].querySelector('.internal-wrapper')); |
| assertFalse(!!items[1].querySelector('.icon-clear').disabled); |
| }); |
| |
| test('navigates to input method options page', () => { |
| const inputMethodsList = inputPage.$.inputMethodsList; |
| const items = inputMethodsList.querySelectorAll('.list-item'); |
| items[0].querySelector('.subpage-arrow').click(); |
| const router = settings.Router.getInstance(); |
| assertEquals( |
| router.getCurrentRoute().getAbsolutePath(), |
| 'chrome://os-settings/osLanguages/inputMethodOptions'); |
| assertEquals( |
| router.getQueryParameters().get('id'), |
| '_comp_ime_jkghodnilhceideoidjikpgommlajknkxkb:us::eng'); |
| }); |
| |
| test('removes an input method', () => { |
| const inputMethodName = 'US keyboard'; |
| |
| let inputMethodsList = inputPage.$.inputMethodsList; |
| let items = inputMethodsList.querySelectorAll('.list-item'); |
| assertEquals(3, items.length); |
| assertEquals( |
| inputMethodName, |
| items[0].querySelector('.display-name').textContent.trim()); |
| |
| // clicks remove input method button. |
| items[0].querySelector('.icon-clear').click(); |
| Polymer.dom.flush(); |
| |
| inputMethodsList = inputPage.$.inputMethodsList; |
| items = inputMethodsList.querySelectorAll('.list-item'); |
| assertEquals(2, items.length); |
| assertTrue( |
| items[0].querySelector('.display-name').textContent.trim() !== |
| inputMethodName); |
| }); |
| |
| test('disables remove input method option', async () => { |
| // Add US Swahili keyboard, a third party IME |
| languageHelper.addInputMethod( |
| 'ime_abcdefghijklmnopqrstuvwxyzabcdefxkb:us:sw'); |
| // Remove US Dvorak keyboard, so there is only 1 component IME left. |
| languageHelper.removeInputMethod( |
| '_comp_ime_fgoepimhcoialccpbmpnnblemnepkkaoxkb:us:dvorak:eng'); |
| Polymer.dom.flush(); |
| |
| const inputMethodsList = inputPage.$.inputMethodsList; |
| const items = inputMethodsList.querySelectorAll('.list-item'); |
| assertEquals(3, items.length); |
| assertEquals( |
| 'US keyboard', |
| items[0].querySelector('.display-name').textContent.trim()); |
| assertTrue(!!items[0].querySelector('.icon-clear').disabled); |
| assertEquals( |
| 'US Swahili keyboard', |
| items[1].querySelector('.display-name').textContent.trim()); |
| assertFalse(!!items[1].querySelector('.icon-clear').disabled); |
| }); |
| |
| test('shows managed input methods label', () => { |
| const inputMethodsManagedbyPolicy = |
| inputPage.$$('#inputMethodsManagedbyPolicy'); |
| assertFalse(!!inputMethodsManagedbyPolicy); |
| |
| inputPage.setPrefValue( |
| 'settings.language.allowed_input_methods', ['xkb:us::eng']); |
| Polymer.dom.flush(); |
| |
| assertTrue(!!inputPage.$$('#inputMethodsManagedbyPolicy')); |
| }); |
| }); |
| |
| suite('input page', () => { |
| test('Deep link to spell check', async () => { |
| loadTimeData.overrideValues({ |
| isDeepLinkingEnabled: true, |
| }); |
| |
| const params = new URLSearchParams; |
| params.append('settingId', '1207'); |
| settings.Router.getInstance().navigateTo( |
| settings.routes.OS_LANGUAGES_INPUT, params); |
| |
| Polymer.dom.flush(); |
| |
| const deepLinkElement = |
| inputPage.$$('#enableSpellcheckingToggle').$$('cr-toggle'); |
| await test_util.waitAfterNextRender(deepLinkElement); |
| assertEquals( |
| deepLinkElement, getDeepActiveElement(), |
| 'Spell check toggle should be focused for settingId=1207.'); |
| }); |
| }); |
| |
| suite('add input methods dialog', () => { |
| let dialog; |
| let suggestedInputMethods; |
| let allInputMethods; |
| let cancelButton; |
| let actionButton; |
| |
| setup(() => { |
| assertFalse(!!inputPage.$$('os-settings-add-input-methods-dialog')); |
| inputPage.$$('#addInputMethod').click(); |
| Polymer.dom.flush(); |
| |
| dialog = inputPage.$$('os-settings-add-input-methods-dialog'); |
| assertTrue(!!dialog); |
| |
| actionButton = dialog.$$('.action-button'); |
| assertTrue(!!actionButton); |
| cancelButton = dialog.$$('.cancel-button'); |
| assertTrue(!!cancelButton); |
| |
| suggestedInputMethods = dialog.$$('#suggestedInputMethods'); |
| assertTrue(!!suggestedInputMethods); |
| |
| allInputMethods = dialog.$$('#allInputMethods'); |
| assertTrue(!!allInputMethods); |
| |
| // No input methods has been selected, so the action button is disabled. |
| assertTrue(actionButton.disabled); |
| assertFalse(cancelButton.disabled); |
| }); |
| |
| test('has action button working correctly', () => { |
| const listItems = suggestedInputMethods.querySelectorAll('.list-item'); |
| // selecting a language enables action button |
| listItems[0].click(); |
| assertFalse(actionButton.disabled); |
| |
| // selecting the same language again disables action button |
| listItems[0].click(); |
| assertTrue(actionButton.disabled); |
| }); |
| |
| test('has correct structure and adds input methods', () => { |
| const suggestedItems = |
| suggestedInputMethods.querySelectorAll('.list-item'); |
| // input methods are based on and ordered by enabled languages |
| // only allowed input methods are shown. |
| assertEquals(2, suggestedItems.length); |
| assertEquals('US Swahili keyboard', suggestedItems[0].textContent.trim()); |
| assertEquals('Swahili keyboard', suggestedItems[1].textContent.trim()); |
| // selecting Swahili keyboard. |
| suggestedItems[1].click(); |
| |
| const allItems = allInputMethods.querySelectorAll('.list-item'); |
| // All input methods should appear and ordered based on fake settings |
| // data. |
| assertEquals(4, allItems.length); |
| |
| const expectedItems = [ |
| { |
| name: 'Swahili keyboard', |
| checkboxDisabled: false, |
| checkboxChecked: true, |
| policyIcon: false, |
| }, |
| { |
| name: 'US Swahili keyboard', |
| checkboxDisabled: false, |
| checkboxChecked: false, |
| policyIcon: false, |
| }, |
| { |
| name: 'US International keyboard', |
| checkboxDisabled: true, |
| checkboxChecked: false, |
| policyIcon: true, |
| }, |
| { |
| name: 'Vietnamese keyboard', |
| checkboxDisabled: false, |
| checkboxChecked: false, |
| policyIcon: false, |
| }, |
| ]; |
| |
| for (let i = 0; i < allItems.length; i++) { |
| assertTrue( |
| allItems[i].textContent.includes(expectedItems[i].name), |
| `expect ${allItems[i].textContent} to include ${ |
| expectedItems[i].name}`); |
| assertEquals( |
| expectedItems[i].checkboxDisabled, |
| allItems[i].shadowRoot.querySelector('cr-checkbox').disabled, |
| `expect ${expectedItems[i].name}'s checkbox disabled state to be ${ |
| expectedItems[i].checkboxDisabled}`); |
| assertEquals( |
| expectedItems[i].checkboxChecked, |
| allItems[i].shadowRoot.querySelector('cr-checkbox').checked, |
| `expect ${expectedItems[i].name}'s checkbox checked state to be ${ |
| expectedItems[i].checkboxChecked}`); |
| assertEquals( |
| expectedItems[i].policyIcon, |
| !!allItems[i].shadowRoot.querySelector('iron-icon'), |
| `expect ${expectedItems[i].name}'s policy icon presence to be ${ |
| expectedItems[i].policyIcon}`); |
| } |
| |
| // selecting Vietnamese keyboard |
| allItems[3].shadowRoot.querySelector('cr-checkbox').click(); |
| |
| actionButton.click(); |
| |
| assertTrue(languageHelper.isInputMethodEnabled( |
| '_comp_ime_abcdefghijklmnopqrstuvwxyzabcdefxkb:sw:sw')); |
| assertFalse(languageHelper.isInputMethodEnabled( |
| 'ime_abcdefghijklmnopqrstuvwxyzabcdefxkb:us:sw')); |
| assertTrue(languageHelper.isInputMethodEnabled( |
| '_comp_ime_abcdefghijklmnopqrstuvwxyzabcdefxkb:vi:vi')); |
| }); |
| |
| test('suggested input methods hidden when no languages is enabled', () => { |
| languageHelper.setPrefValue('settings.language.preferred_languages', ''); |
| Polymer.dom.flush(); |
| |
| suggestedInputMethods = dialog.$$('#suggestedInputMethods'); |
| // suggested input methods is rendered previously. |
| assertTrue(!!suggestedInputMethods); |
| assertEquals('none', getComputedStyle(suggestedInputMethods).display); |
| }); |
| |
| test('suggested input methods hidden when no input methods left', () => { |
| const languageCode = 'sw'; |
| languageHelper.setPrefValue( |
| 'settings.language.preferred_languages', languageCode); |
| languageHelper.getInputMethodsForLanguage(languageCode) |
| .forEach(inputMethod => { |
| languageHelper.addInputMethod(inputMethod.id); |
| }); |
| Polymer.dom.flush(); |
| |
| suggestedInputMethods = dialog.$$('#suggestedInputMethods'); |
| // suggested input methods is rendered previously. |
| assertTrue(!!suggestedInputMethods); |
| assertEquals('none', getComputedStyle(suggestedInputMethods).display); |
| }); |
| |
| test('searches input methods correctly', () => { |
| const searchInput = dialog.$$('cr-search-field'); |
| const getItems = function() { |
| return allInputMethods.querySelectorAll('.list-item:not([hidden])'); |
| }; |
| |
| assertFalse(dialog.$$('#allInputMethodsLabel').hidden); |
| assertEquals('block', getComputedStyle(suggestedInputMethods).display); |
| |
| // Expecting a few languages to be displayed when no query exists. |
| assertGE(getItems().length, 1); |
| |
| // Search hides suggestedInputMethods and allInputMethodsLabel. |
| searchInput.setValue('v'); |
| Polymer.dom.flush(); |
| assertTrue(dialog.$$('#allInputMethodsLabel').hidden); |
| assertEquals('none', getComputedStyle(suggestedInputMethods).display); |
| |
| // Search input methods name |
| searchInput.setValue('vietnamese'); |
| Polymer.dom.flush(); |
| assertEquals(1, getItems().length); |
| assertTrue(getItems()[0].textContent.includes('Vietnamese')); |
| |
| // Search input methods' language |
| searchInput.setValue('Turkmen'); |
| Polymer.dom.flush(); |
| assertEquals(1, getItems().length); |
| assertTrue(getItems()[0].textContent.includes('Swahili keyboard')); |
| }); |
| |
| test('has escape key behavior working correctly', function() { |
| const searchInput = dialog.$$('cr-search-field'); |
| searchInput.setValue('dummyquery'); |
| |
| // Test that dialog is not closed if 'Escape' is pressed on the input |
| // and a search query exists. |
| MockInteractions.keyDownOn(searchInput, 19, [], 'Escape'); |
| assertTrue(dialog.$.dialog.open); |
| |
| // Test that dialog is closed if 'Escape' is pressed on the input and no |
| // search query exists. |
| searchInput.setValue(''); |
| MockInteractions.keyDownOn(searchInput, 19, [], 'Escape'); |
| assertFalse(dialog.$.dialog.open); |
| }); |
| }); |
| |
| suite('records metrics', () => { |
| test('when deactivating show ime menu', async () => { |
| inputPage.setPrefValue('settings.language.ime_menu_activated', true); |
| inputPage.$$('#showImeMenu').click(); |
| Polymer.dom.flush(); |
| |
| assertFalse( |
| await metricsProxy.whenCalled('recordToggleShowInputOptionsOnShelf')); |
| }); |
| |
| test('when activating show ime menu', async () => { |
| inputPage.setPrefValue('settings.language.ime_menu_activated', false); |
| inputPage.$$('#showImeMenu').click(); |
| Polymer.dom.flush(); |
| |
| assertTrue( |
| await metricsProxy.whenCalled('recordToggleShowInputOptionsOnShelf')); |
| }); |
| |
| test('when adding input methods', async () => { |
| inputPage.$$('#addInputMethod').click(); |
| Polymer.dom.flush(); |
| |
| await metricsProxy.whenCalled('recordAddInputMethod'); |
| }); |
| |
| test('when switch input method', async () => { |
| const inputMethodsList = inputPage.$$('#inputMethodsList'); |
| assertTrue(!!inputMethodsList); |
| |
| // The test input methods should appear. |
| const items = inputMethodsList.querySelectorAll('.list-item'); |
| items[0].click(); |
| assertEquals( |
| settings.LanguagesPageInteraction.SWITCH_INPUT_METHOD, |
| await metricsProxy.whenCalled('recordInteraction')); |
| }); |
| }); |
| |
| suite('spell check v1', () => { |
| let spellCheckToggle; |
| let spellCheckListContainer; |
| let spellCheckList; |
| |
| setup(() => { |
| // Disable Update 2. |
| // We use the property directly instead of loadTimeData, as overriding |
| // loadTimeData does not work as the property is set using a value(). |
| inputPage.languageSettingsV2Update2Enabled_ = false; |
| // However, we should still set loadTimeData as some other code may use |
| // it (such as languages.js). |
| loadTimeData.overrideValues({enableLanguageSettingsV2Update2: false}); |
| |
| Polymer.dom.flush(); |
| // spell check is initially on |
| spellCheckToggle = inputPage.$.enableSpellcheckingToggle; |
| assertTrue(!!spellCheckToggle); |
| assertTrue(spellCheckToggle.checked); |
| |
| spellCheckListContainer = inputPage.$$('#spellCheckLanguagesList'); |
| assertTrue(!!spellCheckListContainer); |
| |
| // two languages are in the list, with en-US on and sw off. |
| spellCheckList = spellCheckListContainer.querySelectorAll('.list-item'); |
| assertEquals(2, spellCheckList.length); |
| assertTrue( |
| spellCheckList[0].textContent.includes('English (United States)')); |
| assertTrue(spellCheckList[0].querySelector('cr-toggle').checked); |
| assertTrue(spellCheckList[1].textContent.includes('Swahili')); |
| assertFalse(spellCheckList[1].querySelector('cr-toggle').checked); |
| }); |
| |
| test('toggles a spell check language add/remove it from dictionary', () => { |
| assertDeepEquals( |
| ['en-US'], languageHelper.prefs.spellcheck.dictionaries.value); |
| // Get toggle for en-US. |
| const spellCheckLanguageToggle = |
| spellCheckList[0].querySelector('cr-toggle'); |
| |
| // toggle off |
| spellCheckLanguageToggle.click(); |
| |
| assertFalse(spellCheckLanguageToggle.checked); |
| assertDeepEquals([], languageHelper.prefs.spellcheck.dictionaries.value); |
| |
| // The spell check toggle should be off now. |
| assertFalse(spellCheckToggle.checked); |
| spellCheckToggle.click(); |
| assertTrue(spellCheckToggle.checked); |
| |
| // toggle on |
| spellCheckLanguageToggle.click(); |
| |
| assertTrue(spellCheckLanguageToggle.checked); |
| assertDeepEquals( |
| ['en-US'], languageHelper.prefs.spellcheck.dictionaries.value); |
| }); |
| |
| test( |
| 'clicks a spell check language name add/remove it from dictionary', |
| () => { |
| assertDeepEquals( |
| ['en-US'], languageHelper.prefs.spellcheck.dictionaries.value); |
| // Get toggle for en-US. |
| const spellCheckLanguageToggle = |
| spellCheckList[0].querySelector('cr-toggle'); |
| |
| // toggle off by clicking name |
| spellCheckList[0].querySelector('.name-with-error').click(); |
| Polymer.dom.flush(); |
| |
| assertFalse(spellCheckLanguageToggle.checked); |
| assertDeepEquals( |
| [], languageHelper.prefs.spellcheck.dictionaries.value); |
| |
| // The spell check toggle should be off now. |
| assertFalse(spellCheckToggle.checked); |
| spellCheckToggle.click(); |
| assertTrue(spellCheckToggle.checked); |
| |
| // toggle on by clicking name |
| spellCheckList[0].querySelector('.name-with-error').click(); |
| Polymer.dom.flush(); |
| |
| assertTrue(spellCheckLanguageToggle.checked); |
| assertDeepEquals( |
| ['en-US'], languageHelper.prefs.spellcheck.dictionaries.value); |
| }); |
| |
| test('shows force-on existing spell check language', () => { |
| // Force-enable an existing language via policy. |
| languageHelper.setPrefValue('spellcheck.forced_dictionaries', ['sw']); |
| Polymer.dom.flush(); |
| |
| const newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| assertEquals(2, newSpellCheckList.length); |
| const forceEnabledSwLanguageRow = newSpellCheckList[1]; |
| assertTrue(!!forceEnabledSwLanguageRow); |
| assertTrue(!!forceEnabledSwLanguageRow.querySelector( |
| 'cr-policy-pref-indicator')); |
| assertTrue( |
| forceEnabledSwLanguageRow.querySelector('.managed-toggle').checked); |
| assertTrue( |
| forceEnabledSwLanguageRow.querySelector('.managed-toggle').disabled); |
| assertEquals( |
| getComputedStyle( |
| forceEnabledSwLanguageRow.querySelector('.name-with-error')) |
| .pointerEvents, |
| 'none'); |
| }); |
| |
| test('shows force-on non-enabled spell check language', () => { |
| // Force-enable a new language via policy. |
| languageHelper.setPrefValue('spellcheck.forced_dictionaries', ['nb']); |
| Polymer.dom.flush(); |
| |
| const newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| assertEquals(3, newSpellCheckList.length); |
| const forceEnabledNbLanguageRow = newSpellCheckList[2]; |
| assertTrue(!!forceEnabledNbLanguageRow); |
| assertTrue(!!forceEnabledNbLanguageRow.querySelector( |
| 'cr-policy-pref-indicator')); |
| assertTrue( |
| forceEnabledNbLanguageRow.querySelector('.managed-toggle').checked); |
| assertTrue( |
| forceEnabledNbLanguageRow.querySelector('.managed-toggle').disabled); |
| assertEquals( |
| getComputedStyle( |
| forceEnabledNbLanguageRow.querySelector('.name-with-error')) |
| .pointerEvents, |
| 'none'); |
| }); |
| |
| test('can disable non-enabled spell check language', () => { |
| // Add a new language to spellcheck.dictionaries which isn't enabled. |
| languageHelper.setPrefValue('spellcheck.dictionaries', ['en-US', 'nb']); |
| Polymer.dom.flush(); |
| |
| let newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| // The spell check list should have en-US (enabled), sw (disabled) and |
| // nb (enabled). |
| assertEquals(3, newSpellCheckList.length); |
| assertTrue( |
| newSpellCheckList[0].textContent.includes('English (United States)')); |
| assertTrue(newSpellCheckList[0].querySelector('cr-toggle').checked); |
| assertTrue(newSpellCheckList[1].textContent.includes('Swahili')); |
| assertFalse(newSpellCheckList[1].querySelector('cr-toggle').checked); |
| assertTrue(newSpellCheckList[2].textContent.includes('Norwegian Bokmål')); |
| assertTrue(newSpellCheckList[2].querySelector('cr-toggle').checked); |
| |
| // Disable nb. |
| newSpellCheckList[2].querySelector('cr-toggle').click(); |
| Polymer.dom.flush(); |
| newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| |
| // The spell check list should have en-US (enabled) and sw (disabled). |
| assertEquals(2, newSpellCheckList.length); |
| assertTrue( |
| newSpellCheckList[0].textContent.includes('English (United States)')); |
| assertTrue(newSpellCheckList[0].querySelector('cr-toggle').checked); |
| assertTrue(newSpellCheckList[1].textContent.includes('Swahili')); |
| assertFalse(newSpellCheckList[1].querySelector('cr-toggle').checked); |
| |
| assertDeepEquals( |
| ['en-US'], languageHelper.prefs.spellcheck.dictionaries.value); |
| }); |
| |
| test( |
| 'does not show force-off spell check when language is not enabled', |
| () => { |
| // Force-disable a language via policy. |
| languageHelper.setPrefValue( |
| 'spellcheck.blocked_dictionaries', ['nb']); |
| Polymer.dom.flush(); |
| const newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| assertEquals(2, newSpellCheckList.length); |
| }); |
| |
| test('shows force-off spell check when language is enabled', () => { |
| // Force-disable a language via policy. |
| languageHelper.setPrefValue('spellcheck.blocked_dictionaries', ['nb']); |
| languageHelper.enableLanguage('nb'); |
| Polymer.dom.flush(); |
| |
| const newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| assertEquals(3, newSpellCheckList.length); |
| const forceDisabledNbLanguageRow = newSpellCheckList[2]; |
| assertTrue(!!forceDisabledNbLanguageRow.querySelector( |
| 'cr-policy-pref-indicator')); |
| assertFalse( |
| forceDisabledNbLanguageRow.querySelector('.managed-toggle').checked); |
| assertTrue( |
| forceDisabledNbLanguageRow.querySelector('.managed-toggle').disabled); |
| assertEquals( |
| getComputedStyle( |
| forceDisabledNbLanguageRow.querySelector('.name-with-error')) |
| .pointerEvents, |
| 'none'); |
| }); |
| |
| test('toggle off disables toggle and click event', () => { |
| // Initially, both toggles are enabled |
| assertFalse(spellCheckList[0].querySelector('cr-toggle').disabled); |
| assertFalse(spellCheckList[1].querySelector('cr-toggle').disabled); |
| assertEquals( |
| getComputedStyle(spellCheckList[0].querySelector('.name-with-error')) |
| .pointerEvents, |
| 'auto'); |
| assertEquals( |
| getComputedStyle(spellCheckList[1].querySelector('.name-with-error')) |
| .pointerEvents, |
| 'auto'); |
| |
| spellCheckToggle.click(); |
| |
| assertFalse(spellCheckToggle.checked); |
| assertTrue(spellCheckList[0].querySelector('cr-toggle').disabled); |
| assertTrue(spellCheckList[1].querySelector('cr-toggle').disabled); |
| assertEquals( |
| getComputedStyle(spellCheckList[0].querySelector('.name-with-error')) |
| .pointerEvents, |
| 'none'); |
| assertEquals( |
| getComputedStyle(spellCheckList[1].querySelector('.name-with-error')) |
| .pointerEvents, |
| 'none'); |
| }); |
| |
| test('does not add a language without spellcheck support', () => { |
| const spellCheckLanguagesCount = spellCheckList.length; |
| // Enabling a language without spellcheck support should not add it to |
| // the list |
| languageHelper.enableLanguage('tk'); |
| Polymer.dom.flush(); |
| assertEquals(spellCheckList.length, spellCheckLanguagesCount); |
| }); |
| |
| test('toggle is disabled when there are no supported languages', () => { |
| assertFalse(spellCheckToggle.disabled); |
| |
| // Empty out supported languages |
| for (const lang of languageHelper.languages.enabled) { |
| languageHelper.disableLanguage(lang.language.code); |
| } |
| |
| assertTrue(spellCheckToggle.disabled); |
| assertFalse(spellCheckToggle.checked); |
| }); |
| |
| test('error handling', () => { |
| const checkAllHidden = nodes => { |
| assertTrue(nodes.every(node => node.hidden)); |
| }; |
| |
| const languageSettingsPrivate = browserProxy.getLanguageSettingsPrivate(); |
| const errorDivs = Array.from( |
| spellCheckListContainer.querySelectorAll('.name-with-error div')); |
| assertEquals(2, errorDivs.length); |
| checkAllHidden(errorDivs); |
| |
| const retryButtons = |
| Array.from(spellCheckListContainer.querySelectorAll('cr-button')); |
| assertEquals(2, retryButtons.length); |
| |
| const languageCode = inputPage.get('languages.enabled.0.language.code'); |
| languageSettingsPrivate.onSpellcheckDictionariesChanged.callListeners([ |
| {languageCode, isReady: false, downloadFailed: true}, |
| ]); |
| |
| Polymer.dom.flush(); |
| assertFalse(errorDivs[0].hidden); |
| assertFalse(retryButtons[0].hidden); |
| assertFalse(retryButtons[0].disabled); |
| |
| // turns off spell check disable retry button. |
| spellCheckToggle.click(); |
| assertTrue(retryButtons[0].disabled); |
| |
| // turns spell check back on and enable download. |
| spellCheckToggle.click(); |
| languageSettingsPrivate.onSpellcheckDictionariesChanged.callListeners([ |
| {languageCode, isReady: true, downloadFailed: false}, |
| ]); |
| |
| Polymer.dom.flush(); |
| assertTrue(errorDivs[0].hidden); |
| assertTrue(retryButtons[0].hidden); |
| }); |
| |
| test('toggle off disables enhanced spell check', () => { |
| const enhancedSpellCheckToggle = |
| inputPage.$$('#enhancedSpellCheckToggle'); |
| assertFalse(enhancedSpellCheckToggle.disabled); |
| spellCheckToggle.click(); |
| |
| assertTrue(enhancedSpellCheckToggle.disabled); |
| }); |
| |
| test('toggle off disables edit dictionary', () => { |
| const editDictionarySubpageTrigger = |
| inputPage.$$('#editDictionarySubpageTrigger'); |
| assertFalse(editDictionarySubpageTrigger.disabled); |
| spellCheckToggle.click(); |
| |
| assertTrue(editDictionarySubpageTrigger.disabled); |
| }); |
| |
| test('opens edit dictionary page', () => { |
| const editDictionarySubpageTrigger = |
| inputPage.$$('#editDictionarySubpageTrigger'); |
| editDictionarySubpageTrigger.click(); |
| const router = settings.Router.getInstance(); |
| assertEquals( |
| router.getCurrentRoute().getAbsolutePath(), |
| 'chrome://os-settings/osLanguages/editDictionary'); |
| }); |
| }); |
| |
| suite('spell check v2', () => { |
| let spellCheckToggle; |
| let spellCheckListContainer; |
| // This list is not dynamically updated. |
| let spellCheckList; |
| |
| setup(() => { |
| // Enable Update 2. |
| // We use the property directly instead of loadTimeData, as overriding |
| // loadTimeData does not work as the property is set using a value(). |
| inputPage.languageSettingsV2Update2Enabled_ = true; |
| // However, we should still set loadTimeData as some other code may use |
| // it (such as languages.js). |
| loadTimeData.overrideValues({enableLanguageSettingsV2Update2: true}); |
| Polymer.dom.flush(); |
| |
| // Spell check is initially on. |
| spellCheckToggle = inputPage.$.enableSpellcheckingToggle; |
| assertTrue(!!spellCheckToggle); |
| assertTrue(spellCheckToggle.checked); |
| |
| spellCheckListContainer = inputPage.$$('#spellCheckLanguagesListV2'); |
| assertTrue(!!spellCheckListContainer); |
| |
| // The spell check list should only have en-US (excluding the "add |
| // languages" button). |
| spellCheckList = spellCheckListContainer.querySelectorAll('.list-item'); |
| assertEquals(1 + 1, spellCheckList.length); |
| assertTrue( |
| spellCheckList[0].textContent.includes('English (United States)')); |
| assertTrue(spellCheckList[1].textContent.includes('Add languages')); |
| }); |
| |
| test('can remove enabled language from spell check list', () => { |
| assertDeepEquals( |
| ['en-US'], languageHelper.prefs.spellcheck.dictionaries.value); |
| // Get remove button for en-US. |
| const spellCheckLanguageToggle = |
| spellCheckList[0].querySelector('cr-icon-button'); |
| |
| // Remove the language. |
| spellCheckLanguageToggle.click(); |
| Polymer.dom.flush(); |
| |
| const newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| // The spell check list should just have "add languages". |
| assertEquals(0 + 1, newSpellCheckList.length); |
| |
| assertDeepEquals([], languageHelper.prefs.spellcheck.dictionaries.value); |
| }); |
| |
| test('can remove non-enabled language from spell check list', () => { |
| // Add a new non-enabled language to spellcheck.dictionaries. |
| languageHelper.setPrefValue('spellcheck.dictionaries', ['en-US', 'nb']); |
| Polymer.dom.flush(); |
| |
| let newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| |
| // The spell check list should have en-US, nb and "add languages". |
| assertEquals(2 + 1, newSpellCheckList.length); |
| assertTrue( |
| newSpellCheckList[0].textContent.includes('English (United States)')); |
| assertTrue(newSpellCheckList[1].textContent.includes('Norwegian Bokmål')); |
| |
| // Remove nb. |
| newSpellCheckList[1].querySelector('cr-icon-button').click(); |
| Polymer.dom.flush(); |
| newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| |
| // The spell check list should have en-US and "add languages". |
| assertEquals(1 + 1, newSpellCheckList.length); |
| assertTrue( |
| newSpellCheckList[0].textContent.includes('English (United States)')); |
| |
| assertDeepEquals( |
| ['en-US'], languageHelper.prefs.spellcheck.dictionaries.value); |
| }); |
| |
| test('shows force-on spell check language turned on by user', () => { |
| // Force-enable a spell check language originally set by the user. |
| languageHelper.setPrefValue('spellcheck.forced_dictionaries', ['en-US']); |
| Polymer.dom.flush(); |
| |
| const newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| |
| // The spell check list should have en-US and "add languages". |
| assertEquals(1 + 1, newSpellCheckList.length); |
| |
| const forceEnabledEnUSLanguageRow = newSpellCheckList[0]; |
| assertTrue(forceEnabledEnUSLanguageRow.textContent.includes( |
| 'English (United States)')); |
| assertTrue(!!forceEnabledEnUSLanguageRow.querySelector( |
| 'cr-policy-pref-indicator')); |
| // Polymer sometimes hides the old enabled element by using a |
| // display: none, so we use the managed-button class to get a reference to |
| // the new disabled button. |
| const managedButton = |
| forceEnabledEnUSLanguageRow.querySelector('.managed-button'); |
| assertTrue(managedButton.disabled); |
| }); |
| |
| test('shows force-on enabled spell check language', () => { |
| // Force-enable an enabled language via policy. |
| languageHelper.setPrefValue('spellcheck.forced_dictionaries', ['sw']); |
| Polymer.dom.flush(); |
| |
| const newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| |
| // The spell check list should have en-US, sw and "add languages". |
| assertEquals(2 + 1, newSpellCheckList.length); |
| assertTrue( |
| newSpellCheckList[0].textContent.includes('English (United States)')); |
| |
| const forceEnabledSwLanguageRow = newSpellCheckList[1]; |
| assertTrue(forceEnabledSwLanguageRow.textContent.includes('Swahili')); |
| assertTrue(!!forceEnabledSwLanguageRow.querySelector( |
| 'cr-policy-pref-indicator')); |
| const managedButton = |
| forceEnabledSwLanguageRow.querySelector('.managed-button'); |
| assertTrue(managedButton.disabled); |
| }); |
| |
| test('shows force-on non-enabled spell check language', () => { |
| // Force-enable a non-enabled language via policy. |
| languageHelper.setPrefValue('spellcheck.forced_dictionaries', ['nb']); |
| Polymer.dom.flush(); |
| |
| const newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| |
| // The spell check list should have en-US, nb and "add languages". |
| assertEquals(2 + 1, newSpellCheckList.length); |
| assertTrue( |
| newSpellCheckList[0].textContent.includes('English (United States)')); |
| |
| const forceEnabledNbLanguageRow = newSpellCheckList[1]; |
| assertTrue( |
| forceEnabledNbLanguageRow.textContent.includes('Norwegian Bokmål')); |
| assertTrue(!!forceEnabledNbLanguageRow.querySelector( |
| 'cr-policy-pref-indicator')); |
| const managedButton = |
| forceEnabledNbLanguageRow.querySelector('.managed-button'); |
| assertTrue(managedButton.disabled); |
| }); |
| |
| test('does not show force-off spell check language enabled by user', () => { |
| // Force-disable a spell check language originally set by the user. |
| languageHelper.setPrefValue('spellcheck.blocked_dictionaries', ['en-US']); |
| Polymer.dom.flush(); |
| |
| // The spell check list should just have "add languages". |
| const newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| assertEquals(0 + 1, newSpellCheckList.length); |
| }); |
| |
| test('does not show force-off enabled spell check language', () => { |
| // Force-disable an enabled language via policy. |
| languageHelper.setPrefValue('spellcheck.blocked_dictionaries', ['sw']); |
| Polymer.dom.flush(); |
| |
| // The spell check list should be the same (en-US, "add languages"). |
| const newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| assertEquals(1 + 1, newSpellCheckList.length); |
| assertTrue( |
| newSpellCheckList[0].textContent.includes('English (United States)')); |
| }); |
| |
| test('does not show force-off non-enabled spell check language', () => { |
| // Force-disable a non-enabled language via policy. |
| languageHelper.setPrefValue('spellcheck.blocked_dictionaries', ['nb']); |
| Polymer.dom.flush(); |
| |
| // The spell check list should be the same (en-US, "add languages"). |
| const newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| assertEquals(1 + 1, newSpellCheckList.length); |
| assertTrue( |
| newSpellCheckList[0].textContent.includes('English (United States)')); |
| }); |
| |
| test('toggle off disables buttons', () => { |
| assertTrue(spellCheckToggle.checked); |
| assertFalse(spellCheckList[0].querySelector('cr-icon-button').disabled); |
| // "Add languages" uses a cr-button instead of a cr-icon-button. |
| assertFalse(spellCheckList[1].querySelector('cr-button').disabled); |
| |
| spellCheckToggle.click(); |
| |
| assertFalse(spellCheckToggle.checked); |
| assertTrue(spellCheckList[0].querySelector('cr-icon-button').disabled); |
| assertTrue(spellCheckList[1].querySelector('cr-button').disabled); |
| }); |
| |
| test('languages are in sorted order', () => { |
| languageHelper.setPrefValue( |
| 'spellcheck.dictionaries', ['sw', 'en-US', 'nb', 'en-CA']); |
| Polymer.dom.flush(); |
| // The spell check list should be sorted by display name: |
| // English (Canada), English (United States), Norwegian Bokmål, then |
| // Swahili. |
| const newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| assertEquals(4 + 1, newSpellCheckList.length); |
| assertTrue(newSpellCheckList[0].textContent.includes('English (Canada)')); |
| assertTrue( |
| newSpellCheckList[1].textContent.includes('English (United States)')); |
| assertTrue(newSpellCheckList[2].textContent.includes('Norwegian Bokmål')); |
| assertTrue(newSpellCheckList[3].textContent.includes('Swahili')); |
| }); |
| |
| test('removing all languages, then adding enabled language works', () => { |
| // See https://crbug.com/1197386 for more information. |
| // Remove en-US so there are no spell check languages. |
| const spellCheckLanguageToggle = |
| spellCheckList[0].querySelector('cr-icon-button'); |
| spellCheckLanguageToggle.click(); |
| Polymer.dom.flush(); |
| |
| let newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| |
| // The spell check list should just have "add languages". |
| assertEquals(0 + 1, newSpellCheckList.length); |
| // The "enable spellchecking" toggle should be off as well. |
| assertFalse(spellCheckToggle.checked); |
| |
| // Enable spell checking again. |
| spellCheckToggle.click(); |
| newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| // The spell check list shouldn't have changed... |
| assertEquals(0 + 1, newSpellCheckList.length); |
| // ...but the "enable spellchecking" toggle should be checked. |
| assertTrue(spellCheckToggle.checked); |
| |
| // Add an enabled language (en-US). |
| languageHelper.toggleSpellCheck('en-US', true); |
| Polymer.dom.flush(); |
| |
| newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| // The spell check list should now have en-US. |
| assertEquals(1 + 1, newSpellCheckList.length); |
| assertTrue( |
| newSpellCheckList[0].textContent.includes('English (United States)')); |
| // Spell check should still be enabled. |
| assertTrue(spellCheckToggle.checked); |
| }); |
| |
| test('changing Accept-Language does not change spellcheck', () => { |
| // Remove en-US from Accept-Language, which is also an enabled spell check |
| // language. |
| languageHelper.disableLanguage('en-US'); |
| Polymer.dom.flush(); |
| |
| // en-US should still be there. |
| let newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| assertEquals(1 + 1, newSpellCheckList.length); |
| assertTrue( |
| newSpellCheckList[0].textContent.includes('English (United States)')); |
| |
| // Add a spell check language not in Accept-Language. |
| languageHelper.toggleSpellCheck('nb', true); |
| Polymer.dom.flush(); |
| |
| // The spell check list should now have en-US, nb and "add languages". |
| newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| assertEquals(2 + 1, newSpellCheckList.length); |
| assertTrue( |
| newSpellCheckList[0].textContent.includes('English (United States)')); |
| assertTrue(newSpellCheckList[1].textContent.includes('Norwegian Bokmål')); |
| |
| // Add an arbitrary language to Accept-Language. |
| languageHelper.enableLanguage('tk'); |
| Polymer.dom.flush(); |
| |
| // The spell check list should remain the same. |
| newSpellCheckList = |
| spellCheckListContainer.querySelectorAll('.list-item'); |
| assertEquals(2 + 1, newSpellCheckList.length); |
| assertTrue( |
| newSpellCheckList[0].textContent.includes('English (United States)')); |
| assertTrue(newSpellCheckList[1].textContent.includes('Norwegian Bokmål')); |
| }); |
| |
| // TODO(crbug.com/1201540): Add test to ensure that it is impossible to |
| // enable spell check without a spell check language added (i.e. the |
| // "add spell check languages" dialog appears when turning it on). |
| |
| // TODO(crbug.com/1201540): Add a test for the "automatically determining |
| // spell check language" behaviour when the user has no spell check |
| // languages. |
| |
| // TODO(crbug.com/1201540): Add a test for the shortcut reminder. |
| |
| test('error handling', () => { |
| // Enable Swahili so we have two languages for testing. |
| languageHelper.setPrefValue('spellcheck.dictionaries', ['en-US', 'sw']); |
| Polymer.dom.flush(); |
| const checkAllHidden = nodes => { |
| assertTrue(nodes.every(node => node.hidden)); |
| }; |
| |
| const languageSettingsPrivate = browserProxy.getLanguageSettingsPrivate(); |
| const errorDivs = Array.from( |
| spellCheckListContainer.querySelectorAll('.name-with-error div')); |
| assertEquals(2, errorDivs.length); |
| checkAllHidden(errorDivs); |
| |
| const retryButtons = Array.from(spellCheckListContainer.querySelectorAll( |
| 'cr-button:not(#addSpellcheckLanguages)')); |
| assertEquals(2, retryButtons.length); |
| |
| const languageCode = inputPage.get('languages.enabled.0.language.code'); |
| languageSettingsPrivate.onSpellcheckDictionariesChanged.callListeners([ |
| {languageCode, isReady: false, downloadFailed: true}, |
| ]); |
| |
| Polymer.dom.flush(); |
| assertFalse(errorDivs[0].hidden); |
| assertFalse(retryButtons[0].hidden); |
| assertFalse(retryButtons[0].disabled); |
| |
| // turns off spell check disable retry button. |
| spellCheckToggle.click(); |
| assertTrue(retryButtons[0].disabled); |
| |
| // turns spell check back on and enable download. |
| spellCheckToggle.click(); |
| languageSettingsPrivate.onSpellcheckDictionariesChanged.callListeners([ |
| {languageCode, isReady: true, downloadFailed: false}, |
| ]); |
| |
| Polymer.dom.flush(); |
| assertTrue(errorDivs[0].hidden); |
| assertTrue(retryButtons[0].hidden); |
| }); |
| |
| test('toggle off disables enhanced spell check', () => { |
| const enhancedSpellCheckToggle = |
| inputPage.$$('#enhancedSpellCheckToggle'); |
| assertFalse(enhancedSpellCheckToggle.disabled); |
| spellCheckToggle.click(); |
| |
| assertTrue(enhancedSpellCheckToggle.disabled); |
| }); |
| |
| test('toggle off disables edit dictionary', () => { |
| const editDictionarySubpageTrigger = |
| inputPage.$$('#editDictionarySubpageTrigger'); |
| assertFalse(editDictionarySubpageTrigger.disabled); |
| spellCheckToggle.click(); |
| |
| assertTrue(editDictionarySubpageTrigger.disabled); |
| }); |
| |
| test('opens edit dictionary page', () => { |
| const editDictionarySubpageTrigger = |
| inputPage.$$('#editDictionarySubpageTrigger'); |
| editDictionarySubpageTrigger.click(); |
| const router = settings.Router.getInstance(); |
| assertEquals( |
| router.getCurrentRoute().getAbsolutePath(), |
| 'chrome://os-settings/osLanguages/editDictionary'); |
| }); |
| }); |
| |
| suite('add spell check languages dialog', () => { |
| let dialog; |
| let suggestedLanguages; |
| let allLanguages; |
| let cancelButton; |
| let actionButton; |
| |
| /** |
| * Returns the list items in the dialog. |
| * @return {!Array<!Element>} |
| */ |
| function getAllLanguagesCheckboxWithPolicies() { |
| // If an element (the <iron-list> in this case) is hidden in Polymer, |
| // Polymer will intelligently not update the DOM of the hidden element |
| // to prevent DOM updates that the user can't see. However, this means |
| // that when the <iron-list> is hidden (due to no results), the list |
| // items still exist in the DOM. |
| // This function should return the *visible* items that the user can |
| // select, so if the <iron-list> is hidden we should return an empty |
| // list instead. |
| const list = allLanguages.querySelector('iron-list'); |
| if (list.hidden || list.style.display === 'none') { |
| return []; |
| } |
| return [...allLanguages.querySelectorAll( |
| 'cr-checkbox-with-policy:not([hidden])')]; |
| } |
| |
| /** |
| * Returns the internal cr-checkboxes in allLanguages. |
| * @return {!Array<!Element>} |
| */ |
| function getAllLanguagesCheckboxes() { |
| const checkboxWithPolicies = getAllLanguagesCheckboxWithPolicies(); |
| return checkboxWithPolicies.map( |
| checkboxWithPolicy => checkboxWithPolicy.$.checkbox); |
| } |
| |
| setup(() => { |
| // Enable Update 2. |
| // We use the property directly instead of loadTimeData, as overriding |
| // loadTimeData does not work as the property is set using a value(). |
| inputPage.languageSettingsV2Update2Enabled_ = true; |
| // However, we should still set loadTimeData as some other code may use |
| // it (such as languages.js). |
| loadTimeData.overrideValues({enableLanguageSettingsV2Update2: true}); |
| Polymer.dom.flush(); |
| |
| assertFalse( |
| !!inputPage.$$('os-settings-add-spellcheck-languages-dialog')); |
| inputPage.$$('#addSpellcheckLanguages').click(); |
| Polymer.dom.flush(); |
| |
| dialog = inputPage.$$('os-settings-add-spellcheck-languages-dialog'); |
| assertTrue(!!dialog); |
| assertTrue(dialog.$.dialog.open); |
| |
| suggestedLanguages = dialog.$$('#suggestedLanguages'); |
| assertTrue(!!suggestedLanguages); |
| allLanguages = dialog.$$('#allLanguages'); |
| assertTrue(!!allLanguages); |
| |
| actionButton = dialog.$$('.action-button'); |
| assertTrue(!!actionButton); |
| cancelButton = dialog.$$('.cancel-button'); |
| assertTrue(!!cancelButton); |
| }); |
| |
| test('action button is enabled and disabled when necessary', () => { |
| // Mimic $$, but with a querySelectorAll instead of querySelector. |
| const checkboxes = getAllLanguagesCheckboxes(); |
| assertTrue(checkboxes.length > 0); |
| |
| // By default, no languages have been selected so the action button is |
| // disabled. |
| assertTrue(actionButton.disabled); |
| |
| // Selecting a language enables the action button. |
| checkboxes[0].click(); |
| assertFalse(actionButton.disabled); |
| |
| // Selecting the same language again disables the action button. |
| checkboxes[0].click(); |
| assertTrue(actionButton.disabled); |
| }); |
| |
| test('cancel button is never disabled', () => { |
| assertFalse(cancelButton.disabled); |
| }); |
| |
| test('initial expected layout', () => { |
| // As Swahili is an enabled language, it should be shown as a suggested |
| // language. |
| const suggestedItems = suggestedLanguages.querySelectorAll('cr-checkbox'); |
| assertEquals(suggestedItems.length, 1); |
| assertTrue(suggestedItems[0].textContent.includes('Swahili')); |
| |
| // There are four languages with spell check enabled in |
| // fake_language_settings_private.js: en-US, en-CA, sw, nb. |
| // en-US shouldn't be displayed as it is already enabled. |
| const allItems = getAllLanguagesCheckboxWithPolicies(); |
| assertEquals(allItems.length, 3); |
| assertTrue(allItems[0].textContent.includes('English (Canada)')); |
| assertTrue(allItems[1].textContent.includes('Swahili')); |
| assertTrue(allItems[2].textContent.includes('Norwegian Bokmål')); |
| |
| // By default, all checkboxes should not be disabled, and should not be |
| // checked. |
| const checkboxes = [...suggestedItems, ...getAllLanguagesCheckboxes()]; |
| assertTrue(checkboxes.every(checkbox => !checkbox.disabled)); |
| assertTrue(checkboxes.every(checkbox => !checkbox.checked)); |
| |
| // There should be a label for both sections. |
| const suggestedLabel = suggestedLanguages.querySelector('.label'); |
| assertTrue(!!suggestedLabel); |
| assertFalse(suggestedLabel.hidden); |
| |
| const allLanguagesLabel = allLanguages.querySelector('.label'); |
| assertTrue(!!allLanguagesLabel); |
| assertFalse(allLanguagesLabel.hidden); |
| }); |
| |
| test('can add single language and uncheck language', () => { |
| const checkboxes = getAllLanguagesCheckboxes(); |
| const swCheckbox = checkboxes[1]; |
| const nbCheckbox = checkboxes[2]; |
| |
| // By default, en-US should be the only enabled spell check dictionary. |
| assertDeepEquals( |
| ['en-US'], languageHelper.prefs.spellcheck.dictionaries.value); |
| |
| swCheckbox.click(); |
| assertTrue(swCheckbox.checked); |
| |
| // Check and uncheck nb to ensure that it gets "ignored". |
| nbCheckbox.click(); |
| assertTrue(nbCheckbox.checked); |
| |
| nbCheckbox.click(); |
| assertFalse(nbCheckbox.checked); |
| |
| actionButton.click(); |
| assertDeepEquals( |
| ['en-US', 'sw'], languageHelper.prefs.spellcheck.dictionaries.value); |
| assertFalse(dialog.$.dialog.open); |
| }); |
| |
| test('can add multiple languages', () => { |
| const checkboxes = getAllLanguagesCheckboxes(); |
| |
| assertDeepEquals( |
| ['en-US'], languageHelper.prefs.spellcheck.dictionaries.value); |
| |
| // Click en-CA and nb. |
| checkboxes[0].click(); |
| assertTrue(checkboxes[0].checked); |
| checkboxes[2].click(); |
| assertTrue(checkboxes[2].checked); |
| |
| actionButton.click(); |
| // The two possible results are en-US, en-CA, nb OR en-US, nb, en-CA. |
| // We do not care about the ordering of the last two, but the first one |
| // should still be en-US. |
| assertEquals( |
| 'en-US', languageHelper.prefs.spellcheck.dictionaries.value[0]); |
| // Note that .sort() mutates the array, but as this is the end of the test |
| // the prefs will be reset after this anyway. |
| assertDeepEquals( |
| ['en-CA', 'en-US', 'nb'], |
| languageHelper.prefs.spellcheck.dictionaries.value.sort()); |
| assertFalse(dialog.$.dialog.open); |
| }); |
| |
| test('policy disabled languages cannot be selected and show icon', () => { |
| // Force-disable sw. |
| languageHelper.setPrefValue('spellcheck.blocked_dictionaries', ['sw']); |
| Polymer.dom.flush(); |
| |
| const swCheckboxWithPolicy = getAllLanguagesCheckboxWithPolicies()[1]; |
| const swCheckbox = |
| swCheckboxWithPolicy.shadowRoot.querySelector('cr-checkbox'); |
| const swPolicyIcon = |
| swCheckboxWithPolicy.shadowRoot.querySelector('iron-icon'); |
| |
| assertTrue(swCheckbox.disabled); |
| assertFalse(swCheckbox.checked); |
| assertTrue(!!swPolicyIcon); |
| }); |
| |
| test('labels do not appear if there are no suggested languages', () => { |
| // Disable sw, the only default suggested language, as a web language. |
| languageHelper.disableLanguage('sw'); |
| Polymer.dom.flush(); |
| |
| /** |
| * @param {!HTMLElement|null} el |
| * @return {boolean} |
| */ |
| function isHidden(el) { |
| return !el || el.hidden || getComputedStyle(el).display === 'none' || |
| getComputedStyle(el).visibility === 'hidden'; |
| } |
| |
| // Suggested languages should not show up whatsoever. |
| assertTrue(isHidden(suggestedLanguages)); |
| // The label for all languages should not appear either. |
| assertTrue(isHidden(allLanguages.querySelector('.label'))); |
| }); |
| |
| test('input method languages appear as suggested languages', () => { |
| // Remove en-US from the dictionary list AND the enabled languages list. |
| languageHelper.setPrefValue('spellcheck.dictionaries', []); |
| languageHelper.disableLanguage('en-US'); |
| Polymer.dom.flush(); |
| |
| // Both Swahili (as it is an enabled language) and English (US) (as it is |
| // enabled as an input method) should appear in the list. |
| const suggestedListItems = |
| suggestedLanguages.querySelectorAll('.list-item'); |
| assertEquals(suggestedListItems.length, 2); |
| assertTrue(suggestedListItems[0].textContent.includes( |
| 'English (United States)')); |
| assertTrue(suggestedListItems[1].textContent.includes('Swahili')); |
| |
| // en-US should also appear in the all languages list now. |
| assertEquals(allLanguages.querySelectorAll('.list-item').length, 4); |
| }); |
| |
| test('searches languages on display name', () => { |
| const searchInput = dialog.$$('cr-search-field'); |
| |
| // Expecting a few languages to be displayed when no query exists. |
| assertGE(getAllLanguagesCheckboxWithPolicies().length, 1); |
| |
| // Issue query that matches the |displayedName| in lowercase. |
| searchInput.setValue('norwegian'); |
| Polymer.dom.flush(); |
| assertEquals(getAllLanguagesCheckboxWithPolicies().length, 1); |
| assertTrue(getAllLanguagesCheckboxWithPolicies()[0].textContent.includes( |
| 'Norwegian Bokmål')); |
| |
| // Issue query that matches the |nativeDisplayedName|. |
| searchInput.setValue('norsk'); |
| Polymer.dom.flush(); |
| assertEquals(getAllLanguagesCheckboxWithPolicies().length, 1); |
| |
| // Issue query that does not match any language. |
| searchInput.setValue('egaugnal'); |
| Polymer.dom.flush(); |
| assertEquals(getAllLanguagesCheckboxWithPolicies().length, 0); |
| assertFalse(dialog.$$('#no-search-results').hidden); |
| }); |
| |
| test('has escape key behavior working correctly', function() { |
| const searchInput = dialog.$$('cr-search-field'); |
| searchInput.setValue('dummyquery'); |
| |
| // Test that dialog is not closed if 'Escape' is pressed on the input |
| // and a search query exists. |
| MockInteractions.keyDownOn(searchInput, 19, [], 'Escape'); |
| assertTrue(dialog.$.dialog.open); |
| |
| // Test that dialog is closed if 'Escape' is pressed on the input and no |
| // search query exists. |
| searchInput.setValue(''); |
| MockInteractions.keyDownOn(searchInput, 19, [], 'Escape'); |
| assertFalse(dialog.$.dialog.open); |
| }); |
| }); |
| }); |