| // Copyright 2019 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. |
| |
| #include <memory> |
| |
| #include "ash/public/cpp/test/shell_test_api.h" |
| #include "base/bind.h" |
| #include "base/files/file_util.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_path_override.h" |
| #include "base/test/task_environment.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" |
| #include "chrome/browser/chromeos/accessibility/magnification_manager.h" |
| #include "chrome/browser/chromeos/accessibility/speech_monitor.h" |
| #include "chrome/browser/chromeos/login/login_wizard.h" |
| #include "chrome/browser/chromeos/login/screens/welcome_screen.h" |
| #include "chrome/browser/chromeos/login/test/js_checker.h" |
| #include "chrome/browser/chromeos/login/test/oobe_base_test.h" |
| #include "chrome/browser/chromeos/login/test/oobe_screen_exit_waiter.h" |
| #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" |
| #include "chrome/browser/chromeos/login/test/oobe_screens_utils.h" |
| #include "chrome/browser/chromeos/login/test/test_predicate_waiter.h" |
| #include "chrome/browser/chromeos/login/ui/login_display_host.h" |
| #include "chrome/browser/chromeos/login/wizard_controller.h" |
| #include "chrome/browser/speech/extension_api/tts_engine_extension_api.h" |
| #include "chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h" |
| #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" |
| #include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/test/base/interactive_test_utils.h" |
| #include "chromeos/constants/chromeos_paths.h" |
| #include "chromeos/dbus/constants/dbus_switches.h" |
| #include "chromeos/system/fake_statistics_provider.h" |
| #include "components/language/core/browser/pref_names.h" |
| #include "components/prefs/pref_service.h" |
| #include "content/public/test/browser_test.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/base/ime/chromeos/extension_ime_util.h" |
| |
| namespace chromeos { |
| |
| namespace { |
| |
| const char kStartupManifestEnglish[] = |
| R"({ |
| "version": "1.0", |
| "initial_locale" : "en-US", |
| "initial_timezone" : "US/Pacific", |
| "keyboard_layout" : "xkb:us::eng", |
| })"; |
| |
| const char kStartupManifestFrench[] = |
| R"({ |
| "version": "1.0", |
| "initial_locale" : "fr-FR", |
| "initial_timezone" : "Europe/Paris", |
| "keyboard_layout" : "xkb:fr::fra", |
| })"; |
| |
| const char kCurrentLang[] = |
| R"(document.getElementById('connect').$.welcomeScreen.currentLanguage)"; |
| const char kCurrentKeyboard[] = |
| R"(document.getElementById('connect').currentKeyboard)"; |
| |
| const test::UIPath kChromeVoxHintDialog = {"connect", "welcomeScreen", |
| "chromeVoxHint"}; |
| const test::UIPath kDismissChromeVoxButton = {"connect", "welcomeScreen", |
| "dismissChromeVoxButton"}; |
| const test::UIPath kActivateChromeVoxButton = {"connect", "welcomeScreen", |
| "activateChromeVoxButton"}; |
| |
| const char kSetAvailableVoices[] = R"( |
| chrome.tts.getVoices = function(callback) { |
| callback([ |
| {'lang': 'en-US', 'voiceName': 'Chrome OS US English'}, |
| {'lang': 'fr-FR', 'voiceName': 'Chrome OS français'} |
| ]); |
| };)"; |
| |
| const char kChromeVoxHintLaptopSpokenString[] = |
| "Do you want to activate ChromeVox, the built-in screenreader for Chrome " |
| "OS? If so, press the space bar."; |
| |
| void ToggleAccessibilityFeature(const std::string& feature_name, |
| bool new_value) { |
| test::JSChecker js = test::OobeJS(); |
| std::string feature_toggle = |
| test::GetOobeElementPath({"connect", feature_name, "button"}) + |
| ".checked"; |
| |
| if (!new_value) |
| feature_toggle = "!" + feature_toggle; |
| |
| js.ExpectVisiblePath({"connect", feature_name, "button"}); |
| EXPECT_FALSE(js.GetBool(feature_toggle)); |
| js.TapOnPath({"connect", feature_name, "button"}); |
| js.CreateWaiter(feature_toggle)->Wait(); |
| } |
| |
| } // namespace |
| |
| class WelcomeScreenBrowserTest : public OobeBaseTest { |
| public: |
| WelcomeScreenBrowserTest() = default; |
| ~WelcomeScreenBrowserTest() override = default; |
| |
| // OobeBaseTest: |
| bool SetUpUserDataDirectory() override { |
| if (!OobeBaseTest::SetUpUserDataDirectory()) |
| return false; |
| EXPECT_TRUE(data_dir_.CreateUniqueTempDir()); |
| const base::FilePath startup_manifest = |
| data_dir_.GetPath().AppendASCII("startup_manifest.json"); |
| EXPECT_TRUE(base::WriteFile(startup_manifest, kStartupManifestEnglish)); |
| path_override_ = std::make_unique<base::ScopedPathOverride>( |
| chromeos::FILE_STARTUP_CUSTOMIZATION_MANIFEST, startup_manifest); |
| return true; |
| } |
| |
| WelcomeScreen* welcome_screen() { |
| EXPECT_NE(WizardController::default_controller(), nullptr); |
| WelcomeScreen* welcome_screen = |
| WizardController::default_controller()->GetScreen<WelcomeScreen>(); |
| EXPECT_NE(welcome_screen, nullptr); |
| return welcome_screen; |
| } |
| |
| void WaitForScreenExit() { |
| OobeScreenExitWaiter(WelcomeView::kScreenId).Wait(); |
| } |
| |
| base::HistogramTester histogram_tester_; |
| |
| private: |
| std::unique_ptr<base::ScopedPathOverride> path_override_; |
| base::ScopedTempDir data_dir_; |
| }; |
| |
| class WelcomeScreenSystemDevModeBrowserTest : public WelcomeScreenBrowserTest { |
| public: |
| WelcomeScreenSystemDevModeBrowserTest() = default; |
| ~WelcomeScreenSystemDevModeBrowserTest() override = default; |
| |
| // WelcomeScreenBrowserTest: |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| WelcomeScreenBrowserTest::SetUpCommandLine(command_line); |
| command_line->AppendSwitch(chromeos::switches::kSystemDevMode); |
| } |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenElements) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| |
| test::OobeJS().ExpectVisiblePath({"connect", "welcomeScreen"}); |
| test::OobeJS().ExpectHiddenPath({"connect", "accessibilityScreen"}); |
| test::OobeJS().ExpectHiddenPath({"connect", "languageScreen"}); |
| test::OobeJS().ExpectHiddenPath({"connect", "timezoneScreen"}); |
| test::OobeJS().ExpectVisiblePath( |
| {"connect", "welcomeScreen", "welcomeNextButton"}); |
| test::OobeJS().ExpectVisiblePath( |
| {"connect", "welcomeScreen", "languageSelectionButton"}); |
| test::OobeJS().ExpectVisiblePath( |
| {"connect", "welcomeScreen", "accessibilitySettingsButton"}); |
| test::OobeJS().ExpectHiddenPath( |
| {"connect", "welcomeScreen", "timezoneSettingsButton"}); |
| test::OobeJS().ExpectVisiblePath( |
| {"connect", "welcomeScreen", "enableDebuggingLink"}); |
| } |
| |
| // This is a minimal possible test for OOBE. It is used as reference test |
| // for measurements during OOBE speedup work. |
| // TODO(crbug.com/1058022): Remove after speedup work. |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, OobeStartupTime) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenNext) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| test::OobeJS().TapOnPath({"connect", "welcomeScreen", "welcomeNextButton"}); |
| WaitForScreenExit(); |
| } |
| |
| // Set of browser tests for Welcome Screen Language options. |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenLanguageFlow) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| test::OobeJS().TapOnPath( |
| {"connect", "welcomeScreen", "languageSelectionButton"}); |
| |
| test::OobeJS().TapOnPath({"connect", "ok-button-language"}); |
| test::OobeJS().TapOnPath({"connect", "welcomeScreen", "welcomeNextButton"}); |
| WaitForScreenExit(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, |
| WelcomeScreenLanguageElements) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| test::OobeJS().TapOnPath( |
| {"connect", "welcomeScreen", "languageSelectionButton"}); |
| |
| test::OobeJS().ExpectVisiblePath({"connect", "languageDropdownContainer"}); |
| test::OobeJS().ExpectVisiblePath({"connect", "keyboardDropdownContainer"}); |
| test::OobeJS().ExpectVisiblePath({"connect", "languageSelect"}); |
| test::OobeJS().ExpectVisiblePath({"connect", "keyboardSelect"}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, |
| WelcomeScreenLanguageSelection) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| |
| test::OobeJS().TapOnPath( |
| {"connect", "welcomeScreen", "languageSelectionButton"}); |
| EXPECT_EQ(g_browser_process->GetApplicationLocale(), "en-US"); |
| |
| test::OobeJS().ExpectEQ(kCurrentLang, std::string("English (United States)")); |
| |
| { |
| test::LanguageReloadObserver observer(welcome_screen()); |
| test::OobeJS().SelectElementInPath("fr", |
| {"connect", "languageSelect", "select"}); |
| observer.Wait(); |
| test::OobeJS().ExpectEQ(kCurrentLang, std::string("français")); |
| EXPECT_EQ(g_browser_process->GetApplicationLocale(), "fr"); |
| } |
| |
| { |
| test::LanguageReloadObserver observer(welcome_screen()); |
| test::OobeJS().SelectElementInPath("en-US", |
| {"connect", "languageSelect", "select"}); |
| observer.Wait(); |
| test::OobeJS().ExpectEQ(kCurrentLang, |
| std::string("English (United States)")); |
| EXPECT_EQ(g_browser_process->GetApplicationLocale(), "en-US"); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, |
| WelcomeScreenKeyboardSelection) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| test::OobeJS().TapOnPath( |
| {"connect", "welcomeScreen", "languageSelectionButton"}); |
| |
| std::string extension_id_prefix = |
| std::string("_comp_ime_") + extension_ime_util::kXkbExtensionId; |
| |
| test::OobeJS().SelectElementInPath(extension_id_prefix + "xkb:us:intl:eng", |
| {"connect", "keyboardSelect", "select"}); |
| test::OobeJS().ExpectEQ(kCurrentKeyboard, std::string("US international")); |
| ASSERT_EQ(welcome_screen()->GetInputMethod(), |
| extension_id_prefix + "xkb:us:intl:eng"); |
| |
| test::OobeJS().SelectElementInPath(extension_id_prefix + "xkb:us:workman:eng", |
| {"connect", "keyboardSelect", "select"}); |
| test::OobeJS().ExpectEQ(kCurrentKeyboard, std::string("US Workman")); |
| ASSERT_EQ(welcome_screen()->GetInputMethod(), |
| extension_id_prefix + "xkb:us:workman:eng"); |
| } |
| |
| // Set of browser tests for Welcome Screen Accessibility options. |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, |
| WelcomeScreenAccessibilityFlow) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| test::OobeJS().TapOnPath( |
| {"connect", "welcomeScreen", "accessibilitySettingsButton"}); |
| |
| test::OobeJS().TapOnPath({"connect", "ok-button-accessibility"}); |
| test::OobeJS().TapOnPath({"connect", "welcomeScreen", "welcomeNextButton"}); |
| WaitForScreenExit(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, |
| WelcomeScreenAccessibilitySpokenFeedback) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| test::OobeJS().TapOnPath( |
| {"connect", "welcomeScreen", "accessibilitySettingsButton"}); |
| |
| ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); |
| ToggleAccessibilityFeature("accessibility-spoken-feedback", true); |
| ASSERT_TRUE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); |
| histogram_tester_.ExpectBucketCount( |
| "OOBE.WelcomeScreen.A11yUserActions", |
| WelcomeScreen::A11yUserAction::kEnableSpokenFeedback, 1); |
| |
| ToggleAccessibilityFeature("accessibility-spoken-feedback", false); |
| ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); |
| histogram_tester_.ExpectBucketCount( |
| "OOBE.WelcomeScreen.A11yUserActions", |
| WelcomeScreen::A11yUserAction::kDisableSpokenFeedback, 1); |
| |
| histogram_tester_.ExpectTotalCount("OOBE.WelcomeScreen.A11yUserActions", 2); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, |
| WelcomeScreenAccessibilityLargeCursor) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| test::OobeJS().TapOnPath( |
| {"connect", "welcomeScreen", "accessibilitySettingsButton"}); |
| |
| ASSERT_FALSE(AccessibilityManager::Get()->IsLargeCursorEnabled()); |
| ToggleAccessibilityFeature("accessibility-large-cursor", true); |
| ASSERT_TRUE(AccessibilityManager::Get()->IsLargeCursorEnabled()); |
| histogram_tester_.ExpectBucketCount( |
| "OOBE.WelcomeScreen.A11yUserActions", |
| WelcomeScreen::A11yUserAction::kEnableLargeCursor, 1); |
| |
| ToggleAccessibilityFeature("accessibility-large-cursor", false); |
| ASSERT_FALSE(AccessibilityManager::Get()->IsLargeCursorEnabled()); |
| histogram_tester_.ExpectBucketCount( |
| "OOBE.WelcomeScreen.A11yUserActions", |
| WelcomeScreen::A11yUserAction::kDisableLargeCursor, 1); |
| |
| histogram_tester_.ExpectTotalCount("OOBE.WelcomeScreen.A11yUserActions", 2); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, |
| WelcomeScreenAccessibilityHighContrast) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| test::OobeJS().TapOnPath( |
| {"connect", "welcomeScreen", "accessibilitySettingsButton"}); |
| |
| ASSERT_FALSE(AccessibilityManager::Get()->IsHighContrastEnabled()); |
| ToggleAccessibilityFeature("accessibility-high-contrast", true); |
| ASSERT_TRUE(AccessibilityManager::Get()->IsHighContrastEnabled()); |
| histogram_tester_.ExpectBucketCount( |
| "OOBE.WelcomeScreen.A11yUserActions", |
| WelcomeScreen::A11yUserAction::kEnableHighContrast, 1); |
| |
| ToggleAccessibilityFeature("accessibility-high-contrast", false); |
| ASSERT_FALSE(AccessibilityManager::Get()->IsHighContrastEnabled()); |
| histogram_tester_.ExpectBucketCount( |
| "OOBE.WelcomeScreen.A11yUserActions", |
| WelcomeScreen::A11yUserAction::kDisableHighContrast, 1); |
| |
| histogram_tester_.ExpectTotalCount("OOBE.WelcomeScreen.A11yUserActions", 2); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, |
| WelcomeScreenAccessibilitySelectToSpeak) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| test::OobeJS().TapOnPath( |
| {"connect", "welcomeScreen", "accessibilitySettingsButton"}); |
| |
| ASSERT_FALSE(AccessibilityManager::Get()->IsSelectToSpeakEnabled()); |
| ToggleAccessibilityFeature("accessibility-select-to-speak", true); |
| ASSERT_TRUE(AccessibilityManager::Get()->IsSelectToSpeakEnabled()); |
| histogram_tester_.ExpectBucketCount( |
| "OOBE.WelcomeScreen.A11yUserActions", |
| WelcomeScreen::A11yUserAction::kEnableSelectToSpeak, 1); |
| |
| ToggleAccessibilityFeature("accessibility-select-to-speak", false); |
| ASSERT_FALSE(AccessibilityManager::Get()->IsSelectToSpeakEnabled()); |
| histogram_tester_.ExpectBucketCount( |
| "OOBE.WelcomeScreen.A11yUserActions", |
| WelcomeScreen::A11yUserAction::kDisableSelectToSpeak, 1); |
| |
| histogram_tester_.ExpectTotalCount("OOBE.WelcomeScreen.A11yUserActions", 2); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, |
| WelcomeScreenAccessibilityScreenMagnifier) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| test::OobeJS().TapOnPath( |
| {"connect", "welcomeScreen", "accessibilitySettingsButton"}); |
| |
| ASSERT_FALSE(MagnificationManager::Get()->IsMagnifierEnabled()); |
| ToggleAccessibilityFeature("accessibility-screen-magnifier", true); |
| ASSERT_TRUE(MagnificationManager::Get()->IsMagnifierEnabled()); |
| histogram_tester_.ExpectBucketCount( |
| "OOBE.WelcomeScreen.A11yUserActions", |
| WelcomeScreen::A11yUserAction::kEnableScreenMagnifier, 1); |
| |
| ToggleAccessibilityFeature("accessibility-screen-magnifier", false); |
| ASSERT_FALSE(MagnificationManager::Get()->IsMagnifierEnabled()); |
| histogram_tester_.ExpectBucketCount( |
| "OOBE.WelcomeScreen.A11yUserActions", |
| WelcomeScreen::A11yUserAction::kDisableScreenMagnifier, 1); |
| |
| histogram_tester_.ExpectTotalCount("OOBE.WelcomeScreen.A11yUserActions", 2); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, |
| WelcomeScreenAccessibilityDockedMagnifier) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| test::OobeJS().TapOnPath( |
| {"connect", "welcomeScreen", "accessibilitySettingsButton"}); |
| |
| ASSERT_FALSE(MagnificationManager::Get()->IsDockedMagnifierEnabled()); |
| ToggleAccessibilityFeature("accessibility-docked-magnifier", true); |
| ASSERT_TRUE(MagnificationManager::Get()->IsDockedMagnifierEnabled()); |
| histogram_tester_.ExpectBucketCount( |
| "OOBE.WelcomeScreen.A11yUserActions", |
| WelcomeScreen::A11yUserAction::kEnableDockedMagnifier, 1); |
| |
| ToggleAccessibilityFeature("accessibility-docked-magnifier", false); |
| ASSERT_FALSE(MagnificationManager::Get()->IsDockedMagnifierEnabled()); |
| histogram_tester_.ExpectBucketCount( |
| "OOBE.WelcomeScreen.A11yUserActions", |
| WelcomeScreen::A11yUserAction::kDisableDockedMagnifier, 1); |
| |
| histogram_tester_.ExpectTotalCount("OOBE.WelcomeScreen.A11yUserActions", 2); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, PRE_SelectedLanguage) { |
| EXPECT_EQ( |
| StartupCustomizationDocument::GetInstance()->initial_locale_default(), |
| "en-US"); |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| const std::string locale = "ru"; |
| test::LanguageReloadObserver observer(welcome_screen()); |
| welcome_screen()->SetApplicationLocale(locale); |
| observer.Wait(); |
| |
| EXPECT_EQ(g_browser_process->local_state()->GetString( |
| language::prefs::kApplicationLocale), |
| locale); |
| EXPECT_EQ(g_browser_process->GetApplicationLocale(), locale); |
| |
| // We need to proceed otherwise welcome screen would reset language on the |
| // next show. |
| test::OobeJS().TapOnPath({"connect", "welcomeScreen", "welcomeNextButton"}); |
| WaitForScreenExit(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, SelectedLanguage) { |
| const std::string locale = "ru"; |
| EXPECT_EQ(g_browser_process->local_state()->GetString( |
| language::prefs::kApplicationLocale), |
| locale); |
| EXPECT_EQ(g_browser_process->GetApplicationLocale(), locale); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, A11yVirtualKeyboard) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| test::OobeJS().TapOnPath( |
| {"connect", "welcomeScreen", "accessibilitySettingsButton"}); |
| |
| ASSERT_FALSE(AccessibilityManager::Get()->IsVirtualKeyboardEnabled()); |
| ToggleAccessibilityFeature("accessibility-virtual-keyboard", true); |
| ASSERT_TRUE(AccessibilityManager::Get()->IsVirtualKeyboardEnabled()); |
| histogram_tester_.ExpectBucketCount( |
| "OOBE.WelcomeScreen.A11yUserActions", |
| WelcomeScreen::A11yUserAction::kEnableVirtualKeyboard, 1); |
| |
| ToggleAccessibilityFeature("accessibility-virtual-keyboard", false); |
| ASSERT_FALSE(AccessibilityManager::Get()->IsVirtualKeyboardEnabled()); |
| histogram_tester_.ExpectBucketCount( |
| "OOBE.WelcomeScreen.A11yUserActions", |
| WelcomeScreen::A11yUserAction::kDisableVirtualKeyboard, 1); |
| |
| histogram_tester_.ExpectTotalCount("OOBE.WelcomeScreen.A11yUserActions", 2); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenSystemDevModeBrowserTest, |
| DebuggerModeTest) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| test::OobeJS().ClickOnPath( |
| {"connect", "welcomeScreen", "enableDebuggingLink"}); |
| |
| test::OobeJS() |
| .CreateVisibilityWaiter(true, {"debugging", "removeProtectionDialog"}) |
| ->Wait(); |
| test::OobeJS().ExpectVisiblePath( |
| {"debugging", "removeProtectionProceedButton"}); |
| test::OobeJS().ExpectVisiblePath( |
| {"debugging", "removeProtectionCancelButton"}); |
| test::OobeJS().ExpectVisiblePath({"debugging", "help-link"}); |
| test::OobeJS().ClickOnPath({"debugging", "removeProtectionCancelButton"}); |
| } |
| |
| class WelcomeScreenTimezone : public WelcomeScreenBrowserTest { |
| public: |
| WelcomeScreenTimezone() { |
| fake_statistics_provider_.SetMachineFlag(system::kOemKeyboardDrivenOobeKey, |
| true); |
| } |
| |
| WelcomeScreenTimezone(const WelcomeScreenTimezone&) = delete; |
| WelcomeScreenTimezone& operator=(const WelcomeScreenTimezone&) = delete; |
| |
| protected: |
| void CheckTimezone(const std::string& timezone) { |
| std::string system_timezone; |
| CrosSettings::Get()->GetString(kSystemTimezone, &system_timezone); |
| EXPECT_EQ(timezone, system_timezone); |
| |
| const std::string signin_screen_timezone = |
| g_browser_process->local_state()->GetString( |
| prefs::kSigninScreenTimezone); |
| EXPECT_EQ(timezone, signin_screen_timezone); |
| } |
| |
| private: |
| system::ScopedFakeStatisticsProvider fake_statistics_provider_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenTimezone, ChangeTimezoneFlow) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| test::OobeJS().TapOnPath( |
| {"connect", "welcomeScreen", "timezoneSettingsButton"}); |
| |
| std::string system_timezone; |
| CrosSettings::Get()->GetString(kSystemTimezone, &system_timezone); |
| const char kTestTimezone[] = "Asia/Novosibirsk"; |
| ASSERT_NE(kTestTimezone, system_timezone); |
| |
| test::OobeJS().SelectElementInPath(kTestTimezone, |
| {"connect", "timezoneSelect", "select"}); |
| CheckTimezone(kTestTimezone); |
| test::OobeJS().TapOnPath({"connect", "ok-button-timezone"}); |
| test::OobeJS().TapOnPath({"connect", "welcomeScreen", "welcomeNextButton"}); |
| WaitForScreenExit(); |
| |
| // Must not change. |
| CheckTimezone(kTestTimezone); |
| } |
| |
| class WelcomeScreenChromeVoxHintTest : public WelcomeScreenBrowserTest { |
| public: |
| WelcomeScreenChromeVoxHintTest() = default; |
| ~WelcomeScreenChromeVoxHintTest() override = default; |
| |
| void WaitForChromeVoxHintDialogToOpen() { |
| test::OobeJS() |
| .CreateWaiter(test::GetOobeElementPath({kChromeVoxHintDialog}) + |
| ".open") |
| ->Wait(); |
| } |
| |
| void WaitForChromeVoxHintDialogToClose() { |
| test::OobeJS() |
| .CreateWaiter(test::GetOobeElementPath({kChromeVoxHintDialog}) + |
| ".open === false") |
| ->Wait(); |
| } |
| |
| void WaitForSpokenSuccessMetric() { |
| test::TestPredicateWaiter( |
| base::BindRepeating( |
| [](base::HistogramTester* tester) { |
| return tester->GetBucketCount( |
| "OOBE.WelcomeScreen.ChromeVoxHintSpokenSuccess", |
| true) == 1; |
| }, |
| &histogram_tester_)) |
| .Wait(); |
| histogram_tester_.ExpectUniqueSample( |
| "OOBE.WelcomeScreen.ChromeVoxHintSpokenSuccess", true, 1); |
| } |
| }; |
| |
| // Assert that the ChromeVox hint gives speech output and shows a dialog. |
| // Clicking the 'activate' button in the dialog should activate ChromeVox. |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, LaptopClick) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); |
| test::ExecuteOobeJS(kSetAvailableVoices); |
| test::SpeechMonitor monitor; |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, false); |
| welcome_screen()->GiveChromeVoxHintForTesting(); |
| monitor.ExpectSpeech(kChromeVoxHintLaptopSpokenString); |
| monitor.Call([this]() { |
| ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); |
| WaitForChromeVoxHintDialogToOpen(); |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, true); |
| test::OobeJS().ClickOnPath(kActivateChromeVoxButton); |
| }); |
| monitor.ExpectSpeechPattern("*"); |
| monitor.Call([this]() { |
| ASSERT_TRUE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); |
| WaitForChromeVoxHintDialogToClose(); |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, false); |
| histogram_tester_.ExpectUniqueSample( |
| "OOBE.WelcomeScreen.AcceptChromeVoxHint", true, 1); |
| }); |
| monitor.Replay(); |
| WaitForSpokenSuccessMetric(); |
| } |
| |
| // Assert that the ChromeVox hint gives speech output and shows a dialog. |
| // Pressing the space bar while the dialog is open should activate ChromeVox. |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, LaptopSpaceBar) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); |
| test::ExecuteOobeJS(kSetAvailableVoices); |
| test::SpeechMonitor monitor; |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, false); |
| welcome_screen()->GiveChromeVoxHintForTesting(); |
| monitor.ExpectSpeech(kChromeVoxHintLaptopSpokenString); |
| monitor.Call([this]() { |
| ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); |
| WaitForChromeVoxHintDialogToOpen(); |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, true); |
| ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( |
| nullptr, ui::VKEY_SPACE, false /* control */, false /* shift */, |
| false /* alt */, false /* command */)); |
| }); |
| monitor.ExpectSpeechPattern("*"); |
| monitor.Call([this]() { |
| ASSERT_TRUE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); |
| WaitForChromeVoxHintDialogToClose(); |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, false); |
| histogram_tester_.ExpectUniqueSample( |
| "OOBE.WelcomeScreen.AcceptChromeVoxHint", true, 1); |
| }); |
| monitor.Replay(); |
| WaitForSpokenSuccessMetric(); |
| } |
| |
| // Tests the ChromeVox hint speech given in tablet mode. |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, Tablet) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); |
| test::ExecuteOobeJS(kSetAvailableVoices); |
| ash::ShellTestApi().SetTabletModeEnabledForTest(true); |
| test::SpeechMonitor monitor; |
| welcome_screen()->GiveChromeVoxHintForTesting(); |
| monitor.ExpectSpeech( |
| "Do you want to activate ChromeVox, the built-in screenreader for Chrome " |
| "OS? If so, press and hold both volume keys for five seconds."); |
| monitor.Replay(); |
| WaitForSpokenSuccessMetric(); |
| } |
| |
| // Tests that the ChromeVox hint can be spoken, even if the necessary voice |
| // hasn't loaded when the timer has fired. |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, VoicesChanged) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); |
| const std::string set_no_english_voice = R"( |
| chrome.tts.getVoices = function(callback) { |
| callback([{'lang': 'fr-FR', 'voiceName': 'Chrome OS français'}]); |
| };)"; |
| test::ExecuteOobeJS(set_no_english_voice); |
| test::SpeechMonitor monitor; |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, false); |
| welcome_screen()->GiveChromeVoxHintForTesting(); |
| // Wait for voiceschanged listener to register. |
| test::OobeJS() |
| .CreateWaiter( |
| "document.getElementById('connect')." |
| "voicesChangedListenerMaybeGiveChromeVoxHint_ !== undefined") |
| ->Wait(); |
| const std::string load_english_voice = R"( |
| chrome.tts.getVoices = function(callback) { |
| callback([ |
| {'lang': 'fr-FR', 'voiceName': 'Chrome OS français'}, |
| {'lang': 'en-US', 'voiceName': 'Chrome OS US English'}, |
| ]); |
| }; |
| window.speechSynthesis.dispatchEvent(new Event('voiceschanged')); |
| )"; |
| test::ExecuteOobeJS(load_english_voice); |
| monitor.ExpectSpeech(kChromeVoxHintLaptopSpokenString); |
| monitor.Replay(); |
| WaitForSpokenSuccessMetric(); |
| } |
| |
| // Assert that clicking on one of the three buttons on the welcome screen |
| // cancels the ChromeVox hint. |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, CancelHint) { |
| WelcomeScreen* screen = welcome_screen(); |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| ASSERT_FALSE(screen->GetChromeVoxHintTimerCancelledForTesting()); |
| test::OobeJS().ClickOnPath( |
| {"connect", "welcomeScreen", "accessibilitySettingsButton"}); |
| ASSERT_TRUE(screen->GetChromeVoxHintTimerCancelledForTesting()); |
| } |
| |
| // Assert that activating ChromeVox before the hint cancels the hint's timeout. |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, |
| ActivateChromeVoxBeforeHint) { |
| WelcomeScreen* screen = welcome_screen(); |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| ASSERT_FALSE(screen->GetChromeVoxHintTimerCancelledForTesting()); |
| ToggleAccessibilityFeature("accessibility-spoken-feedback", true); |
| ASSERT_TRUE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); |
| ASSERT_TRUE(screen->GetChromeVoxHintTimerCancelledForTesting()); |
| } |
| |
| // Assert that activating ChromeVox (after the hint is given) closes the hint |
| // dialog. |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, |
| ActivateChromeVoxAfterHint) { |
| WelcomeScreen* screen = welcome_screen(); |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); |
| test::ExecuteOobeJS(kSetAvailableVoices); |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, false); |
| screen->GiveChromeVoxHintForTesting(); |
| WaitForChromeVoxHintDialogToOpen(); |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, true); |
| AccessibilityManager::Get()->EnableSpokenFeedback(true); |
| ASSERT_TRUE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); |
| WaitForChromeVoxHintDialogToClose(); |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, false); |
| } |
| |
| // Assert that we can dismiss the ChromeVox hint dialog and that the appropriate |
| // metrics get recorded. |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, DismissAfterHint) { |
| WelcomeScreen* screen = welcome_screen(); |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); |
| test::ExecuteOobeJS(kSetAvailableVoices); |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, false); |
| screen->GiveChromeVoxHintForTesting(); |
| WaitForChromeVoxHintDialogToOpen(); |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, true); |
| test::OobeJS().ClickOnPath(kDismissChromeVoxButton); |
| WaitForChromeVoxHintDialogToClose(); |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, false); |
| histogram_tester_.ExpectUniqueSample("OOBE.WelcomeScreen.AcceptChromeVoxHint", |
| false, 1); |
| } |
| |
| // Assert that the ChromeVox hint dialog behaves as a modal dialog and traps |
| // focus when using tab. |
| // TODO(crbug/1161398): The test is flaky. |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, DISABLED_TrapFocus) { |
| WelcomeScreen* screen = welcome_screen(); |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); |
| test::ExecuteOobeJS(kSetAvailableVoices); |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, false); |
| screen->GiveChromeVoxHintForTesting(); |
| WaitForChromeVoxHintDialogToOpen(); |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, true); |
| |
| // Ensure that focus stays inside the dialog's context. |
| // Move forward through the tab order by pressing tab. |
| test::OobeJS().CreateFocusWaiter(kChromeVoxHintDialog)->Wait(); |
| ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( |
| nullptr, ui::VKEY_TAB, false /* control */, false /* shift */, |
| false /* alt */, false /* command */)); |
| test::OobeJS().CreateFocusWaiter(kDismissChromeVoxButton)->Wait(); |
| ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( |
| nullptr, ui::VKEY_TAB, false /* control */, false /* shift */, |
| false /* alt */, false /* command */)); |
| test::OobeJS().CreateFocusWaiter(kActivateChromeVoxButton)->Wait(); |
| ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( |
| nullptr, ui::VKEY_TAB, false /* control */, false /* shift */, |
| false /* alt */, false /* command */)); |
| test::OobeJS().CreateFocusWaiter(kDismissChromeVoxButton)->Wait(); |
| |
| // Move backward by pressing shift + tab. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( |
| nullptr, ui::VKEY_TAB, false /* control */, true /* shift */, |
| false /* alt */, false /* command */)); |
| test::OobeJS().CreateFocusWaiter(kActivateChromeVoxButton)->Wait(); |
| } |
| |
| class WelcomeScreenInternationalChromeVoxHintTest |
| : public WelcomeScreenChromeVoxHintTest { |
| public: |
| bool SetUpUserDataDirectory() override { |
| if (!OobeBaseTest::SetUpUserDataDirectory()) |
| return false; |
| EXPECT_TRUE(data_dir_.CreateUniqueTempDir()); |
| const base::FilePath startup_manifest = |
| data_dir_.GetPath().AppendASCII("startup_manifest.json"); |
| EXPECT_TRUE(base::WriteFile(startup_manifest, kStartupManifestFrench)); |
| path_override_ = std::make_unique<base::ScopedPathOverride>( |
| chromeos::FILE_STARTUP_CUSTOMIZATION_MANIFEST, startup_manifest); |
| return true; |
| } |
| |
| private: |
| std::unique_ptr<base::ScopedPathOverride> path_override_; |
| base::ScopedTempDir data_dir_; |
| }; |
| |
| // Tests the ChromeVox hint speech can be given in a language other than |
| // English. |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenInternationalChromeVoxHintTest, SpeakHint) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); |
| test::ExecuteOobeJS(kSetAvailableVoices); |
| test::SpeechMonitor monitor; |
| welcome_screen()->GiveChromeVoxHintForTesting(); |
| monitor.ExpectSpeechPatternWithLocale("*", "fr"); |
| monitor.Replay(); |
| WaitForSpokenSuccessMetric(); |
| } |
| |
| // Tests that the ChromeVox hint is spoken in English (after a timeout) if no |
| // available voice can be loaded. |
| IN_PROC_BROWSER_TEST_F(WelcomeScreenInternationalChromeVoxHintTest, |
| DefaultAnnouncement) { |
| OobeScreenWaiter(WelcomeView::kScreenId).Wait(); |
| TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); |
| // Load an English voice, but do not load a French voice. |
| // Also set the timeout for the fallback hint to 0 MS. |
| const std::string set_no_french_voice = R"( |
| chrome.tts.getVoices = function(callback) { |
| callback([{'lang': 'en-US', 'voiceName': 'Chrome OS US English'}]); |
| };)"; |
| const std::string set_default_hint_timeout_ms = R"( |
| document.getElementById('connect').DEFAULT_CHROMEVOX_HINT_TIMEOUT_MS_ = 0; |
| )"; |
| test::ExecuteOobeJS(set_default_hint_timeout_ms); |
| test::ExecuteOobeJS(set_no_french_voice); |
| test::SpeechMonitor monitor; |
| test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, false); |
| welcome_screen()->GiveChromeVoxHintForTesting(); |
| // Expect speech in English, even though the system locale is French. |
| monitor.ExpectSpeechPatternWithLocale("*", "en-US"); |
| monitor.Replay(); |
| WaitForSpokenSuccessMetric(); |
| } |
| |
| } // namespace chromeos |