// Copyright (c) 2006-2008 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/view_ids.h" #include "chrome/views/view.h" #include "chrome/test/automation/browser_proxy.h" #include "chrome/test/automation/window_proxy.h" #include "chrome/test/automation/tab_proxy.h" #include "chrome/test/ui/ui_test.h" #include "net/url_request/url_request_unittest.h" namespace { // The delay waited after sending an OS simulated event. const int kActionDelayMs = 500; const wchar_t kDocRoot[] = L"chrome/test/data"; const wchar_t kSimplePage[] = L"files/focus/page_with_focus.html"; const wchar_t kStealFocusPage[] = L"files/focus/page_steals_focus.html"; const wchar_t kTypicalPage[] = L"files/focus/typical_page.html"; class BrowserFocusTest : public UITest { public: BrowserFocusTest() { show_window_ = true; dom_automation_enabled_ = true; } }; // Activate a tab by clicking on it. Returns true if the call was successful // (meaning the messages were correctly sent, but does not guarantee the tab // has been changed). bool ActivateTabByClick(AutomationProxy* automation, WindowProxy* browser_window, int tab_index) { // Click on the tab. gfx::Rect bounds; if (!browser_window->GetViewBounds(VIEW_ID_TAB_0 + tab_index, &bounds, true)) return false; POINT click(bounds.CenterPoint().ToPOINT()); if (!browser_window->SimulateOSClick(click, ChromeViews::Event::EF_LEFT_BUTTON_DOWN)) return false; // Wait a bit to let the click be processed. ::Sleep(kActionDelayMs); return true; } } // namespace TEST_F(BrowserFocusTest, BrowsersRememberFocus) { TestServer server(kDocRoot); // First we navigate to our test page. GURL url = server.TestServerPageW(kSimplePage); scoped_ptr tab(GetActiveTab()); EXPECT_NE(AUTOMATION_MSG_NAVIGATION_ERROR, tab->NavigateToURL(url)); // The focus should be on the Tab contents. scoped_ptr window(automation()->GetActiveWindow()); ASSERT_TRUE(window.get() != NULL); scoped_ptr browser(automation()-> GetBrowserForWindow(window.get())); ASSERT_TRUE(browser.get() != NULL); int focused_view_id; EXPECT_TRUE(window->GetFocusedViewID(&focused_view_id)); EXPECT_EQ(VIEW_ID_TAB_CONTAINER, focused_view_id); // Now hide the window, show it again, the focus should not have changed. EXPECT_TRUE(window->SetVisible(false)); EXPECT_TRUE(window->SetVisible(true)); EXPECT_TRUE(window->GetFocusedViewID(&focused_view_id)); EXPECT_EQ(VIEW_ID_TAB_CONTAINER, focused_view_id); // Click on the location bar. gfx::Rect bounds; EXPECT_TRUE(window->GetViewBounds(VIEW_ID_LOCATION_BAR, &bounds, false)); POINT click(bounds.CenterPoint().ToPOINT()); EXPECT_TRUE(window->SimulateOSClick(click, ChromeViews::Event::EF_LEFT_BUTTON_DOWN)); ::Sleep(kActionDelayMs); EXPECT_TRUE(window->GetFocusedViewID(&focused_view_id)); EXPECT_EQ(VIEW_ID_LOCATION_BAR, focused_view_id); // Hide the window, show it again, the focus should not have changed. EXPECT_TRUE(window->SetVisible(false)); EXPECT_TRUE(window->SetVisible(true)); EXPECT_TRUE(window->GetFocusedViewID(&focused_view_id)); EXPECT_EQ(VIEW_ID_LOCATION_BAR, focused_view_id); // Open a new browser window. EXPECT_TRUE(automation()->OpenNewBrowserWindow(SW_SHOWNORMAL)); scoped_ptr new_window(automation()->GetActiveWindow()); ASSERT_TRUE(new_window.get() != NULL); scoped_ptr new_browser(automation()-> GetBrowserForWindow(new_window.get())); ASSERT_TRUE(new_browser.get() != NULL); // Let's make sure we have 2 different browser windows. EXPECT_TRUE(browser->handle() != new_browser->handle()); tab.reset(new_browser->GetActiveTab()); EXPECT_TRUE(tab.get()); tab->NavigateToURL(url); // Switch to the 1st browser window, focus should still be on the location // bar and the second browser should have nothing focused. EXPECT_TRUE(window->Activate()); EXPECT_TRUE(window->GetFocusedViewID(&focused_view_id)); EXPECT_EQ(VIEW_ID_LOCATION_BAR, focused_view_id); EXPECT_TRUE(new_window->GetFocusedViewID(&focused_view_id)); EXPECT_EQ(-1, focused_view_id); // Switch back to the second browser, focus should still be on the page. EXPECT_TRUE(new_window->Activate()); EXPECT_TRUE(new_window->GetFocusedViewID(&focused_view_id)); EXPECT_EQ(VIEW_ID_TAB_CONTAINER, focused_view_id); EXPECT_TRUE(window->GetFocusedViewID(&focused_view_id)); EXPECT_EQ(-1, focused_view_id); } // Tabs remember focus. TEST_F(BrowserFocusTest, TabsRememberFocus) { TestServer server(kDocRoot); scoped_ptr window(automation()->GetActiveWindow()); ASSERT_TRUE(window.get() != NULL); scoped_ptr browser( automation()->GetBrowserForWindow(window.get())); ASSERT_TRUE(browser.get() != NULL); // First we navigate to our test page. GURL url = server.TestServerPageW(kSimplePage); scoped_ptr tab(GetActiveTab()); tab->NavigateToURL(url); // Create several tabs. EXPECT_TRUE(browser->AppendTab(url)); EXPECT_TRUE(browser->AppendTab(url)); EXPECT_TRUE(browser->AppendTab(url)); EXPECT_TRUE(browser->AppendTab(url)); int tab_count; EXPECT_TRUE(browser->GetTabCount(&tab_count)); ASSERT_EQ(5, tab_count); // Alternate focus for the tab. const bool kFocusPage[3][5] = { { true, true, true, true, false }, { false, false, false, false, false }, { false, true, false, true, false } }; for (int i = 1; i < 3; i++) { for (int j = 0; j < 5; j++) { // Click on the tab. ActivateTabByClick(automation(), window.get(), j); // Activate the location bar or the page. int view_id = kFocusPage[i][j] ? VIEW_ID_TAB_CONTAINER : VIEW_ID_LOCATION_BAR; gfx::Rect bounds; EXPECT_TRUE(window->GetViewBounds(view_id, &bounds, true)); POINT click(bounds.CenterPoint().ToPOINT()); EXPECT_TRUE(window->SimulateOSClick(click, ChromeViews::Event::EF_LEFT_BUTTON_DOWN)); ::Sleep(kActionDelayMs); } // Now come back to the tab and check the right view is focused. for (int j = 0; j < 5; j++) { // Click on the tab. ActivateTabByClick(automation(), window.get(), j); // Activate the location bar or the page. int exp_view_id = kFocusPage[i][j] ? VIEW_ID_TAB_CONTAINER : VIEW_ID_LOCATION_BAR; int focused_view_id; EXPECT_TRUE(window->GetFocusedViewID(&focused_view_id)); EXPECT_EQ(exp_view_id, focused_view_id); } } } // Background window does not steal focus. TEST_F(BrowserFocusTest, BackgroundBrowserDontStealFocus) { TestServer server(kDocRoot); // First we navigate to our test page. GURL simple_page_url = server.TestServerPageW(kSimplePage); scoped_ptr tab(GetActiveTab()); tab->NavigateToURL(simple_page_url); scoped_ptr window(automation()->GetActiveWindow()); ASSERT_TRUE(window.get() != NULL); scoped_ptr browser( automation()->GetBrowserForWindow(window.get())); ASSERT_TRUE(browser.get() != NULL); // Open a new browser window. EXPECT_TRUE(automation()->OpenNewBrowserWindow(SW_SHOWNORMAL)); scoped_ptr new_window(automation()->GetActiveWindow()); ASSERT_TRUE(window.get() != NULL); scoped_ptr new_browser( automation()->GetBrowserForWindow(new_window.get())); ASSERT_TRUE(new_browser.get() != NULL); GURL steal_focus_url = server.TestServerPageW(kStealFocusPage); new_browser->AppendTab(steal_focus_url); // Make the first browser active EXPECT_TRUE(window->Activate()); // Wait for the focus to be stolen by the other browser. ::Sleep(2000); // Make sure the 1st browser window is still active. bool is_active = false; EXPECT_TRUE(window->IsActive(&is_active)); EXPECT_TRUE(is_active); } // Page cannot steal focus when focus is on location bar. TEST_F(BrowserFocusTest, LocationBarLockFocus) { TestServer server(kDocRoot); // Open the page that steals focus. GURL url = server.TestServerPageW(kStealFocusPage); scoped_ptr tab(GetActiveTab()); tab->NavigateToURL(url); scoped_ptr window(automation()->GetActiveWindow()); ASSERT_TRUE(window.get() != NULL); scoped_ptr browser( automation()->GetBrowserForWindow(window.get())); ASSERT_TRUE(browser.get() != NULL); // Click on the location bar. gfx::Rect bounds; EXPECT_TRUE(window->GetViewBounds(VIEW_ID_LOCATION_BAR, &bounds, true)); POINT click(bounds.CenterPoint().ToPOINT()); EXPECT_TRUE(window->SimulateOSClick(click, ChromeViews::Event::EF_LEFT_BUTTON_DOWN)); ::Sleep(kActionDelayMs); // Wait for the page to steal focus. ::Sleep(2000); // Make sure the location bar is still focused. int focused_view_id; EXPECT_TRUE(window->GetFocusedViewID(&focused_view_id)); EXPECT_EQ(VIEW_ID_LOCATION_BAR, focused_view_id); } // Focus traversal TEST_F(BrowserFocusTest, FocusTraversal) { TestServer server(kDocRoot); // Open the page the test page. GURL url = server.TestServerPageW(kTypicalPage); scoped_ptr tab(GetActiveTab()); tab->NavigateToURL(url); scoped_ptr window(automation()->GetActiveWindow()); ASSERT_TRUE(window.get() != NULL); scoped_ptr browser( automation()->GetBrowserForWindow(window.get())); ASSERT_TRUE(browser.get() != NULL); // Click on the location bar. gfx::Rect bounds; EXPECT_TRUE(window->GetViewBounds(VIEW_ID_LOCATION_BAR, &bounds, true)); POINT click(bounds.CenterPoint().ToPOINT()); EXPECT_TRUE(window->SimulateOSClick(click, ChromeViews::Event::EF_LEFT_BUTTON_DOWN)); ::Sleep(kActionDelayMs); const wchar_t* kExpElementIDs[] = { L"", // Initially no element in the page should be focused // (the location bar is focused). L"textEdit", L"searchButton", L"luckyButton", L"googleLink", L"gmailLink", L"gmapLink" }; // Test forward focus traversal. for (int i = 0; i < 3; ++i) { // Location bar should be focused. int focused_view_id; EXPECT_TRUE(window->GetFocusedViewID(&focused_view_id)); EXPECT_EQ(VIEW_ID_LOCATION_BAR, focused_view_id); // Now let's press tab to move the focus. for (int j = 0; j < 7; ++j) { // Let's make sure the focus is on the expected element in the page. std::wstring actual; ASSERT_TRUE(tab->ExecuteAndExtractString(L"", L"javascript:void(window.domAutomationController)" L".send(getFocusedElement());", &actual)); ASSERT_STREQ(kExpElementIDs[j], actual.c_str()); window->SimulateOSKeyPress(L'\t', 0); ::Sleep(kActionDelayMs); } } // Now let's try reverse focus traversal. for (int i = 0; i < 3; ++i) { // Location bar should be focused. int focused_view_id; EXPECT_TRUE(window->GetFocusedViewID(&focused_view_id)); EXPECT_EQ(VIEW_ID_LOCATION_BAR, focused_view_id); // Now let's press tab to move the focus. for (int j = 0; j < 7; ++j) { window->SimulateOSKeyPress(L'\t', ChromeViews::Event::EF_SHIFT_DOWN); ::Sleep(kActionDelayMs); // Let's make sure the focus is on the expected element in the page. std::wstring actual; ASSERT_TRUE(tab->ExecuteAndExtractString(L"", L"javascript:void(window.domAutomationController)" L".send(getFocusedElement());", &actual)); ASSERT_STREQ(kExpElementIDs[6 - j], actual.c_str()); } } }