blob: 6111c088c787e86460a522f0f99688822be82443 [file] [log] [blame]
// Copyright 2014 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 "chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.h"
#include <queue>
#include "ash/accelerators/accelerator_controller.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/system/status_area_widget.h"
#include "ash/system/unified/unified_system_tray.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/macros.h"
#include "base/strings/pattern.h"
#include "base/strings/string_util.h"
#include "base/task/post_task.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
#include "chrome/browser/chromeos/login/login_manager_test.h"
#include "chrome/browser/chromeos/login/test/js_checker.h"
#include "chrome/browser/chromeos/login/ui/login_display_host.h"
#include "chrome/browser/chromeos/login/ui/webui_login_view.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
#include "chrome/browser/ui/ash/ksv/keyboard_shortcut_viewer_util.h"
#include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chromeos/constants/chromeos_switches.h"
#include "components/account_id/account_id.h"
#include "components/user_manager/user_names.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/tts_controller.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/process_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/test/ui_controls.h"
#include "ui/views/mus/ax_remote_host.h"
#include "ui/views/widget/widget.h"
namespace chromeos {
LoggedInSpokenFeedbackTest::LoggedInSpokenFeedbackTest()
: animation_mode_(ui::ScopedAnimationDurationScaleMode::ZERO_DURATION) {}
LoggedInSpokenFeedbackTest::~LoggedInSpokenFeedbackTest() = default;
void LoggedInSpokenFeedbackTest::SetUpInProcessBrowserTestFixture() {
AccessibilityManager::SetBrailleControllerForTest(&braille_controller_);
}
void LoggedInSpokenFeedbackTest::TearDownOnMainThread() {
AccessibilityManager::SetBrailleControllerForTest(nullptr);
// Unload the ChromeVox extension so the browser doesn't try to respond to
// in-flight requests during test shutdown. https://crbug.com/923090
AccessibilityManager::Get()->EnableSpokenFeedback(false);
AutomationManagerAura::GetInstance()->Disable();
}
void LoggedInSpokenFeedbackTest::SendKeyPress(ui::KeyboardCode key) {
ASSERT_NO_FATAL_FAILURE(ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
nullptr, key, false, false, false, false)));
}
void LoggedInSpokenFeedbackTest::SendKeyPressWithControl(ui::KeyboardCode key) {
ASSERT_NO_FATAL_FAILURE(ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
nullptr, key, true, false, false, false)));
}
void LoggedInSpokenFeedbackTest::SendKeyPressWithSearchAndShift(
ui::KeyboardCode key) {
ASSERT_NO_FATAL_FAILURE(ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
nullptr, key, false, true, false, true)));
}
void LoggedInSpokenFeedbackTest::SendKeyPressWithSearch(ui::KeyboardCode key) {
ASSERT_NO_FATAL_FAILURE(ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
nullptr, key, false, false, false, true)));
}
void LoggedInSpokenFeedbackTest::RunJavaScriptInChromeVoxBackgroundPage(
const std::string& script) {
extensions::ExtensionHost* host =
extensions::ProcessManager::Get(browser()->profile())
->GetBackgroundHostForExtension(
extension_misc::kChromeVoxExtensionId);
CHECK(content::ExecuteScript(host->host_contents(), script));
}
void LoggedInSpokenFeedbackTest::SimulateTouchScreenInChromeVox() {
// ChromeVox looks at whether 'ontouchstart' exists to know whether
// or not it should respond to hover events. Fake it so that touch
// exploration events get spoken.
RunJavaScriptInChromeVoxBackgroundPage(
"window.ontouchstart = function() {};");
}
bool LoggedInSpokenFeedbackTest::PerformAcceleratorAction(
ash::AcceleratorAction action) {
ash::AcceleratorController* controller =
ash::Shell::Get()->accelerator_controller();
return controller->PerformActionIfEnabled(action);
}
void LoggedInSpokenFeedbackTest::DisableEarcons() {
// Playing earcons from within a test is not only annoying if you're
// running the test locally, but seems to cause crashes
// (http://crbug.com/396507). Work around this by just telling
// ChromeVox to not ever play earcons (prerecorded sound effects).
RunJavaScriptInChromeVoxBackgroundPage(
"cvox.ChromeVox.earcons.playEarcon = function() {};");
}
void LoggedInSpokenFeedbackTest::EnableChromeVox() {
// Test setup.
// Enable ChromeVox, skip welcome message/notification, and disable earcons.
ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled());
AccessibilityManager::Get()->EnableSpokenFeedback(true);
EXPECT_TRUE(speech_monitor_.SkipChromeVoxEnabledMessage());
DisableEarcons();
}
void LoggedInSpokenFeedbackTest::PressRepeatedlyUntilUtterance(
ui::KeyboardCode key,
const std::string& expected_utterance) {
// This helper function is needed when you want to poll for something
// that happens asynchronously. Keep pressing |key|, until
// the speech feedback that follows is |expected_utterance|.
// Note that this doesn't work if pressing that key doesn't speak anything
// at all before the asynchronous event occurred.
while (true) {
SendKeyPress(key);
const std::string& utterance = speech_monitor_.GetNextUtterance();
if (utterance == expected_utterance)
break;
}
}
// This test is very flakey with ChromeVox Next since we generate a lot more
// utterances for text fields.
// TODO(dtseng): Fix properly.
IN_PROC_BROWSER_TEST_F(LoggedInSpokenFeedbackTest, DISABLED_AddBookmark) {
EnableChromeVox();
chrome::ExecuteCommand(browser(), IDC_SHOW_BOOKMARK_BAR);
// Create a bookmark with title "foo".
chrome::ExecuteCommand(browser(), IDC_BOOKMARK_PAGE);
EXPECT_EQ("Bookmark added! dialog Bookmark name about:blank Edit text",
speech_monitor_.GetNextUtterance());
EXPECT_EQ("about:blank", speech_monitor_.GetNextUtterance());
SendKeyPress(ui::VKEY_F);
EXPECT_EQ("f", speech_monitor_.GetNextUtterance());
SendKeyPress(ui::VKEY_O);
EXPECT_EQ("o", speech_monitor_.GetNextUtterance());
SendKeyPress(ui::VKEY_O);
EXPECT_EQ("o", speech_monitor_.GetNextUtterance());
SendKeyPress(ui::VKEY_TAB);
EXPECT_EQ("Bookmark folder combo Box Bookmarks bar",
speech_monitor_.GetNextUtterance());
SendKeyPress(ui::VKEY_RETURN);
EXPECT_TRUE(
base::MatchPattern(speech_monitor_.GetNextUtterance(), "*oolbar*"));
// Wait for active window change to be announced to avoid interference from
// that below.
while (speech_monitor_.GetNextUtterance() != "window about blank tab") {
// Do nothing.
}
// Focus bookmarks bar and listen for "foo".
chrome::ExecuteCommand(browser(), IDC_FOCUS_BOOKMARKS);
while (true) {
std::string utterance = speech_monitor_.GetNextUtterance();
VLOG(0) << "Got utterance: " << utterance;
if (utterance == "Bookmarks,")
break;
}
EXPECT_EQ("foo,", speech_monitor_.GetNextUtterance());
EXPECT_EQ("button", speech_monitor_.GetNextUtterance());
}
IN_PROC_BROWSER_TEST_F(LoggedInSpokenFeedbackTest,
DISABLED_NavigateNotificationCenter) {
EnableChromeVox();
EXPECT_TRUE(PerformAcceleratorAction(ash::TOGGLE_MESSAGE_CENTER_BUBBLE));
// Tab to request the initial focus.
SendKeyPress(ui::VKEY_TAB);
// Wait for it to say "Notification Center, window".
while ("Notification Center, window" != speech_monitor_.GetNextUtterance()) {
}
// Tab until we get to the Do Not Disturb button.
SendKeyPress(ui::VKEY_TAB);
do {
std::string ut = speech_monitor_.GetNextUtterance();
if (ut == "Do not disturb")
break;
else if (ut == "Button")
SendKeyPress(ui::VKEY_TAB);
} while (true);
EXPECT_EQ("Button", speech_monitor_.GetNextUtterance());
EXPECT_EQ("Not pressed", speech_monitor_.GetNextUtterance());
SendKeyPress(ui::VKEY_SPACE);
EXPECT_EQ("Do not disturb", speech_monitor_.GetNextUtterance());
EXPECT_EQ("Button", speech_monitor_.GetNextUtterance());
EXPECT_EQ("Pressed", speech_monitor_.GetNextUtterance());
SendKeyPress(ui::VKEY_SPACE);
EXPECT_EQ("Do not disturb", speech_monitor_.GetNextUtterance());
EXPECT_EQ("Button", speech_monitor_.GetNextUtterance());
EXPECT_EQ("Not pressed", speech_monitor_.GetNextUtterance());
}
// Tests the keyboard shortcut viewer, which is an out-of-process mojo app.
IN_PROC_BROWSER_TEST_F(LoggedInSpokenFeedbackTest, KeyboardShortcutViewer) {
EnableChromeVox();
keyboard_shortcut_viewer_util::ToggleKeyboardShortcutViewer();
// Focus should move to the search field and ChromeVox should speak it.
while ("Search for keyboard shortcuts" !=
speech_monitor_.GetNextUtterance()) {
}
// Capture the destroyed AX tree id when the remote host disconnects.
base::RunLoop run_loop;
ui::AXTreeID destroyed_tree_id = ui::AXTreeIDUnknown();
extensions::AutomationEventRouter::GetInstance()
->SetTreeDestroyedCallbackForTest(base::BindRepeating(
[](base::RunLoop* run_loop, ui::AXTreeID* destroyed_tree_id,
ui::AXTreeID tree_id) {
*destroyed_tree_id = tree_id;
run_loop->Quit();
},
&run_loop, &destroyed_tree_id));
// Close the remote shortcut viewer app.
keyboard_shortcut_viewer_util::ToggleKeyboardShortcutViewer();
// Wait for the AX tree to be destroyed.
run_loop.Run();
// Verify an AX tree was destroyed. It's awkward to get the remote app's
// actual tree ID, so just ensure it's a valid ID and not the desktop.
EXPECT_NE(ui::AXTreeIDUnknown(), destroyed_tree_id);
EXPECT_NE(AutomationManagerAura::GetInstance()->ax_tree_id(),
destroyed_tree_id);
extensions::AutomationEventRouter::GetInstance()
->SetTreeDestroyedCallbackForTest(base::DoNothing());
}
//
// Spoken feedback tests in both a logged in browser window and guest mode.
//
enum SpokenFeedbackTestVariant { kTestAsNormalUser, kTestAsGuestUser };
class SpokenFeedbackTest
: public LoggedInSpokenFeedbackTest,
public ::testing::WithParamInterface<SpokenFeedbackTestVariant> {
protected:
SpokenFeedbackTest() {}
virtual ~SpokenFeedbackTest() {}
void SetUpCommandLine(base::CommandLine* command_line) override {
if (GetParam() == kTestAsGuestUser) {
command_line->AppendSwitch(chromeos::switches::kGuestSession);
command_line->AppendSwitch(::switches::kIncognito);
command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile,
"user");
command_line->AppendSwitchASCII(
switches::kLoginUser, user_manager::GuestAccountId().GetUserEmail());
}
}
};
INSTANTIATE_TEST_SUITE_P(TestAsNormalAndGuestUser,
SpokenFeedbackTest,
::testing::Values(kTestAsNormalUser,
kTestAsGuestUser));
// TODO(tommi): Flakily hitting HasOneRef DCHECK in
// AudioOutputResampler::Shutdown, see crbug.com/630031.
IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, DISABLED_EnableSpokenFeedback) {
EnableChromeVox();
}
IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, FocusToolbar) {
EnableChromeVox();
chrome::ExecuteCommand(browser(), IDC_FOCUS_TOOLBAR);
while (speech_monitor_.GetNextUtterance() != "Reload") {
}
EXPECT_EQ("Button", speech_monitor_.GetNextUtterance());
}
IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, DISABLED_TypeInOmnibox) {
EnableChromeVox();
// Location bar has focus by default so just start typing.
SendKeyPress(ui::VKEY_X);
EXPECT_EQ("x", speech_monitor_.GetNextUtterance());
SendKeyPress(ui::VKEY_Y);
EXPECT_EQ("y", speech_monitor_.GetNextUtterance());
SendKeyPress(ui::VKEY_Z);
EXPECT_EQ("z", speech_monitor_.GetNextUtterance());
SendKeyPress(ui::VKEY_BACK);
EXPECT_EQ("z", speech_monitor_.GetNextUtterance());
}
IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, FocusShelf) {
EnableChromeVox();
EXPECT_TRUE(PerformAcceleratorAction(ash::FOCUS_SHELF));
while (true) {
std::string utterance = speech_monitor_.GetNextUtterance();
if (base::MatchPattern(utterance, "Launcher"))
break;
}
EXPECT_EQ("Button", speech_monitor_.GetNextUtterance());
EXPECT_EQ("Shelf", speech_monitor_.GetNextUtterance());
EXPECT_EQ("Tool bar", speech_monitor_.GetNextUtterance());
EXPECT_EQ(", window", speech_monitor_.GetNextUtterance());
EXPECT_EQ("Press Search plus Space to activate.",
speech_monitor_.GetNextUtterance());
SendKeyPress(ui::VKEY_TAB);
EXPECT_TRUE(base::MatchPattern(speech_monitor_.GetNextUtterance(), "*"));
EXPECT_TRUE(base::MatchPattern(speech_monitor_.GetNextUtterance(), "Button"));
}
IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, OpenStatusTray) {
EnableChromeVox();
EXPECT_TRUE(PerformAcceleratorAction(ash::TOGGLE_SYSTEM_TRAY_BUBBLE));
while (true) {
std::string utterance = speech_monitor_.GetNextUtterance();
if (base::MatchPattern(utterance, "Status tray*"))
break;
}
EXPECT_TRUE(base::MatchPattern(speech_monitor_.GetNextUtterance(), "time *"));
EXPECT_TRUE(base::MatchPattern(speech_monitor_.GetNextUtterance(),
"Battery is*full."));
EXPECT_EQ("Dialog", speech_monitor_.GetNextUtterance());
EXPECT_TRUE(
base::MatchPattern(speech_monitor_.GetNextUtterance(), "*window"));
}
// Fails on ASAN. See http://crbug.com/776308 . (Note MAYBE_ doesn't work well
// with parameterized tests).
#if !defined(ADDRESS_SANITIZER) && !defined(OS_CHROMEOS)
IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, NavigateSystemTray) {
EnableChromeVox();
EXPECT_TRUE(PerformAcceleratorAction(ash::TOGGLE_SYSTEM_TRAY_BUBBLE));
while (true) {
std::string utterance = speech_monitor_.GetNextUtterance();
if (base::MatchPattern(utterance, "Status tray,"))
break;
}
while (true) {
std::string utterance = speech_monitor_.GetNextUtterance();
if (base::MatchPattern(utterance, "*window"))
break;
}
SendKeyPress(ui::VKEY_TAB);
while (true) {
std::string utterance = speech_monitor_.GetNextUtterance();
if (base::MatchPattern(utterance, "Button"))
break;
}
// Next element.
SendKeyPressWithSearch(ui::VKEY_RIGHT);
EXPECT_TRUE(base::MatchPattern(speech_monitor_.GetNextUtterance(), "*"));
EXPECT_TRUE(base::MatchPattern(speech_monitor_.GetNextUtterance(), "Button"));
// Next button.
SendKeyPressWithSearch(ui::VKEY_B);
EXPECT_TRUE(base::MatchPattern(speech_monitor_.GetNextUtterance(), "*"));
EXPECT_TRUE(base::MatchPattern(speech_monitor_.GetNextUtterance(), "Button"));
// Navigate to Bluetooth sub-menu and open it.
while (true) {
SendKeyPress(ui::VKEY_TAB);
std::string content = speech_monitor_.GetNextUtterance();
std::string role = speech_monitor_.GetNextUtterance();
if (base::MatchPattern(content, "*Bluetooth*") &&
base::MatchPattern(role, "Button"))
break;
}
SendKeyPress(ui::VKEY_RETURN);
// Navigate to return to previous menu button and press it.
while (true) {
std::string utterance = speech_monitor_.GetNextUtterance();
if (base::MatchPattern(utterance, "Previous menu"))
break;
SendKeyPress(ui::VKEY_TAB);
}
SendKeyPress(ui::VKEY_RETURN);
while (true) {
std::string utterance = speech_monitor_.GetNextUtterance();
if (base::MatchPattern(utterance, "Bluetooth*"))
break;
}
}
#endif // !defined(ADDRESS_SANITIZER) && !defined(OS_CHROMEOS)
// See http://crbug.com/443608
IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, DISABLED_ScreenBrightness) {
EnableChromeVox();
EXPECT_TRUE(PerformAcceleratorAction(ash::BRIGHTNESS_UP));
EXPECT_TRUE(base::MatchPattern(speech_monitor_.GetNextUtterance(),
"Brightness * percent"));
EXPECT_TRUE(PerformAcceleratorAction(ash::BRIGHTNESS_DOWN));
EXPECT_TRUE(base::MatchPattern(speech_monitor_.GetNextUtterance(),
"Brightness * percent"));
}
IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, DISABLED_VolumeSlider) {
EnableChromeVox();
// Volume slider does not fire valueChanged event on first key press because
// it has no widget.
EXPECT_TRUE(PerformAcceleratorAction(ash::VOLUME_UP));
EXPECT_TRUE(PerformAcceleratorAction(ash::VOLUME_UP));
EXPECT_TRUE(
base::MatchPattern(speech_monitor_.GetNextUtterance(), "* percent*"));
}
IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, OverviewMode) {
EnableChromeVox();
EXPECT_TRUE(PerformAcceleratorAction(ash::TOGGLE_OVERVIEW));
while (true) {
std::string utterance = speech_monitor_.GetNextUtterance();
if (utterance == "Entered window overview mode")
break;
}
SendKeyPress(ui::VKEY_TAB);
// On Chrome OS accessibility title for tabbed browser windows contains app
// name ("Chrome" or "Chromium") in overview mode.
while (true) {
std::string utterance = speech_monitor_.GetNextUtterance();
if (base::MatchPattern(utterance, "Chromium - about:blank"))
break;
}
EXPECT_EQ("Button", speech_monitor_.GetNextUtterance());
}
#if defined(MEMORY_SANITIZER) || defined(OS_CHROMEOS)
// Fails under MemorySanitizer: http://crbug.com/472125
// Test is flaky under ChromeOS: http://crbug.com/897249
#define MAYBE_ChromeVoxShiftSearch DISABLED_ChromeVoxShiftSearch
#else
#define MAYBE_ChromeVoxShiftSearch ChromeVoxShiftSearch
#endif
IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, MAYBE_ChromeVoxShiftSearch) {
EnableChromeVox();
ui_test_utils::NavigateToURL(
browser(),
GURL("data:text/html;charset=utf-8,<button autofocus>Click me</button>"));
while (true) {
std::string utterance = speech_monitor_.GetNextUtterance();
if (utterance == "Click me")
break;
}
// Press Search+/ to enter ChromeVox's "find in page".
SendKeyPressWithSearch(ui::VKEY_OEM_2);
while (true) {
std::string utterance = speech_monitor_.GetNextUtterance();
if (utterance == "Find in page.")
break;
}
}
#if defined(MEMORY_SANITIZER) || defined(OS_CHROMEOS)
// Fails under MemorySanitizer: http://crbug.com/472125
// TODO(crbug.com/721475): Flaky on CrOS.
#define MAYBE_ChromeVoxNavigateAndSelect DISABLED_ChromeVoxNavigateAndSelect
#else
#define MAYBE_ChromeVoxNavigateAndSelect ChromeVoxNavigateAndSelect
#endif
IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, MAYBE_ChromeVoxNavigateAndSelect) {
EnableChromeVox();
ui_test_utils::NavigateToURL(browser(),
GURL("data:text/html;charset=utf-8,"
"<h1>Title</h1>"
"<button autofocus>Click me</button>"));
while (true) {
std::string utterance = speech_monitor_.GetNextUtterance();
if (utterance == "Click me")
break;
}
EXPECT_EQ("Button", speech_monitor_.GetNextUtterance());
// Press Search+Left to navigate to the previous item.
SendKeyPressWithSearch(ui::VKEY_LEFT);
EXPECT_EQ("Title", speech_monitor_.GetNextUtterance());
EXPECT_EQ("Heading 1", speech_monitor_.GetNextUtterance());
// Press Search+S to select the text.
SendKeyPressWithSearch(ui::VKEY_S);
EXPECT_EQ("Title", speech_monitor_.GetNextUtterance());
EXPECT_EQ("selected", speech_monitor_.GetNextUtterance());
// Press again to end the selection.
SendKeyPressWithSearch(ui::VKEY_S);
EXPECT_EQ("End selection", speech_monitor_.GetNextUtterance());
EXPECT_EQ("Title", speech_monitor_.GetNextUtterance());
}
IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, DISABLED_ChromeVoxNextStickyMode) {
EnableChromeVox();
ui_test_utils::NavigateToURL(
browser(),
GURL("data:text/html;charset=utf-8,<button autofocus>Click me</button>"));
while ("Button" != speech_monitor_.GetNextUtterance()) {
}
// Press the sticky-key sequence: Search Search.
SendKeyPress(ui::VKEY_LWIN);
// Sticky key has a minimum 100 ms check to prevent key repeat from toggling
// it.
base::PostDelayedTaskWithTraits(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&LoggedInSpokenFeedbackTest::SendKeyPress,
base::Unretained(this), ui::VKEY_LWIN),
base::TimeDelta::FromMilliseconds(200));
EXPECT_EQ("Sticky mode enabled", speech_monitor_.GetNextUtterance());
SendKeyPress(ui::VKEY_H);
while ("No next heading." != speech_monitor_.GetNextUtterance()) {
}
SendKeyPress(ui::VKEY_LWIN);
// Sticky key has a minimum 100 ms check to prevent key repeat from toggling
// it.
base::PostDelayedTaskWithTraits(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&LoggedInSpokenFeedbackTest::SendKeyPress,
base::Unretained(this), ui::VKEY_LWIN),
base::TimeDelta::FromMilliseconds(200));
while ("Sticky mode disabled" != speech_monitor_.GetNextUtterance()) {
}
}
// Flaky on Linux ChromiumOS MSan Tests. https://crbug.com/752427
IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, DISABLED_TouchExploreStatusTray) {
EnableChromeVox();
SimulateTouchScreenInChromeVox();
// Send an accessibility hover event on the system tray, which is
// what we get when you tap it on a touch screen when ChromeVox is on.
ash::TrayBackgroundView* tray = ash::Shell::Get()
->GetPrimaryRootWindowController()
->GetStatusAreaWidget()
->unified_system_tray();
tray->NotifyAccessibilityEvent(ax::mojom::Event::kHover, true);
EXPECT_EQ("Status tray,", speech_monitor_.GetNextUtterance());
EXPECT_TRUE(base::MatchPattern(speech_monitor_.GetNextUtterance(), "time*,"));
EXPECT_TRUE(
base::MatchPattern(speech_monitor_.GetNextUtterance(), "Battery*"));
EXPECT_EQ("Button", speech_monitor_.GetNextUtterance());
}
IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, ChromeVoxNextTabRecovery) {
EnableChromeVox();
ui_test_utils::NavigateToURL(
browser(), GURL("data:text/html;charset=utf-8,"
"<button id='b1' autofocus>11</button>"
"<button>22</button>"
"<button>33</button>"
"<h1>Middle</h1>"
"<button>44</button>"
"<button>55</button>"
"<div id=console aria-live=polite></div>"
"<script>"
"var b1 = document.getElementById('b1');"
"b1.addEventListener('blur', function() {"
" document.getElementById('console').innerText = "
"'button lost focus';"
"});"
"</script>"));
while ("Button" != speech_monitor_.GetNextUtterance()) {
}
// Press Search+H to go to the next heading
SendKeyPressWithSearch(ui::VKEY_H);
while ("Middle" != speech_monitor_.GetNextUtterance()) {
}
// To ensure that the setSequentialFocusNavigationStartingPoint has
// executed before pressing Tab, the page has an event handler waiting
// for the 'blur' event on the button, and when it loses focus it
// triggers a live region announcement that we wait for, here.
while ("button lost focus" != speech_monitor_.GetNextUtterance()) {
}
// Now we know that focus has left the button, so the sequential focus
// navigation starting point must be on the heading. Press Tab and
// ensure that we land on the first link past the heading.
SendKeyPress(ui::VKEY_TAB);
while ("44" != speech_monitor_.GetNextUtterance()) {
}
}
//
// Spoken feedback tests that run only in guest mode.
//
class GuestSpokenFeedbackTest : public LoggedInSpokenFeedbackTest {
protected:
GuestSpokenFeedbackTest() {}
~GuestSpokenFeedbackTest() override {}
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(chromeos::switches::kGuestSession);
command_line->AppendSwitch(::switches::kIncognito);
command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
command_line->AppendSwitchASCII(
switches::kLoginUser, user_manager::GuestAccountId().GetUserEmail());
}
private:
DISALLOW_COPY_AND_ASSIGN(GuestSpokenFeedbackTest);
};
IN_PROC_BROWSER_TEST_F(GuestSpokenFeedbackTest, FocusToolbar) {
EnableChromeVox();
chrome::ExecuteCommand(browser(), IDC_FOCUS_TOOLBAR);
while (speech_monitor_.GetNextUtterance() != "Reload") {
}
EXPECT_EQ("Button", speech_monitor_.GetNextUtterance());
}
//
// Spoken feedback tests of the out-of-box experience.
//
class OobeSpokenFeedbackTest : public LoginManagerTest {
protected:
OobeSpokenFeedbackTest()
: LoginManagerTest(false, true /* should_initialize_webui */) {}
~OobeSpokenFeedbackTest() override {}
void SetUpCommandLine(base::CommandLine* command_line) override {
LoginManagerTest::SetUpCommandLine(command_line);
// Many bots don't have keyboard/mice which triggers the HID detection
// dialog in the OOBE. Avoid confusing the tests with that.
command_line->AppendSwitch(chromeos::switches::kDisableHIDDetectionOnOOBE);
}
SpeechMonitor speech_monitor_;
private:
DISALLOW_COPY_AND_ASSIGN(OobeSpokenFeedbackTest);
};
// Test is flaky: http://crbug.com/346797
IN_PROC_BROWSER_TEST_F(OobeSpokenFeedbackTest, DISABLED_SpokenFeedbackInOobe) {
ui_controls::EnableUIControls();
ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled());
LoginDisplayHost* login_display_host = LoginDisplayHost::default_host();
WebUILoginView* web_ui_login_view = login_display_host->GetWebUILoginView();
views::Widget* widget = web_ui_login_view->GetWidget();
gfx::NativeWindow window = widget->GetNativeWindow();
// We expect to be in the language select dropdown for this test to work,
// so make sure that's the case.
test::OobeJS().ExecuteAsync("$('language-select').focus()");
AccessibilityManager::Get()->EnableSpokenFeedback(true);
ASSERT_TRUE(speech_monitor_.SkipChromeVoxEnabledMessage());
// There's no guarantee that ChromeVox speaks anything when injected after
// the page loads, which is by design. Tab forward and then backward
// to make sure we get the right feedback from the language and keyboard
// selection fields.
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
window, ui::VKEY_TAB, false, false, false, false));
while (speech_monitor_.GetNextUtterance() != "Select your keyboard:") {
}
EXPECT_EQ("U S", speech_monitor_.GetNextUtterance());
EXPECT_TRUE(base::MatchPattern(speech_monitor_.GetNextUtterance(),
"Combo box * of *"));
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
window, ui::VKEY_TAB, false, true /*shift*/, false, false));
while (speech_monitor_.GetNextUtterance() != "Select your language:") {
}
EXPECT_EQ("English ( United States)", speech_monitor_.GetNextUtterance());
EXPECT_TRUE(base::MatchPattern(speech_monitor_.GetNextUtterance(),
"Combo box * of *"));
}
} // namespace chromeos