| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 /** @fileoverview Suite of tests for settings-languages-page. */ | |
| 6 | |
| 7 /** @const {string} Path to root from chrome/test/data/webui/settings/. */ | |
| 8 var ROOT_PATH = '../../../../../'; | |
| 9 | |
| 10 // Polymer BrowserTest fixture. | |
| 11 GEN_INCLUDE( | |
| 12 [ROOT_PATH + 'chrome/test/data/webui/polymer_browser_test_base.js']); | |
| 13 // SettingsPageBrowserTest fixture. | |
| 14 GEN_INCLUDE([ROOT_PATH + | |
| 15 'chrome/test/data/webui/settings/settings_page_browsertest.js']); | |
| 16 | |
| 17 /** | |
| 18 * Test class for settings-languages-page UI. | |
| 19 * @constructor | |
| 20 * @extends {SettingsPageBrowserTest} | |
| 21 */ | |
| 22 function SettingsLanguagesPageBrowserTest() {} | |
| 23 | |
| 24 SettingsLanguagesPageBrowserTest.prototype = { | |
| 25 __proto__: SettingsPageBrowserTest.prototype, | |
| 26 | |
| 27 /** @override */ | |
| 28 preLoad: function() { | |
| 29 SettingsPageBrowserTest.prototype.preLoad.call(this); | |
| 30 settingsHidePagesByDefaultForTest = true; | |
| 31 }, | |
| 32 }; | |
| 33 | |
| 34 // Flaky on Windows, Mac and Linux. See https://crbug.com/641400. | |
| 35 // | |
| 36 // May time out on debug builders and memory bots because the Settings page can | |
| 37 // take several seconds to load in a Release build and several times that in a | |
| 38 // Debug build. See https://crbug.com/558434. | |
| 39 // | |
| 40 // Disabling this test in general. | |
| 41 GEN('#define MAYBE_LanguagesPage DISABLED_LanguagesPage'); | |
| 42 | |
| 43 // Runs languages page tests. | |
| 44 TEST_F('SettingsLanguagesPageBrowserTest', 'MAYBE_LanguagesPage', function() { | |
| 45 var self = this; | |
| 46 | |
| 47 suiteSetup(function() { | |
| 48 self.toggleAdvanced(); | |
| 49 }); | |
| 50 | |
| 51 suite('languages page', function() { | |
| 52 testing.Test.disableAnimationsAndTransitions(); | |
| 53 | |
| 54 var languagesSection; | |
| 55 var languagesPage; | |
| 56 var languagesCollapse; | |
| 57 var languageHelper; | |
| 58 var actionMenu; | |
| 59 | |
| 60 /** | |
| 61 * @param {numExpected} Expected number of languages to eventually be | |
| 62 * enabled. | |
| 63 * @return {!Promise} Resolved when the number of enabled languages changes | |
| 64 * to match expectations. | |
| 65 */ | |
| 66 function whenNumEnabledLanguagesBecomes(numExpected) { | |
| 67 assert(!!languagesPage); | |
| 68 return new Promise(function(resolve, reject) { | |
| 69 languagesPage.addEventListener('languages-changed', function changed() { | |
| 70 if (languagesPage.languages.enabled.length != numExpected) | |
| 71 return; | |
| 72 resolve(); | |
| 73 languagesPage.removeEventListener('languages-changed', changed); | |
| 74 }); | |
| 75 }); | |
| 76 } | |
| 77 | |
| 78 // Returns supported languages that are not enabled. | |
| 79 function getAvailableLanguages() { | |
| 80 return languagesPage.languages.supported.filter(function(language) { | |
| 81 return !languageHelper.isLanguageEnabled(language.code); | |
| 82 }); | |
| 83 } | |
| 84 | |
| 85 suiteSetup(function() { | |
| 86 var page = self.basicPage; | |
| 87 page.set('pageVisibility.languages', true); | |
| 88 Polymer.dom.flush(); | |
| 89 | |
| 90 languagesSection = assert(this.getSection(page, 'languages')); | |
| 91 languagesPage = assert( | |
| 92 languagesSection.querySelector('settings-languages-page')); | |
| 93 languagesCollapse = languagesPage.$.languagesCollapse; | |
| 94 languagesCollapse.opened = true; | |
| 95 actionMenu = languagesPage.$.menu.get(); | |
| 96 | |
| 97 languageHelper = languagesPage.languageHelper; | |
| 98 return languageHelper.whenReady(); | |
| 99 }.bind(this)); | |
| 100 | |
| 101 teardown(function(done) { | |
| 102 if (actionMenu.open) | |
| 103 actionMenu.close(); | |
| 104 | |
| 105 // Close the section if we're in a sub-page. | |
| 106 if (settings.getCurrentRoute().isSubpage()) { | |
| 107 settings.navigateTo(settings.Route.BASIC); | |
| 108 setTimeout(done); | |
| 109 } else { | |
| 110 done(); | |
| 111 } | |
| 112 }); | |
| 113 | |
| 114 suite('add languages dialog', function() { | |
| 115 var dialog; | |
| 116 var dialogItems; | |
| 117 var cancelButton; | |
| 118 var actionButton; | |
| 119 | |
| 120 setup(function(done) { | |
| 121 var addLanguagesButton = | |
| 122 languagesCollapse.querySelector('#addLanguages'); | |
| 123 MockInteractions.tap(addLanguagesButton); | |
| 124 | |
| 125 // The page stamps the dialog, registers listeners, and populates the | |
| 126 // iron-list asynchronously at microtask timing, so wait for a new task. | |
| 127 setTimeout(function() { | |
| 128 dialog = languagesPage.$$('settings-add-languages-dialog'); | |
| 129 assertTrue(!!dialog); | |
| 130 | |
| 131 actionButton = assert(dialog.$$('.action-button')); | |
| 132 cancelButton = assert(dialog.$$('.cancel-button')); | |
| 133 | |
| 134 // The fixed-height dialog's iron-list should stamp far fewer than | |
| 135 // 50 items. | |
| 136 dialogItems = | |
| 137 dialog.$.dialog.querySelectorAll('.list-item:not([hidden])'); | |
| 138 assertGT(dialogItems.length, 1); | |
| 139 assertLT(dialogItems.length, 50); | |
| 140 | |
| 141 // No languages have been checked, so the action button is disabled. | |
| 142 assertTrue(actionButton.disabled); | |
| 143 assertFalse(cancelButton.disabled); | |
| 144 | |
| 145 done(); | |
| 146 }); | |
| 147 }); | |
| 148 | |
| 149 // After every test, check that the dialog is removed from the DOM. | |
| 150 teardown(function() { | |
| 151 Polymer.dom.flush(); | |
| 152 assertEquals(null, languagesPage.$$('settings-add-languages-dialog')); | |
| 153 }); | |
| 154 | |
| 155 test('cancel', function() { | |
| 156 // Canceling the dialog should close and remove it. | |
| 157 MockInteractions.tap(cancelButton); | |
| 158 }); | |
| 159 | |
| 160 test('add languages and cancel', function(done) { | |
| 161 var numEnabled = languagesPage.languages.enabled.length; | |
| 162 | |
| 163 // Check some languages. | |
| 164 MockInteractions.tap(dialogItems[0]); | |
| 165 MockInteractions.tap(dialogItems[1]); | |
| 166 | |
| 167 // Canceling the dialog should close and remove it without enabling | |
| 168 // the checked languages. A small timeout lets us check this. | |
| 169 MockInteractions.tap(cancelButton); | |
| 170 setTimeout(function() { | |
| 171 // Number of enabled languages should be the same. | |
| 172 assertEquals(numEnabled, languagesPage.languages.enabled.length); | |
| 173 done(); | |
| 174 }, 100); | |
| 175 }); | |
| 176 | |
| 177 test('add languages and confirm', function() { | |
| 178 var numEnabled = languagesPage.languages.enabled.length; | |
| 179 | |
| 180 // No languages have been checked, so the action button is inert. | |
| 181 MockInteractions.tap(actionButton); | |
| 182 Polymer.dom.flush(); | |
| 183 assertEquals(dialog, languagesPage.$$('settings-add-languages-dialog')); | |
| 184 | |
| 185 // Check and uncheck one language. | |
| 186 MockInteractions.tap(dialogItems[0]); | |
| 187 assertFalse(actionButton.disabled); | |
| 188 MockInteractions.tap(dialogItems[0]); | |
| 189 assertTrue(actionButton.disabled); | |
| 190 | |
| 191 // Check multiple languages. | |
| 192 MockInteractions.tap(dialogItems[0]); | |
| 193 MockInteractions.tap(dialogItems[1]); | |
| 194 assertFalse(actionButton.disabled); | |
| 195 | |
| 196 // The action button should close and remove the dialog, enabling the | |
| 197 // checked languages. | |
| 198 MockInteractions.tap(actionButton); | |
| 199 | |
| 200 // Wait for the languages to be enabled by the browser. | |
| 201 return whenNumEnabledLanguagesBecomes(numEnabled + 2); | |
| 202 }); | |
| 203 }); | |
| 204 | |
| 205 suite('language menu', function() { | |
| 206 var origTranslateEnabled; | |
| 207 | |
| 208 /** | |
| 209 * Finds, asserts and returns the menu item for the given i18n key. | |
| 210 * @param {string} i18nKey Name of the i18n string for the item's text. | |
| 211 * @return {!HTMLElement} Menu item. | |
| 212 */ | |
| 213 function getMenuItem(i18nKey) { | |
| 214 var i18nString = assert(loadTimeData.getString(i18nKey)); | |
| 215 var menuItems = actionMenu.querySelectorAll('.dropdown-item'); | |
| 216 var menuItem = Array.from(menuItems).find( | |
| 217 item => item.textContent.trim() == i18nString); | |
| 218 return assert(menuItem, 'Menu item "' + i18nKey + '" not found'); | |
| 219 } | |
| 220 | |
| 221 /** | |
| 222 * Checks the visibility of each expected menu item button. | |
| 223 * param {!Object<boolean>} Dictionary from i18n keys to expected | |
| 224 * visibility of those menu items. | |
| 225 */ | |
| 226 function assertMenuItemButtonsVisible(buttonVisibility) { | |
| 227 assertTrue(actionMenu.open); | |
| 228 for (var buttonKey of Object.keys(buttonVisibility)) { | |
| 229 var buttonItem = getMenuItem(buttonKey); | |
| 230 assertEquals(!buttonVisibility[buttonKey], buttonItem.hidden, | |
| 231 'Menu item "' + buttonKey + '" hidden'); | |
| 232 } | |
| 233 } | |
| 234 | |
| 235 suiteSetup(function() { | |
| 236 // Cache the value of Translate to avoid side effects. | |
| 237 origTranslateEnabled = languageHelper.prefs.translate.enabled.value; | |
| 238 }); | |
| 239 | |
| 240 suiteTeardown(function() { | |
| 241 var cur = languageHelper.prefs.translate.enabled.value; | |
| 242 // Restore the value of Translate. | |
| 243 languageHelper.setPrefValue('translate.enabled', origTranslateEnabled); | |
| 244 cur = languageHelper.prefs.translate.enabled.value; | |
| 245 }); | |
| 246 | |
| 247 test('structure', function() { | |
| 248 var languageOptionsDropdownTrigger = languagesCollapse.querySelector( | |
| 249 'paper-icon-button'); | |
| 250 assertTrue(!!languageOptionsDropdownTrigger); | |
| 251 MockInteractions.tap(languageOptionsDropdownTrigger); | |
| 252 assertTrue(actionMenu.open); | |
| 253 | |
| 254 // Enable Translate so the menu always shows the Translate checkbox. | |
| 255 languageHelper.setPrefValue('translate.enabled', true); | |
| 256 | |
| 257 var separator = actionMenu.querySelector('hr'); | |
| 258 assertEquals(1, separator.offsetHeight); | |
| 259 | |
| 260 // Disable Translate. On platforms that can't change the UI language, | |
| 261 // this hides all the checkboxes, so the separator isn't needed. | |
| 262 // Chrome OS and Windows still show a checkbox and thus the separator. | |
| 263 languageHelper.setPrefValue('translate.enabled', false); | |
| 264 assertEquals( | |
| 265 cr.isChromeOS || cr.isWindows ? 1 : 0, separator.offsetHeight); | |
| 266 }); | |
| 267 | |
| 268 test('test translate.enable toggle', function() { | |
| 269 languageHelper.setPrefValue('translate.enabled', true); | |
| 270 var toggle = languagesPage.$.offerTranslateOtherLangs.root | |
| 271 .querySelectorAll('paper-toggle-button')[0]; | |
| 272 assertTrue(!!toggle); | |
| 273 | |
| 274 // Clicking on toggle switch it to false. | |
| 275 MockInteractions.tap(toggle); | |
| 276 var newToggleValue = languageHelper.prefs.translate.enabled.value; | |
| 277 assertFalse(newToggleValue); | |
| 278 | |
| 279 // Clicking on toggle switch it to true again. | |
| 280 MockInteractions.tap(toggle); | |
| 281 newToggleValue = languageHelper.prefs.translate.enabled.value; | |
| 282 assertTrue(newToggleValue); | |
| 283 }); | |
| 284 | |
| 285 test('toggle translate for a specific language', function(done) { | |
| 286 // Enable Translate so the menu always shows the Translate checkbox. | |
| 287 languageHelper.setPrefValue('translate.enabled', true); | |
| 288 languagesPage.set('languages.translateTarget', 'foo'); | |
| 289 languagesPage.set('languages.enabled.1.supportsTranslate', true); | |
| 290 | |
| 291 var languageOptionsDropdownTrigger = | |
| 292 languagesCollapse.querySelectorAll('paper-icon-button')[1]; | |
| 293 assertTrue(!!languageOptionsDropdownTrigger); | |
| 294 MockInteractions.tap(languageOptionsDropdownTrigger); | |
| 295 assertTrue(actionMenu.open); | |
| 296 | |
| 297 // Toggle the translate option. | |
| 298 var translateOption = getMenuItem('offerToTranslateInThisLanguage'); | |
| 299 assertFalse(translateOption.disabled); | |
| 300 MockInteractions.tap(translateOption); | |
| 301 | |
| 302 // Menu should stay open briefly. | |
| 303 assertTrue(actionMenu.open); | |
| 304 // Guaranteed to run later than the menu close delay. | |
| 305 setTimeout(function() { | |
| 306 assertFalse(actionMenu.open); | |
| 307 done(); | |
| 308 }, settings.kMenuCloseDelay + 1); | |
| 309 }); | |
| 310 | |
| 311 test('disable translate hides language-specific option', function() { | |
| 312 // Disables translate. | |
| 313 languageHelper.setPrefValue('translate.enabled', false); | |
| 314 languagesPage.set('languages.translateTarget', 'foo'); | |
| 315 languagesPage.set('languages.enabled.1.supportsTranslate', true); | |
| 316 | |
| 317 // Makes sure language-specific menu exists. | |
| 318 var languageOptionsDropdownTrigger = | |
| 319 languagesCollapse.querySelectorAll('paper-icon-button')[1]; | |
| 320 assertTrue(!!languageOptionsDropdownTrigger); | |
| 321 MockInteractions.tap(languageOptionsDropdownTrigger); | |
| 322 assertTrue(actionMenu.open); | |
| 323 | |
| 324 // The language-specific translation option should be hidden. | |
| 325 var translateOption = actionMenu.querySelector('#offerTranslations'); | |
| 326 assertTrue(!!translateOption); | |
| 327 assertTrue(translateOption.hidden); | |
| 328 }); | |
| 329 | |
| 330 test('remove language', function() { | |
| 331 var numEnabled = languagesPage.languages.enabled.length; | |
| 332 | |
| 333 // Enabled a language which we can then disable. | |
| 334 var newLanguage = assert(getAvailableLanguages()[0]); | |
| 335 languageHelper.enableLanguage(newLanguage.code); | |
| 336 | |
| 337 // Wait for the language to be enabled. | |
| 338 return whenNumEnabledLanguagesBecomes(numEnabled + 1).then(function() { | |
| 339 // Populate the dom-repeat. | |
| 340 Polymer.dom.flush(); | |
| 341 | |
| 342 // Find the new language item. | |
| 343 var items = languagesCollapse.querySelectorAll('.list-item'); | |
| 344 var domRepeat = assert( | |
| 345 languagesCollapse.querySelector('template[is="dom-repeat"]')); | |
| 346 var item = Array.from(items).find(function(el) { | |
| 347 return domRepeat.itemForElement(el) && | |
| 348 domRepeat.itemForElement(el).language == newLanguage; | |
| 349 }); | |
| 350 | |
| 351 // Open the menu and select Remove. | |
| 352 MockInteractions.tap(item.querySelector('paper-icon-button')); | |
| 353 | |
| 354 assertTrue(actionMenu.open); | |
| 355 var removeMenuItem = getMenuItem('removeLanguage'); | |
| 356 assertFalse(removeMenuItem.disabled); | |
| 357 MockInteractions.tap(removeMenuItem); | |
| 358 assertFalse(actionMenu.open); | |
| 359 | |
| 360 // We should go back down to the original number of enabled languages. | |
| 361 return whenNumEnabledLanguagesBecomes(numEnabled); | |
| 362 }).then(function() { | |
| 363 assertFalse(languageHelper.isLanguageEnabled(newLanguage.code)); | |
| 364 }); | |
| 365 }); | |
| 366 | |
| 367 test('move up/down buttons', function() { | |
| 368 // Add several languages. | |
| 369 var numEnabled = languagesPage.languages.enabled.length; | |
| 370 var available = getAvailableLanguages(); | |
| 371 for (var i = 0; i < 4; i++) | |
| 372 languageHelper.enableLanguage(assert(available[i]).code); | |
| 373 | |
| 374 return whenNumEnabledLanguagesBecomes(numEnabled + 4).then(function() { | |
| 375 Polymer.dom.flush(); | |
| 376 | |
| 377 var menuButtons = | |
| 378 languagesCollapse.querySelectorAll( | |
| 379 '.list-item paper-icon-button[icon="cr:more-vert"]'); | |
| 380 | |
| 381 // First language should not have "Move up" or "Move to top". | |
| 382 MockInteractions.tap(menuButtons[0]); | |
| 383 assertMenuItemButtonsVisible({ | |
| 384 moveToTop: false, moveUp: false, moveDown: true, | |
| 385 }); | |
| 386 actionMenu.close(); | |
| 387 | |
| 388 // Second language should not have "Move up". | |
| 389 MockInteractions.tap(menuButtons[1]); | |
| 390 assertMenuItemButtonsVisible({ | |
| 391 moveToTop: true, moveUp: false, moveDown: true, | |
| 392 }); | |
| 393 actionMenu.close(); | |
| 394 | |
| 395 // Middle languages should have all buttons. | |
| 396 MockInteractions.tap(menuButtons[2]); | |
| 397 assertMenuItemButtonsVisible({ | |
| 398 moveToTop: true, moveUp: true, moveDown: true, | |
| 399 }); | |
| 400 actionMenu.close(); | |
| 401 | |
| 402 // Last language should not have "Move down". | |
| 403 MockInteractions.tap(menuButtons[menuButtons.length - 1]); | |
| 404 assertMenuItemButtonsVisible({ | |
| 405 moveToTop: true, moveUp: true, moveDown: false, | |
| 406 }); | |
| 407 actionMenu.close(); | |
| 408 }); | |
| 409 }); | |
| 410 }); | |
| 411 | |
| 412 test('manage input methods', function() { | |
| 413 var inputMethodsCollapse = languagesPage.$.inputMethodsCollapse; | |
| 414 var inputMethodSettingsExist = !!inputMethodsCollapse; | |
| 415 if (cr.isChromeOS) { | |
| 416 assertTrue(inputMethodSettingsExist); | |
| 417 var manageInputMethodsButton = | |
| 418 inputMethodsCollapse.querySelector('#manageInputMethods'); | |
| 419 MockInteractions.tap(manageInputMethodsButton); | |
| 420 assertTrue(!!languagesPage.$$('settings-manage-input-methods-page')); | |
| 421 } else { | |
| 422 assertFalse(inputMethodSettingsExist); | |
| 423 } | |
| 424 }); | |
| 425 | |
| 426 test('spellcheck', function() { | |
| 427 var spellCheckCollapse = languagesPage.$.spellCheckCollapse; | |
| 428 var spellCheckSettingsExist = !!spellCheckCollapse; | |
| 429 if (cr.isMac) { | |
| 430 assertFalse(spellCheckSettingsExist); | |
| 431 } else { | |
| 432 assertTrue(spellCheckSettingsExist); | |
| 433 | |
| 434 // Ensure no language has spell check enabled. | |
| 435 for (var i = 0; i < languagesPage.languages.enabled.length; i++) { | |
| 436 languagesPage.set( | |
| 437 'languages.enabled.' + i + '.spellCheckEnabled', false); | |
| 438 } | |
| 439 | |
| 440 // The row button should have the extra row only if some language has | |
| 441 // spell check enabled. | |
| 442 var triggerRow = languagesPage.$.spellCheckSubpageTrigger; | |
| 443 assertFalse(triggerRow.classList.contains('two-line')); | |
| 444 assertEquals( | |
| 445 0, triggerRow.querySelector('.secondary').textContent.length); | |
| 446 | |
| 447 languagesPage.set( | |
| 448 'languages.enabled.0.language.supportsSpellcheck', true); | |
| 449 languagesPage.set('languages.enabled.0.spellCheckEnabled', true); | |
| 450 assertTrue(triggerRow.classList.contains('two-line')); | |
| 451 assertLT( | |
| 452 0, triggerRow.querySelector('.secondary').textContent.length); | |
| 453 } | |
| 454 }); | |
| 455 }.bind(this)); | |
| 456 | |
| 457 // TODO(michaelpg): Test more aspects of the languages UI. | |
| 458 | |
| 459 // Run all registered tests. | |
| 460 mocha.run(); | |
| 461 }); | |
| OLD | NEW |