1 // Copyright (c) 2012 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.
5 GEN('#include "chrome/browser/ui/webui/options/options_browsertest.h"');
7 /** @const */ var SUPERVISED_USERS_PREF = 'profile.managed_users';
10 * Wait for the method specified by |methodName|, on the |object| object, to be
11 * called, then execute |afterFunction|.
12 * @param {*} object Object with callable property named |methodName|.
13 * @param {string} methodName The name of the property on |object| to use as a
15 * @param {!Function} afterFunction A function to call after object.methodName()
18 function waitForResponse(object, methodName, afterFunction) {
19 var originalCallback = object[methodName];
21 // Install a wrapper that temporarily replaces the original function.
22 object[methodName] = function() {
23 object[methodName] = originalCallback;
24 originalCallback.apply(this, arguments);
30 * Wait for the global window.onpopstate callback to be called (after a tab
31 * history navigation), then execute |afterFunction|.
32 * @param {!Function} afterFunction A function to call after pop state events.
34 function waitForPopstate(afterFunction) {
35 waitForResponse(window, 'onpopstate', afterFunction);
39 * TestFixture for OptionsPage WebUI testing.
40 * @extends {testing.Test}
43 function OptionsWebUITest() {}
45 OptionsWebUITest.prototype = {
46 __proto__: testing.Test.prototype,
49 accessibilityIssuesAreErrors: true,
53 // user-image-stream is a streaming video element used for capturing a
54 // user image during OOBE.
55 this.accessibilityAuditConfig.ignoreSelectors('videoWithoutCaptions',
56 '.user-image-stream');
60 * Browse to the options page & call our preLoad().
62 browsePreload: 'chrome://settings-frame',
67 * Register a mock handler to ensure expectations are met and options pages
71 this.makeAndRegisterMockHandler(
72 ['defaultZoomFactorAction',
81 'coreOptionsUserMetricsAction',
84 // Register stubs for methods expected to be called before/during tests.
85 // Specific expectations can be made in the tests themselves.
86 this.mockHandler.stubs().fetchPrefs(ANYTHING);
87 this.mockHandler.stubs().observePrefs(ANYTHING);
88 this.mockHandler.stubs().coreOptionsUserMetricsAction(ANYTHING);
92 // Crashes on Mac only. See http://crbug.com/79181
93 GEN('#if defined(OS_MACOSX)');
94 GEN('#define MAYBE_testSetBooleanPrefTriggers ' +
95 'DISABLED_testSetBooleanPrefTriggers');
97 GEN('#define MAYBE_testSetBooleanPrefTriggers testSetBooleanPrefTriggers');
98 GEN('#endif // defined(OS_MACOSX)');
100 TEST_F('OptionsWebUITest', 'MAYBE_testSetBooleanPrefTriggers', function() {
101 // TODO(dtseng): make generic to click all buttons.
103 document.querySelector('input[pref="browser.show_home_button"]');
104 var trueListValue = [
105 'browser.show_home_button',
107 'Options_Homepage_HomeButton',
109 // Note: this expectation is checked in testing::Test::tearDown.
110 this.mockHandler.expects(once()).setBooleanPref(trueListValue);
112 // Cause the handler to be called.
113 showHomeButton.click();
114 showHomeButton.blur();
118 // Not meant to run on ChromeOS at this time.
119 // Not finishing in windows. http://crbug.com/81723
120 TEST_F('OptionsWebUITest', 'DISABLED_testRefreshStaysOnCurrentPage',
122 assertTrue($('search-engine-manager-page').hidden);
123 var item = $('manage-default-search-engines');
126 assertFalse($('search-engine-manager-page').hidden);
128 window.location.reload();
130 assertEquals('chrome://settings-frame/searchEngines', document.location.href);
131 assertFalse($('search-engine-manager-page').hidden);
136 * Test the default zoom factor select element.
138 TEST_F('OptionsWebUITest', 'testDefaultZoomFactor', function() {
139 // The expected minimum length of the |defaultZoomFactor| element.
140 var defaultZoomFactorMinimumLength = 10;
141 // Verify that the zoom factor element exists.
142 var defaultZoomFactor = $('defaultZoomFactor');
143 assertNotEquals(defaultZoomFactor, null);
145 // Verify that the zoom factor element has a reasonable number of choices.
146 expectGE(defaultZoomFactor.options.length, defaultZoomFactorMinimumLength);
148 // Simulate a change event, selecting the highest zoom value. Verify that
149 // the javascript handler was invoked once.
150 this.mockHandler.expects(once()).defaultZoomFactorAction(NOT_NULL).
151 will(callFunction(function() { }));
152 defaultZoomFactor.selectedIndex = defaultZoomFactor.options.length - 1;
153 var event = {target: defaultZoomFactor};
154 if (defaultZoomFactor.onchange) defaultZoomFactor.onchange(event);
159 * If |confirmInterstitial| is true, the OK button of the Do Not Track
160 * interstitial is pressed, otherwise the abort button is pressed.
161 * @param {boolean} confirmInterstitial Whether to confirm the Do Not Track
164 OptionsWebUITest.prototype.testDoNotTrackInterstitial =
165 function(confirmInterstitial) {
166 Preferences.prefsFetchedCallback({'enable_do_not_track': {'value': false}});
167 var buttonToClick = confirmInterstitial ? $('do-not-track-confirm-ok') :
168 $('do-not-track-confirm-cancel');
169 var dntCheckbox = $('do-not-track-enabled');
170 var dntOverlay = PageManager.registeredOverlayPages['donottrackconfirm'];
171 assertFalse(dntCheckbox.checked);
173 var visibleChangeCounter = 0;
174 var visibleChangeHandler = function() {
175 ++visibleChangeCounter;
176 switch (visibleChangeCounter) {
178 window.setTimeout(function() {
179 assertTrue(dntOverlay.visible);
180 buttonToClick.click();
184 window.setTimeout(function() {
185 assertFalse(dntOverlay.visible);
186 assertEquals(confirmInterstitial, dntCheckbox.checked);
187 dntOverlay.removeEventListener(visibleChangeHandler);
195 dntOverlay.addEventListener('visibleChange', visibleChangeHandler);
197 if (confirmInterstitial) {
198 this.mockHandler.expects(once()).setBooleanPref(
199 ['enable_do_not_track', true, 'Options_DoNotTrackCheckbox']);
201 // The mock handler complains if setBooleanPref is called even though
208 TEST_F('OptionsWebUITest', 'EnableDoNotTrackAndConfirmInterstitial',
210 this.testDoNotTrackInterstitial(true);
213 TEST_F('OptionsWebUITest', 'EnableDoNotTrackAndCancelInterstitial',
215 this.testDoNotTrackInterstitial(false);
218 // Check that the "Do not Track" preference can be correctly disabled.
219 // In order to do that, we need to enable it first.
220 TEST_F('OptionsWebUITest', 'EnableAndDisableDoNotTrack', function() {
221 Preferences.prefsFetchedCallback({'enable_do_not_track': {'value': false}});
222 var dntCheckbox = $('do-not-track-enabled');
223 var dntOverlay = PageManager.registeredOverlayPages.donottrackconfirm;
224 assertFalse(dntCheckbox.checked);
226 var visibleChangeCounter = 0;
227 var visibleChangeHandler = function() {
228 ++visibleChangeCounter;
229 switch (visibleChangeCounter) {
231 window.setTimeout(function() {
232 assertTrue(dntOverlay.visible);
233 $('do-not-track-confirm-ok').click();
237 window.setTimeout(function() {
238 assertFalse(dntOverlay.visible);
239 assertTrue(dntCheckbox.checked);
240 dntOverlay.removeEventListener(visibleChangeHandler);
248 dntOverlay.addEventListener('visibleChange', visibleChangeHandler);
250 this.mockHandler.expects(once()).setBooleanPref(
251 eq(['enable_do_not_track', true, 'Options_DoNotTrackCheckbox']));
253 var verifyCorrectEndState = function() {
254 window.setTimeout(function() {
255 assertFalse(dntOverlay.visible);
256 assertFalse(dntCheckbox.checked);
260 this.mockHandler.expects(once()).setBooleanPref(
261 eq(['enable_do_not_track', false, 'Options_DoNotTrackCheckbox'])).will(
262 callFunction(verifyCorrectEndState));
267 // Verify that preventDefault() is called on 'Enter' keydown events that trigger
268 // the default button. If this doesn't happen, other elements that may get
269 // focus (by the overlay closing for instance), will execute in addition to the
270 // default button. See crbug.com/268336.
271 TEST_F('OptionsWebUITest', 'EnterPreventsDefault', function() {
272 var page = HomePageOverlay.getInstance();
273 PageManager.showPageByName(page.name);
274 var event = new KeyboardEvent('keydown', {
277 'keyIdentifier': 'Enter'
279 assertFalse(event.defaultPrevented);
280 page.pageDiv.dispatchEvent(event);
281 assertTrue(event.defaultPrevented);
285 // Verifies that sending an empty list of indexes to move doesn't crash chrome.
286 TEST_F('OptionsWebUITest', 'emptySelectedIndexesDoesntCrash', function() {
287 chrome.send('dragDropStartupPage', [0, []]);
288 setTimeout(testDone);
291 // This test turns out to be flaky on all platforms.
292 // See http://crbug.com/315250.
294 // An overlay's position should remain the same as it shows.
295 TEST_F('OptionsWebUITest', 'DISABLED_OverlayShowDoesntShift', function() {
296 var overlayName = 'startup';
297 var overlay = $('startup-overlay');
298 var frozenPages = document.getElementsByClassName('frozen'); // Gets updated.
299 expectEquals(0, frozenPages.length);
301 document.addEventListener('webkitTransitionEnd', function(e) {
302 if (e.target != overlay)
305 assertFalse(overlay.classList.contains('transparent'));
306 expectEquals(numFrozenPages, frozenPages.length);
310 PageManager.showPageByName(overlayName);
311 var numFrozenPages = frozenPages.length;
312 expectGT(numFrozenPages, 0);
315 GEN('#if defined(OS_CHROMEOS)');
316 // Verify that range inputs respond to touch events. Currently only Chrome OS
317 // uses slider options.
318 TEST_F('OptionsWebUITest', 'RangeInputHandlesTouchEvents', function() {
319 this.mockHandler.expects(once()).setIntegerPref([
320 'settings.touchpad.sensitivity2', 1]);
322 var touchpadRange = $('touchpad-sensitivity-range');
323 var event = document.createEvent('UIEvent');
324 event.initUIEvent('touchstart', true, true, window);
325 touchpadRange.dispatchEvent(event);
327 event = document.createEvent('UIEvent');
328 event.initUIEvent('touchmove', true, true, window);
329 touchpadRange.dispatchEvent(event);
331 touchpadRange.value = 1;
333 event = document.createEvent('UIEvent');
334 event.initUIEvent('touchend', true, true, window);
335 touchpadRange.dispatchEvent(event);
337 // touchcancel should also trigger the handler, since it
338 // changes the slider position.
339 this.mockHandler.expects(once()).setIntegerPref([
340 'settings.touchpad.sensitivity2', 2]);
342 event = document.createEvent('UIEvent');
343 event.initUIEvent('touchstart', true, true, window);
344 touchpadRange.dispatchEvent(event);
346 touchpadRange.value = 2;
348 event = document.createEvent('UIEvent');
349 event.initUIEvent('touchcancel', true, true, window);
350 touchpadRange.dispatchEvent(event);
354 GEN('#endif'); // defined(OS_CHROMEOS)
357 * TestFixture for OptionsPage WebUI testing including tab history and support
358 * for preference manipulation. If you don't need the features in the C++
359 * fixture, use the simpler OptionsWebUITest (above) instead.
360 * @extends {testing.Test}
363 function OptionsWebUIExtendedTest() {}
365 OptionsWebUIExtendedTest.prototype = {
366 __proto__: testing.Test.prototype,
369 browsePreload: 'chrome://settings-frame',
372 typedefCppFixture: 'OptionsBrowserTest',
374 testGenPreamble: function() {
375 // Start with no supervised users managed by this profile.
376 GEN(' ClearPref("' + SUPERVISED_USERS_PREF + '");');
384 // user-image-stream is a streaming video element used for capturing a
385 // user image during OOBE.
386 this.accessibilityAuditConfig.ignoreSelectors('videoWithoutCaptions',
387 '.user-image-stream');
391 * Asserts that two non-nested arrays are equal. The arrays must contain only
392 * plain data types, no nested arrays or other objects.
393 * @param {Array} expected An array of expected values.
394 * @param {Array} result An array of actual values.
395 * @param {boolean} doSort If true, the arrays will be sorted before being
397 * @param {string} description A brief description for the array of actual
398 * values, to use in an error message if the arrays differ.
401 compareArrays_: function(expected, result, doSort, description) {
402 var errorMessage = '\n' + description + ': ' + result +
403 '\nExpected: ' + expected;
404 assertEquals(expected.length, result.length, errorMessage);
406 var expectedSorted = expected.slice();
407 var resultSorted = result.slice();
409 expectedSorted.sort();
413 for (var i = 0; i < expectedSorted.length; ++i) {
414 assertEquals(expectedSorted[i], resultSorted[i], errorMessage);
419 * Verifies that the correct pages are currently open/visible.
420 * @param {!Array.<string>} expectedPages An array of page names expected to
421 * be open, with the topmost listed last.
422 * @param {string=} opt_expectedUrl The URL path, including hash, expected to
423 * be open. If undefined, the topmost (last) page name in |expectedPages|
424 * will be used. In either case, 'chrome://settings-frame/' will be
428 verifyOpenPages_: function(expectedPages, opt_expectedUrl) {
429 // Check the topmost page.
430 expectEquals(null, PageManager.getVisibleBubble());
431 var currentPage = PageManager.getTopmostVisiblePage();
433 var lastExpected = expectedPages[expectedPages.length - 1];
434 expectEquals(lastExpected, currentPage.name);
435 // We'd like to check the title too, but we have to load the settings-frame
436 // instead of the outer settings page in order to have access to
437 // OptionsPage, and setting the title from within the settings-frame fails
438 // because of cross-origin access restrictions.
439 // TODO(pamg): Add a test fixture that loads chrome://settings and uses
440 // UI elements to access sub-pages, so we can test the titles and
442 var expectedUrl = (typeof opt_expectedUrl == 'undefined') ?
443 lastExpected : opt_expectedUrl;
444 var fullExpectedUrl = 'chrome://settings-frame/' + expectedUrl;
445 expectEquals(fullExpectedUrl, window.location.href);
447 // Collect open pages.
448 var allPageNames = Object.keys(PageManager.registeredPages).concat(
449 Object.keys(PageManager.registeredOverlayPages));
451 for (var i = 0; i < allPageNames.length; ++i) {
452 var name = allPageNames[i];
453 var page = PageManager.registeredPages[name] ||
454 PageManager.registeredOverlayPages[name];
456 openPages.push(page.name);
459 this.compareArrays_(expectedPages, openPages, true, 'Open pages');
463 * Verifies that the correct URLs are listed in the history. Asynchronous.
464 * @param {!Array.<string>} expectedHistory An array of URL paths expected to
465 * be in the tab navigation history, sorted by visit time, including the
466 * current page as the last entry. The base URL (chrome://settings-frame/)
467 * will be prepended to each. An initial 'about:blank' history entry is
468 * assumed and should not be included in this list.
469 * @param {Function=} callback A function to be called after the history has
470 * been verified successfully. May be undefined.
473 verifyHistory_: function(expectedHistory, callback) {
475 OptionsWebUIExtendedTest.verifyHistoryCallback = function(results) {
476 // The history always starts with a blank page.
477 assertEquals('about:blank', results.shift());
478 var fullExpectedHistory = [];
479 for (var i = 0; i < expectedHistory.length; ++i) {
480 fullExpectedHistory.push(
481 'chrome://settings-frame/' + expectedHistory[i]);
483 self.compareArrays_(fullExpectedHistory, results, false, 'History');
487 // The C++ fixture will call verifyHistoryCallback with the results.
488 chrome.send('optionsTestReportHistory');
492 * Overrides the page callbacks for the given PageManager overlay to verify
493 * that they are not called.
494 * @param {Object} overlay The singleton instance of the overlay.
497 prohibitChangesToOverlay_: function(overlay) {
498 overlay.initializePage =
499 overlay.didShowPage =
500 overlay.didClosePage = function() {
502 'Overlay was affected when changes were prohibited.');
508 * Set by verifyHistory_ to incorporate a followup callback, then called by the
509 * C++ fixture with the navigation history to be verified.
512 OptionsWebUIExtendedTest.verifyHistoryCallback = null;
514 // Show the search page with no query string, to fall back to the settings page.
515 // Test disabled because it's flaky. crbug.com/303841
516 TEST_F('OptionsWebUIExtendedTest', 'DISABLED_ShowSearchPageNoQuery',
518 PageManager.showPageByName('search');
519 this.verifyOpenPages_(['settings']);
520 this.verifyHistory_(['settings'], testDone);
523 // Manipulate the search page via the search field.
524 TEST_F('OptionsWebUIExtendedTest', 'ShowSearchFromField', function() {
525 $('search-field').onsearch({currentTarget: {value: 'query'}});
526 this.verifyOpenPages_(['settings', 'search'], 'search#query');
527 this.verifyHistory_(['', 'search#query'], function() {
528 $('search-field').onsearch({currentTarget: {value: 'query2'}});
529 this.verifyOpenPages_(['settings', 'search'], 'search#query2');
530 this.verifyHistory_(['', 'search#query', 'search#query2'], function() {
531 $('search-field').onsearch({currentTarget: {value: ''}});
532 this.verifyOpenPages_(['settings'], '');
533 this.verifyHistory_(['', 'search#query', 'search#query2', ''], testDone);
538 // Show a page without updating history.
539 TEST_F('OptionsWebUIExtendedTest', 'ShowPageNoHistory', function() {
540 this.verifyOpenPages_(['settings'], '');
541 PageManager.showPageByName('search', true, {hash: '#query'});
543 // The settings page is also still "open" (i.e., visible), in order to show
544 // the search results. Furthermore, the URL hasn't been updated in the parent
545 // page, because we've loaded the chrome-settings frame instead of the whole
546 // settings page, so the cross-origin call to set the URL fails.
547 this.verifyOpenPages_(['settings', 'search'], 'search#query');
549 this.verifyHistory_(['', 'search#query'], function() {
550 PageManager.showPageByName('settings', false);
551 self.verifyOpenPages_(['settings'], 'search#query');
552 self.verifyHistory_(['', 'search#query'], testDone);
556 TEST_F('OptionsWebUIExtendedTest', 'ShowPageWithHistory', function() {
557 PageManager.showPageByName('search', true, {hash: '#query'});
559 this.verifyHistory_(['', 'search#query'], function() {
560 PageManager.showPageByName('settings', true);
561 self.verifyOpenPages_(['settings'], '');
562 self.verifyHistory_(['', 'search#query', ''],
567 TEST_F('OptionsWebUIExtendedTest', 'ShowPageReplaceHistory', function() {
568 PageManager.showPageByName('search', true, {hash: '#query'});
570 this.verifyHistory_(['', 'search#query'], function() {
571 PageManager.showPageByName('settings', true, {'replaceState': true});
572 self.verifyOpenPages_(['settings'], '');
573 self.verifyHistory_(['', ''], testDone);
577 // This should be identical to ShowPageWithHisory.
578 TEST_F('OptionsWebUIExtendedTest', 'NavigateToPage', function() {
579 PageManager.showPageByName('search', true, {hash: '#query'});
581 this.verifyHistory_(['', 'search#query'], function() {
582 PageManager.showPageByName('settings');
583 self.verifyOpenPages_(['settings'], '');
584 self.verifyHistory_(['', 'search#query', ''], testDone);
588 // Settings overlays are much more straightforward than settings pages, opening
589 // normally with none of the latter's quirks in the expected history or URL.
590 TEST_F('OptionsWebUIExtendedTest', 'ShowOverlayNoHistory', function() {
591 // Open a layer-1 overlay, not updating history.
592 PageManager.showPageByName('languages', false);
593 this.verifyOpenPages_(['settings', 'languages'], '');
596 this.verifyHistory_([''], function() {
597 // Open a layer-2 overlay for which the layer-1 is a parent, not updating
599 PageManager.showPageByName('addLanguage', false);
600 self.verifyOpenPages_(['settings', 'languages', 'addLanguage'],
602 self.verifyHistory_([''], testDone);
606 TEST_F('OptionsWebUIExtendedTest', 'ShowOverlayWithHistory', function() {
607 // Open a layer-1 overlay, updating history.
608 PageManager.showPageByName('languages', true);
609 this.verifyOpenPages_(['settings', 'languages']);
612 this.verifyHistory_(['', 'languages'], function() {
613 // Open a layer-2 overlay, updating history.
614 PageManager.showPageByName('addLanguage', true);
615 self.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
616 self.verifyHistory_(['', 'languages', 'addLanguage'], testDone);
620 TEST_F('OptionsWebUIExtendedTest', 'ShowOverlayReplaceHistory', function() {
621 // Open a layer-1 overlay, updating history.
622 PageManager.showPageByName('languages', true);
624 this.verifyHistory_(['', 'languages'], function() {
625 // Open a layer-2 overlay, replacing history.
626 PageManager.showPageByName('addLanguage', true, {'replaceState': true});
627 self.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
628 self.verifyHistory_(['', 'addLanguage'], testDone);
632 // Directly show an overlay further above this page, i.e. one for which the
633 // current page is an ancestor but not a parent.
634 TEST_F('OptionsWebUIExtendedTest', 'ShowOverlayFurtherAbove', function() {
635 // Open a layer-2 overlay directly.
636 PageManager.showPageByName('addLanguage', true);
637 this.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
639 this.verifyHistory_(['', 'addLanguage'], testDone);
642 // Directly show a layer-2 overlay for which the layer-1 overlay is not a
644 TEST_F('OptionsWebUIExtendedTest', 'ShowUnrelatedOverlay', function() {
645 // Open a layer-1 overlay.
646 PageManager.showPageByName('languages', true);
647 this.verifyOpenPages_(['settings', 'languages']);
650 this.verifyHistory_(['', 'languages'], function() {
651 // Open an unrelated layer-2 overlay.
652 PageManager.showPageByName('cookies', true);
653 self.verifyOpenPages_(['settings', 'content', 'cookies']);
654 self.verifyHistory_(['', 'languages', 'cookies'], testDone);
659 TEST_F('OptionsWebUIExtendedTest', 'CloseOverlay', function() {
660 // Open a layer-1 overlay, then a layer-2 overlay on top of it.
661 PageManager.showPageByName('languages', true);
662 this.verifyOpenPages_(['settings', 'languages']);
663 PageManager.showPageByName('addLanguage', true);
664 this.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
667 this.verifyHistory_(['', 'languages', 'addLanguage'], function() {
668 // Close the layer-2 overlay.
669 PageManager.closeOverlay();
670 self.verifyOpenPages_(['settings', 'languages']);
672 ['', 'languages', 'addLanguage', 'languages'],
674 // Close the layer-1 overlay.
675 PageManager.closeOverlay();
676 self.verifyOpenPages_(['settings'], '');
678 ['', 'languages', 'addLanguage', 'languages', ''],
684 // Hashes are maintained separately for each page and are preserved when
686 TEST_F('OptionsWebUIExtendedTest', 'CloseOverlayWithHashes', function() {
687 // Open an overlay on top of the search page.
688 PageManager.showPageByName('search', true, {hash: '#1'});
689 this.verifyOpenPages_(['settings', 'search'], 'search#1');
690 PageManager.showPageByName('languages', true, {hash: '#2'});
691 this.verifyOpenPages_(['settings', 'search', 'languages'],
693 PageManager.showPageByName('addLanguage', true, {hash: '#3'});
694 this.verifyOpenPages_(['settings', 'search', 'languages', 'addLanguage'],
697 this.verifyHistory_(['', 'search#1', 'languages#2', 'addLanguage#3'],
699 // Close the layer-2 overlay.
700 PageManager.closeOverlay();
701 this.verifyOpenPages_(['settings', 'search', 'languages'], 'languages#2');
703 ['', 'search#1', 'languages#2', 'addLanguage#3', 'languages#2'],
705 // Close the layer-1 overlay.
706 PageManager.closeOverlay();
707 this.verifyOpenPages_(['settings', 'search'], 'search#1');
709 ['', 'search#1', 'languages#2', 'addLanguage#3', 'languages#2',
716 // Test that closing an overlay that did not push history when opening does not
717 // again push history.
718 TEST_F('OptionsWebUIExtendedTest', 'CloseOverlayNoHistory', function() {
719 // Open the do not track confirmation prompt.
720 PageManager.showPageByName('doNotTrackConfirm', false);
722 // Opening the prompt does not add to the history.
723 this.verifyHistory_([''], function() {
724 // Close the overlay.
725 PageManager.closeOverlay();
726 // Still no history changes.
727 this.verifyHistory_([''], testDone);
731 // Make sure an overlay isn't closed (even temporarily) when another overlay is
733 TEST_F('OptionsWebUIExtendedTest', 'OverlayAboveNoReset', function() {
734 // Open a layer-1 overlay.
735 PageManager.showPageByName('languages', true);
736 this.verifyOpenPages_(['settings', 'languages']);
738 // Open a layer-2 overlay on top. This should not close 'languages'.
739 this.prohibitChangesToOverlay_(options.LanguageOptions.getInstance());
740 PageManager.showPageByName('addLanguage', true);
741 this.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
745 TEST_F('OptionsWebUIExtendedTest', 'OverlayTabNavigation', function() {
746 // Open a layer-1 overlay, then a layer-2 overlay on top of it.
747 PageManager.showPageByName('languages', true);
748 PageManager.showPageByName('addLanguage', true);
751 // Go back twice, then forward twice.
752 self.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
753 self.verifyHistory_(['', 'languages', 'addLanguage'], function() {
754 window.history.back();
755 waitForPopstate(function() {
756 self.verifyOpenPages_(['settings', 'languages']);
757 self.verifyHistory_(['', 'languages'], function() {
758 window.history.back();
759 waitForPopstate(function() {
760 self.verifyOpenPages_(['settings'], '');
761 self.verifyHistory_([''], function() {
762 window.history.forward();
763 waitForPopstate(function() {
764 self.verifyOpenPages_(['settings', 'languages']);
765 self.verifyHistory_(['', 'languages'], function() {
766 window.history.forward();
767 waitForPopstate(function() {
768 self.verifyOpenPages_(
769 ['settings', 'languages', 'addLanguage']);
771 ['', 'languages', 'addLanguage'], testDone);
782 // Going "back" to an overlay that's a child of the current overlay shouldn't
783 // close the current one.
784 TEST_F('OptionsWebUIExtendedTest', 'OverlayBackToChild', function() {
785 // Open a layer-1 overlay, then a layer-2 overlay on top of it.
786 PageManager.showPageByName('languages', true);
787 PageManager.showPageByName('addLanguage', true);
790 self.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
791 self.verifyHistory_(['', 'languages', 'addLanguage'], function() {
792 // Close the top overlay, then go back to it.
793 PageManager.closeOverlay();
794 self.verifyOpenPages_(['settings', 'languages']);
796 ['', 'languages', 'addLanguage', 'languages'],
798 // Going back to the 'addLanguage' page should not close 'languages'.
799 self.prohibitChangesToOverlay_(options.LanguageOptions.getInstance());
800 window.history.back();
801 waitForPopstate(function() {
802 self.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
803 self.verifyHistory_(['', 'languages', 'addLanguage'],
810 // Going back to an unrelated overlay should close the overlay and its parent.
811 TEST_F('OptionsWebUIExtendedTest', 'OverlayBackToUnrelated', function() {
812 // Open a layer-1 overlay, then an unrelated layer-2 overlay.
813 PageManager.showPageByName('languages', true);
814 PageManager.showPageByName('cookies', true);
816 self.verifyOpenPages_(['settings', 'content', 'cookies']);
817 self.verifyHistory_(['', 'languages', 'cookies'], function() {
818 window.history.back();
819 waitForPopstate(function() {
820 self.verifyOpenPages_(['settings', 'languages']);
826 // Verify history changes properly while the page is loading.
827 TEST_F('OptionsWebUIExtendedTest', 'HistoryUpdatedAfterLoading', function() {
828 var loc = location.href;
830 document.documentElement.classList.add('loading');
831 assertTrue(PageManager.isLoading());
832 PageManager.showPageByName('searchEngines');
833 expectNotEquals(loc, location.href);
835 document.documentElement.classList.remove('loading');
836 assertFalse(PageManager.isLoading());
837 PageManager.showDefaultPage();
838 expectEquals(loc, location.href);
843 // A tip should be shown or hidden depending on whether this profile manages any
845 TEST_F('OptionsWebUIExtendedTest', 'SupervisingUsers', function() {
846 // We start managing no supervised users.
847 assertTrue($('profiles-supervised-dashboard-tip').hidden);
849 // Remove all supervised users, then add some, watching for the pref change
850 // notifications and UI updates in each case. Any non-empty pref dictionary
851 // is interpreted as having supervised users.
852 chrome.send('optionsTestSetPref', [SUPERVISED_USERS_PREF, {key: 'value'}]);
853 waitForResponse(BrowserOptions, 'updateManagesSupervisedUsers', function() {
854 assertFalse($('profiles-supervised-dashboard-tip').hidden);
855 chrome.send('optionsTestSetPref', [SUPERVISED_USERS_PREF, {}]);
856 waitForResponse(BrowserOptions, 'updateManagesSupervisedUsers', function() {
857 assertTrue($('profiles-supervised-dashboard-tip').hidden);
864 * TestFixture that loads the options page at a bogus URL.
865 * @extends {OptionsWebUIExtendedTest}
868 function OptionsWebUIRedirectTest() {
869 OptionsWebUIExtendedTest.call(this);
872 OptionsWebUIRedirectTest.prototype = {
873 __proto__: OptionsWebUIExtendedTest.prototype,
876 browsePreload: 'chrome://settings-frame/nonexistantPage',
879 TEST_F('OptionsWebUIRedirectTest', 'TestURL', function() {
880 assertEquals('chrome://settings-frame/', document.location.href);
881 this.verifyHistory_([''], testDone);