// Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #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()); EXPECT_TRUE(window.get() != NULL); scoped_ptr browser(automation()-> GetBrowserForWindow(window.get())); 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()); EXPECT_TRUE(new_window.get() != NULL); scoped_ptr new_browser(automation()-> GetBrowserForWindow(new_window.get())); EXPECT_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()); EXPECT_TRUE(window.get() != NULL); scoped_ptr browser( automation()->GetBrowserForWindow(window.get())); // 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()); EXPECT_TRUE(window.get() != NULL); scoped_ptr browser( automation()->GetBrowserForWindow(window.get())); // Open a new browser window. EXPECT_TRUE(automation()->OpenNewBrowserWindow(SW_SHOWNORMAL)); scoped_ptr new_window(automation()->GetActiveWindow()); EXPECT_TRUE(window.get() != NULL); scoped_ptr new_browser( automation()->GetBrowserForWindow(new_window.get())); 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()); EXPECT_TRUE(window.get() != NULL); scoped_ptr browser( automation()->GetBrowserForWindow(window.get())); // 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()); EXPECT_TRUE(window.get() != NULL); scoped_ptr browser( automation()->GetBrowserForWindow(window.get())); // 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()); } } }