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 |