// Copyright (c) 2010 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 #include "app/l10n_util.h" #include "base/compiler_specific.h" #include "base/i18n/rtl.h" #include "base/file_path.h" #include "base/sys_info.h" #include "chrome/app/chrome_dll_resource.h" #include "chrome/browser/app_modal_dialog.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_init.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_window.h" #include "chrome/browser/defaults.h" #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/js_modal_dialog.h" #include "chrome/browser/profile.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/tabs/pinned_tab_codec.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/url_constants.h" #include "chrome/common/page_transition_types.h" #include "chrome/test/in_process_browser_test.h" #include "chrome/test/ui_test_utils.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "net/base/mock_host_resolver.h" namespace { const std::string BEFORE_UNLOAD_HTML = "beforeunload" "" ""; const std::wstring OPEN_NEW_BEFOREUNLOAD_PAGE = L"w=window.open(); w.onbeforeunload=function(e){return 'foo'};"; const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html"); const FilePath::CharType* kTitle2File = FILE_PATH_LITERAL("title2.html"); const wchar_t kDocRoot[] = L"chrome/test/data"; // Given a page title, returns the expected window caption string. std::wstring WindowCaptionFromPageTitle(std::wstring page_title) { #if defined(OS_MACOSX) || defined(OS_CHROMEOS) // On Mac or ChromeOS, we don't want to suffix the page title with // the application name. if (page_title.empty()) return l10n_util::GetString(IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED); return page_title; #else if (page_title.empty()) return l10n_util::GetString(IDS_PRODUCT_NAME); return l10n_util::GetStringF(IDS_BROWSER_WINDOW_TITLE_FORMAT, page_title); #endif } // Returns the number of active RenderProcessHosts. int CountRenderProcessHosts() { int result = 0; for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); !i.IsAtEnd(); i.Advance()) ++result; return result; } class MockTabStripModelObserver : public TabStripModelObserver { public: MockTabStripModelObserver() : closing_count_(0) {} virtual void TabClosingAt(TabContents* contents, int index) { closing_count_++; } int closing_count() const { return closing_count_; } private: int closing_count_; DISALLOW_COPY_AND_ASSIGN(MockTabStripModelObserver); }; } // namespace class BrowserTest : public ExtensionBrowserTest { public: // Used by phantom tab tests. Creates two tabs, pins the first and makes it // a phantom tab (by closing it). void PhantomTabTest() { HTTPTestServer* server = StartHTTPServer(); ASSERT_TRUE(server); host_resolver()->AddRule("www.example.com", "127.0.0.1"); GURL url(server->TestServerPage("empty.html")); TabStripModel* model = browser()->tabstrip_model(); ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/"))); Extension* extension_app = GetExtension(); ui_test_utils::NavigateToURL(browser(), url); TabContents* app_contents = new TabContents(browser()->profile(), NULL, MSG_ROUTING_NONE, NULL); app_contents->SetExtensionApp(extension_app); model->AddTabContents(app_contents, 0, 0, TabStripModel::ADD_NONE); model->SetTabPinned(0, true); ui_test_utils::NavigateToURL(browser(), url); // Close the first, which should make it a phantom. model->CloseTabContentsAt(0, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); // There should still be two tabs. ASSERT_EQ(2, browser()->tab_count()); // The first tab should be a phantom. EXPECT_TRUE(model->IsPhantomTab(0)); // And the tab contents of the first tab should have changed. EXPECT_TRUE(model->GetTabContentsAt(0) != app_contents); } protected: virtual void SetUpCommandLine(CommandLine* command_line) { ExtensionBrowserTest::SetUpCommandLine(command_line); // Needed for phantom tab tests. command_line->AppendSwitch(switches::kEnableApps); } // In RTL locales wrap the page title with RTL embedding characters so that it // matches the value returned by GetWindowTitle(). std::wstring LocaleWindowCaptionFromPageTitle( const std::wstring& expected_title) { std::wstring page_title = WindowCaptionFromPageTitle(expected_title); #if defined(OS_WIN) std::string locale = g_browser_process->GetApplicationLocale(); if (base::i18n::GetTextDirectionForLocale(locale.c_str()) == base::i18n::RIGHT_TO_LEFT) { base::i18n::WrapStringWithLTRFormatting(&page_title); } return page_title; #else // Do we need to use the above code on POSIX as well? return page_title; #endif } // Returns the app extension installed by PhantomTabTest. Extension* GetExtension() { const ExtensionList* extensions = browser()->profile()->GetExtensionsService()->extensions(); for (size_t i = 0; i < extensions->size(); ++i) { if ((*extensions)[i]->name() == "App Test") return (*extensions)[i]; } NOTREACHED(); return NULL; } }; // Launch the app on a page with no title, check that the app title was set // correctly. IN_PROC_BROWSER_TEST_F(BrowserTest, NoTitle) { ui_test_utils::NavigateToURL(browser(), ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), FilePath(kTitle1File))); EXPECT_EQ(LocaleWindowCaptionFromPageTitle(L"title1.html"), UTF16ToWideHack(browser()->GetWindowTitleForCurrentTab())); string16 tab_title; ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(), &tab_title)); EXPECT_EQ(ASCIIToUTF16("title1.html"), tab_title); } // Launch the app, navigate to a page with a title, check that the app title // was set correctly. IN_PROC_BROWSER_TEST_F(BrowserTest, Title) { ui_test_utils::NavigateToURL(browser(), ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), FilePath(kTitle2File))); const std::wstring test_title(L"Title Of Awesomeness"); EXPECT_EQ(LocaleWindowCaptionFromPageTitle(test_title), UTF16ToWideHack(browser()->GetWindowTitleForCurrentTab())); string16 tab_title; ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(), &tab_title)); EXPECT_EQ(WideToUTF16(test_title), tab_title); } #if defined(OS_MACOSX) // Test is crashing on Mac, see http://crbug.com/29424. #define MAYBE_JavascriptAlertActivatesTab DISABLED_JavascriptAlertActivatesTab #else #define MAYBE_JavascriptAlertActivatesTab JavascriptAlertActivatesTab #endif IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_JavascriptAlertActivatesTab) { GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), FilePath(kTitle1File))); ui_test_utils::NavigateToURL(browser(), url); browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, 0, TabStripModel::ADD_SELECTED, NULL, std::string()); EXPECT_EQ(2, browser()->tab_count()); EXPECT_EQ(0, browser()->selected_index()); TabContents* second_tab = browser()->GetTabContentsAt(1); ASSERT_TRUE(second_tab); second_tab->render_view_host()->ExecuteJavascriptInWebFrame(L"", L"alert('Activate!');"); AppModalDialog* alert = ui_test_utils::WaitForAppModalDialog(); alert->CloseModalDialog(); EXPECT_EQ(2, browser()->tab_count()); EXPECT_EQ(1, browser()->selected_index()); } // Create 34 tabs and verify that a lot of processes have been created. The // exact number of processes depends on the amount of memory. Previously we // had a hard limit of 31 processes and this test is mainly directed at // verifying that we don't crash when we pass this limit. // BrowserTest.ThirtyFourTabs times out on Mac, see http://crbug.com/43862 #if defined OS_MACOSX #define MAYBE_ThirtyFourTabs DISABLED_ThirtyFourTabs #else #define MAYBE_ThirtyFourTabs ThirtyFourTabs #endif IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_ThirtyFourTabs) { GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), FilePath(kTitle2File))); // There is one initial tab. for (int ix = 0; ix != 33; ++ix) { browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, 0, TabStripModel::ADD_SELECTED, NULL, std::string()); } EXPECT_EQ(34, browser()->tab_count()); // See browser\renderer_host\render_process_host.cc for the algorithm to // decide how many processes to create. if (base::SysInfo::AmountOfPhysicalMemoryMB() >= 2048) { EXPECT_GE(CountRenderProcessHosts(), 24); } else { EXPECT_LE(CountRenderProcessHosts(), 23); } } // Test for crbug.com/22004. Reloading a page with a before unload handler and // then canceling the dialog should not leave the throbber spinning. IN_PROC_BROWSER_TEST_F(BrowserTest, ReloadThenCancelBeforeUnload) { GURL url("data:text/html," + BEFORE_UNLOAD_HTML); ui_test_utils::NavigateToURL(browser(), url); // Navigate to another page, but click cancel in the dialog. Make sure that // the throbber stops spinning. browser()->Reload(CURRENT_TAB); AppModalDialog* alert = ui_test_utils::WaitForAppModalDialog(); alert->CloseModalDialog(); EXPECT_FALSE(browser()->GetSelectedTabContents()->is_loading()); // Clear the beforeunload handler so the test can easily exit. browser()->GetSelectedTabContents()->render_view_host()-> ExecuteJavascriptInWebFrame(L"", L"onbeforeunload=null;"); } // Crashy on mac. http://crbug.com/40150 #if defined(OS_MACOSX) #define MAYBE_SingleBeforeUnloadAfterWindowClose \ DISABLED_SingleBeforeUnloadAfterWindowClose #else #define MAYBE_SingleBeforeUnloadAfterWindowClose \ SingleBeforeUnloadAfterWindowClose #endif // Test for crbug.com/11647. A page closed with window.close() should not have // two beforeunload dialogs shown. IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_SingleBeforeUnloadAfterWindowClose) { browser()->GetSelectedTabContents()->render_view_host()-> ExecuteJavascriptInWebFrame(L"", OPEN_NEW_BEFOREUNLOAD_PAGE); // Close the new window with JavaScript, which should show a single // beforeunload dialog. Then show another alert, to make it easy to verify // that a second beforeunload dialog isn't shown. browser()->GetTabContentsAt(0)->render_view_host()-> ExecuteJavascriptInWebFrame(L"", L"w.close(); alert('bar');"); AppModalDialog* alert = ui_test_utils::WaitForAppModalDialog(); alert->AcceptWindow(); alert = ui_test_utils::WaitForAppModalDialog(); EXPECT_FALSE(static_cast(alert)-> is_before_unload_dialog()); alert->AcceptWindow(); } // Test that get_process_idle_time() returns reasonable values when compared // with time deltas measured locally. IN_PROC_BROWSER_TEST_F(BrowserTest, RenderIdleTime) { base::TimeTicks start = base::TimeTicks::Now(); ui_test_utils::NavigateToURL(browser(), ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), FilePath(kTitle1File))); RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator()); for (; !it.IsAtEnd(); it.Advance()) { base::TimeDelta renderer_td = it.GetCurrentValue()->get_child_process_idle_time(); base::TimeDelta browser_td = base::TimeTicks::Now() - start; EXPECT_TRUE(browser_td >= renderer_td); } } // Test IDC_CREATE_SHORTCUTS command is enabled for url scheme file, ftp, http // and https and disabled for chrome://, about:// etc. // TODO(pinkerton): Disable app-mode in the model until we implement it // on the Mac. http://crbug.com/13148 #if !defined(OS_MACOSX) IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutFile) { CommandUpdater* command_updater = browser()->command_updater(); static const FilePath::CharType* kEmptyFile = FILE_PATH_LITERAL("empty.html"); GURL file_url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), FilePath(kEmptyFile))); ASSERT_TRUE(file_url.SchemeIs(chrome::kFileScheme)); ui_test_utils::NavigateToURL(browser(), file_url); EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); } IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutHttp) { CommandUpdater* command_updater = browser()->command_updater(); scoped_refptr http_server( HTTPTestServer::CreateServer(kDocRoot, NULL)); ASSERT_TRUE(NULL != http_server.get()); GURL http_url(http_server->TestServerPage("")); ASSERT_TRUE(http_url.SchemeIs(chrome::kHttpScheme)); ui_test_utils::NavigateToURL(browser(), http_url); EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); } IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutHttps) { CommandUpdater* command_updater = browser()->command_updater(); scoped_refptr https_server( HTTPSTestServer::CreateGoodServer(kDocRoot)); ASSERT_TRUE(NULL != https_server.get()); GURL https_url(https_server->TestServerPage("/")); ASSERT_TRUE(https_url.SchemeIs(chrome::kHttpsScheme)); ui_test_utils::NavigateToURL(browser(), https_url); EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); } IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutFtp) { CommandUpdater* command_updater = browser()->command_updater(); scoped_refptr ftp_server( FTPTestServer::CreateServer(kDocRoot)); ASSERT_TRUE(NULL != ftp_server.get()); GURL ftp_url(ftp_server->TestServerPage("")); ASSERT_TRUE(ftp_url.SchemeIs(chrome::kFtpScheme)); ui_test_utils::NavigateToURL(browser(), ftp_url); EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); } IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutInvalid) { CommandUpdater* command_updater = browser()->command_updater(); // Urls that should not have shortcuts. GURL new_tab_url(chrome::kChromeUINewTabURL); ui_test_utils::NavigateToURL(browser(), new_tab_url); EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); GURL history_url(chrome::kChromeUIHistoryURL); ui_test_utils::NavigateToURL(browser(), history_url); EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); GURL downloads_url(chrome::kChromeUIDownloadsURL); ui_test_utils::NavigateToURL(browser(), downloads_url); EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); GURL blank_url(chrome::kAboutBlankURL); ui_test_utils::NavigateToURL(browser(), blank_url); EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); } #endif // !defined(OS_MACOSX) // Test RenderView correctly send back favicon url for web page that redirects // to an anchor in javascript body.onload handler. IN_PROC_BROWSER_TEST_F(BrowserTest, FaviconOfOnloadRedirectToAnchorPage) { static const wchar_t kDocRoot[] = L"chrome/test/data"; scoped_refptr server( HTTPTestServer::CreateServer(kDocRoot, NULL)); ASSERT_TRUE(NULL != server.get()); GURL url(server->TestServerPage("files/onload_redirect_to_anchor.html")); GURL expected_favicon_url(server->TestServerPage("files/test.png")); ui_test_utils::NavigateToURL(browser(), url); NavigationEntry* entry = browser()->GetSelectedTabContents()-> controller().GetActiveEntry(); EXPECT_EQ(expected_favicon_url.spec(), entry->favicon().url().spec()); } // Test that an icon can be changed from JS. IN_PROC_BROWSER_TEST_F(BrowserTest, FaviconChange) { static const FilePath::CharType* kFile = FILE_PATH_LITERAL("onload_change_favicon.html"); GURL file_url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), FilePath(kFile))); ASSERT_TRUE(file_url.SchemeIs(chrome::kFileScheme)); ui_test_utils::NavigateToURL(browser(), file_url); NavigationEntry* entry = browser()->GetSelectedTabContents()-> controller().GetActiveEntry(); static const FilePath::CharType* kIcon = FILE_PATH_LITERAL("test1.png"); GURL expected_favicon_url( ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), FilePath(kIcon))); EXPECT_EQ(expected_favicon_url.spec(), entry->favicon().url().spec()); } // TODO(sky): get these to run on a Mac. #if !defined(OS_MACOSX) IN_PROC_BROWSER_TEST_F(BrowserTest, PhantomTab) { if (!browser_defaults::kPhantomTabsEnabled) return; PhantomTabTest(); } IN_PROC_BROWSER_TEST_F(BrowserTest, RevivePhantomTab) { if (!browser_defaults::kPhantomTabsEnabled) return; PhantomTabTest(); if (HasFatalFailure()) return; TabStripModel* model = browser()->tabstrip_model(); // Revive the phantom tab by selecting it. browser()->SelectTabContentsAt(0, true); // There should still be two tabs. ASSERT_EQ(2, browser()->tab_count()); // The first tab should no longer be a phantom. EXPECT_FALSE(model->IsPhantomTab(0)); } // Makes sure TabClosing is sent when uninstalling an extension that is an app // tab. IN_PROC_BROWSER_TEST_F(BrowserTest, TabClosingWhenRemovingExtension) { HTTPTestServer* server = StartHTTPServer(); ASSERT_TRUE(server); host_resolver()->AddRule("www.example.com", "127.0.0.1"); GURL url(server->TestServerPage("empty.html")); TabStripModel* model = browser()->tabstrip_model(); ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/"))); Extension* extension_app = GetExtension(); ui_test_utils::NavigateToURL(browser(), url); TabContents* app_contents = new TabContents(browser()->profile(), NULL, MSG_ROUTING_NONE, NULL); app_contents->SetExtensionApp(extension_app); model->AddTabContents(app_contents, 0, 0, TabStripModel::ADD_NONE); model->SetTabPinned(0, true); ui_test_utils::NavigateToURL(browser(), url); MockTabStripModelObserver observer; model->AddObserver(&observer); // Uninstall the extension and make sure TabClosing is sent. ExtensionsService* service = browser()->profile()->GetExtensionsService(); service->UninstallExtension(GetExtension()->id(), false); EXPECT_EQ(1, observer.closing_count()); model->RemoveObserver(&observer); // There should only be one tab now. ASSERT_EQ(1, browser()->tab_count()); } IN_PROC_BROWSER_TEST_F(BrowserTest, AppTabRemovedWhenExtensionUninstalled) { if (!browser_defaults::kPhantomTabsEnabled) return; PhantomTabTest(); Extension* extension = GetExtension(); UninstallExtension(extension->id()); // The uninstall should have removed the tab. ASSERT_EQ(1, browser()->tab_count()); } #endif // !defined(OS_MACOSX) #if defined(OS_WIN) // http://crbug.com/46198. On XP/Vista, the failure rate is 5 ~ 6%. #define MAYBE_PageLanguageDetection FLAKY_PageLanguageDetection #else #define MAYBE_PageLanguageDetection PageLanguageDetection #endif // Tests that the CLD (Compact Language Detection) works properly. IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_PageLanguageDetection) { static const wchar_t kDocRoot[] = L"chrome/test/data"; scoped_refptr server( HTTPTestServer::CreateServer(kDocRoot, NULL)); ASSERT_TRUE(NULL != server.get()); TabContents* current_tab = browser()->GetSelectedTabContents(); // Navigate to a page in English. ui_test_utils::WindowedNotificationObserverWithDetails en_language_detected_signal(NotificationType::TAB_LANGUAGE_DETERMINED, current_tab); ui_test_utils::NavigateToURL( browser(), GURL(server->TestServerPage("files/english_page.html"))); EXPECT_TRUE(current_tab->language_state().original_language().empty()); en_language_detected_signal.Wait(); std::string lang; EXPECT_TRUE(en_language_detected_signal.GetDetailsFor(current_tab, &lang)); EXPECT_EQ("en", lang); EXPECT_EQ("en", current_tab->language_state().original_language()); // Now navigate to a page in French. ui_test_utils::WindowedNotificationObserverWithDetails fr_language_detected_signal(NotificationType::TAB_LANGUAGE_DETERMINED, current_tab); ui_test_utils::NavigateToURL( browser(), GURL(server->TestServerPage("files/french_page.html"))); EXPECT_TRUE(current_tab->language_state().original_language().empty()); fr_language_detected_signal.Wait(); lang.clear(); EXPECT_TRUE(fr_language_detected_signal.GetDetailsFor(current_tab, &lang)); EXPECT_EQ("fr", lang); EXPECT_EQ("fr", current_tab->language_state().original_language()); } // Chromeos defaults to restoring the last session, so this test isn't // applicable. #if !defined(OS_CHROMEOS) #if defined(OS_MACOSX) // Crashy, http://crbug.com/38522 #define RestorePinnedTabs DISABLED_RestorePinnedTabs #endif // Makes sure pinned tabs are restored correctly on start. IN_PROC_BROWSER_TEST_F(BrowserTest, RestorePinnedTabs) { HTTPTestServer* server = StartHTTPServer(); ASSERT_TRUE(server); // Add an pinned app tab. host_resolver()->AddRule("www.example.com", "127.0.0.1"); GURL url(server->TestServerPage("empty.html")); TabStripModel* model = browser()->tabstrip_model(); ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/"))); Extension* extension_app = GetExtension(); ui_test_utils::NavigateToURL(browser(), url); TabContents* app_contents = new TabContents(browser()->profile(), NULL, MSG_ROUTING_NONE, NULL); app_contents->SetExtensionApp(extension_app); model->AddTabContents(app_contents, 0, 0, TabStripModel::ADD_NONE); model->SetTabPinned(0, true); ui_test_utils::NavigateToURL(browser(), url); // Add a non pinned tab. browser()->NewTab(); // Add a pinned non-app tab. browser()->NewTab(); ui_test_utils::NavigateToURL(browser(), GURL("about:blank")); model->SetTabPinned(2, true); // Write out the pinned tabs. PinnedTabCodec::WritePinnedTabs(browser()->profile()); // Simulate launching again. CommandLine dummy(CommandLine::ARGUMENTS_ONLY); BrowserInit::LaunchWithProfile launch(std::wstring(), dummy); launch.profile_ = browser()->profile(); launch.ProcessStartupURLs(std::vector()); // The launch should have created a new browser. ASSERT_EQ(2u, BrowserList::GetBrowserCount(browser()->profile())); // Find the new browser. Browser* new_browser = NULL; for (BrowserList::const_iterator i = BrowserList::begin(); i != BrowserList::end() && !new_browser; ++i) { if (*i != browser()) new_browser = *i; } ASSERT_TRUE(new_browser); ASSERT_TRUE(new_browser != browser()); // We should get back an additional tab for the app. ASSERT_EQ(2, new_browser->tab_count()); // Make sure the state matches. TabStripModel* new_model = new_browser->tabstrip_model(); EXPECT_TRUE(new_model->IsAppTab(0)); EXPECT_FALSE(new_model->IsAppTab(1)); EXPECT_TRUE(new_model->IsTabPinned(0)); EXPECT_TRUE(new_model->IsTabPinned(1)); EXPECT_TRUE(new_model->GetTabContentsAt(0)->extension_app() == extension_app); } #endif // !defined(OS_CHROMEOS) class BrowserAppRefocusTest : public ExtensionBrowserTest { public: BrowserAppRefocusTest(): server_(NULL), extension_app_(NULL), profile_(NULL) {} protected: virtual void SetUpCommandLine(CommandLine* command_line) { ExtensionBrowserTest::SetUpCommandLine(command_line); command_line->AppendSwitch(switches::kEnableApps); } // Common setup for all tests. Can't use SetUpInProcessBrowserTestFixture // because starting the http server crashes if called from that function. // The IO thread is not set up at that point. virtual void SetUpExtensionApp() { // The web URL of the example app we load has a host of // www.example.com . server_ = StartHTTPServer(); ASSERT_TRUE(server_); host_resolver()->AddRule("www.example.com", "127.0.0.1"); profile_ = browser()->profile(); ASSERT_TRUE(profile_); ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/"))); // Save a pointer to the loaded extension in |extension_app_|. const ExtensionList* extensions = profile_->GetExtensionsService()->extensions(); for (size_t i = 0; i < extensions->size(); ++i) { if ((*extensions)[i]->name() == "App Test") extension_app_ =(*extensions)[i]; } ASSERT_TRUE(extension_app_) << "App Test extension not loaded."; } // Given a tab, wait for navigation in the tab, then test that it is // selected. If this function returns false, an error was logged. bool WaitForTab(TabContents* tab) WARN_UNUSED_RESULT { if (!tab) { LOG(ERROR) << "|tab| should not be NULL."; return false; } ui_test_utils::WaitForNavigation(&(tab->controller())); if (tab != browser()->GetSelectedTabContents()) { LOG(ERROR) << "Tab was not selected."; return false; } return true; } HTTPTestServer* server_; Extension* extension_app_; Profile* profile_; }; #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(TOOLKIT_VIEWS)) #define MAYBE_OpenTab OpenTab #define MAYBE_OpenPanel OpenPanel #define MAYBE_OpenWindow OpenWindow #define MAYBE_WindowBeforeTab WindowBeforeTab #define MAYBE_PanelBeforeTab PanelBeforeTab #define MAYBE_TabInFocusedWindow TabInFocusedWindow #else // Crashes on mac involving app panels: http://crbug.com/42865 // Tests fail on Chrome OS: http://crbug.com/43061 #define MAYBE_OpenTab DISABLED_OpenTab #define MAYBE_OpenPanel DISABLED_OpenPanel #define MAYBE_OpenWindow DISABLED_OpenWindow #define MAYBE_WindowBeforeTab DISABLED_WindowBeforeTab #define MAYBE_PanelBeforeTab DISABLED_PanelBeforeTab #define MAYBE_TabInFocusedWindow DISABLED_TabInFocusedWindow #endif // Test that launching an app refocuses a tab already hosting the app. IN_PROC_BROWSER_TEST_F(BrowserAppRefocusTest, MAYBE_OpenTab) { SetUpExtensionApp(); ASSERT_EQ(1, browser()->tab_count()); ASSERT_EQ(NULL, Browser::FindAppTab(browser(), extension_app_)); // Open a tab with the app. TabContents* tab = Browser::OpenApplicationTab(profile_, extension_app_); ASSERT_TRUE(WaitForTab(tab)); ASSERT_EQ(2, browser()->tab_count()); int app_tab_index = browser()->selected_index(); ASSERT_EQ(0, app_tab_index) << "App tab should be the left most tab."; ASSERT_EQ(browser()->GetTabContentsAt(0), Browser::FindAppTab(browser(), extension_app_)); // Open the same app. The existing tab should stay focused. tab = Browser::OpenApplication(profile_, extension_app_->id()); // No need to wait for navigation, because the tab already exists, // and no navigation should take place. ASSERT_TRUE(tab != NULL); ASSERT_EQ(2, browser()->tab_count()); ASSERT_EQ(app_tab_index, browser()->selected_index()); // Focus the other tab, and reopen the app. The existing tab should // be refocused. browser()->SelectTabContentsAt(1, false); Browser::OpenApplication(profile_, extension_app_->id()); tab = Browser::OpenApplication(profile_, extension_app_->id()); ASSERT_TRUE(tab != NULL); ASSERT_EQ(2, browser()->tab_count()); ASSERT_EQ(app_tab_index, browser()->selected_index()); // Open a second browser window, and open the app in a tab. Browser* second_browser = CreateBrowser(profile_); second_browser->window()->Show(); ASSERT_EQ(NULL, Browser::FindAppTab(second_browser, extension_app_)) << "Browser::FindAppTab() should not find an app tab in the second " << "window, beacuse it has not been added yet."; Browser::OpenApplication(profile_, extension_app_, Extension::LAUNCH_TAB); ASSERT_EQ(2, second_browser->tab_count()) << "Expect the app to open in a tab under |second_browser|."; int second_app_tab_index = second_browser->selected_index(); ASSERT_EQ(0, second_app_tab_index) << "Second app tab should be the left most tab."; ASSERT_EQ(second_browser->GetTabContentsAt(0), Browser::FindAppTab(second_browser, extension_app_)) << "Browser::FindAppTab() should look at the focused window."; } // Test that launching an app refocuses a panel running the app. IN_PROC_BROWSER_TEST_F(BrowserAppRefocusTest, MAYBE_OpenPanel) { SetUpExtensionApp(); ASSERT_EQ(1, browser()->tab_count()); ASSERT_EQ(NULL, Browser::FindAppWindowOrPanel(profile_, extension_app_)); // Open the app in a panel. Browser::OpenApplicationWindow(profile_, extension_app_, Extension::LAUNCH_PANEL, GURL()); Browser* app_panel = BrowserList::GetLastActive(); ASSERT_TRUE(app_panel); ASSERT_NE(app_panel, browser()) << "New browser should have opened."; ASSERT_EQ(app_panel, BrowserList::GetLastActive()); ASSERT_EQ(app_panel, Browser::FindAppWindowOrPanel(profile_, extension_app_)); // Focus the initial browser. browser()->window()->Show(); ASSERT_EQ(browser(), BrowserList::GetLastActive()); // Open the app. Browser::OpenApplication(profile_, extension_app_->id()); // Focus should move to the panel. ASSERT_EQ(app_panel, BrowserList::GetLastActive()); ASSERT_EQ(app_panel, Browser::FindAppWindowOrPanel(profile_, extension_app_)); // No new tab should have been created in the initial browser. ASSERT_EQ(1, browser()->tab_count()); } // Test that launching an app refocuses a window running the app. IN_PROC_BROWSER_TEST_F(BrowserAppRefocusTest, MAYBE_OpenWindow) { SetUpExtensionApp(); ASSERT_EQ(1, browser()->tab_count()); ASSERT_EQ(NULL, Browser::FindAppWindowOrPanel(profile_, extension_app_)); // Open a window with the app. Browser::OpenApplicationWindow(profile_, extension_app_, Extension::LAUNCH_WINDOW, GURL()); Browser* app_window = BrowserList::GetLastActive(); ASSERT_TRUE(app_window); ASSERT_NE(app_window, browser()) << "New browser should have opened."; // Focus the initial browser. browser()->window()->Show(); ASSERT_EQ(browser(), BrowserList::GetLastActive()); // Open the app. Browser::OpenApplication(profile_, extension_app_->id()); // Focus should move to the window. ASSERT_EQ(app_window, BrowserList::GetLastActive()); ASSERT_EQ(app_window, Browser::FindAppWindowOrPanel(profile_, extension_app_)); // No new tab should have been created in the initial browser. ASSERT_EQ(1, browser()->tab_count()); } // Test that if an app is opened while running in a window and a tab, // the window is focused. IN_PROC_BROWSER_TEST_F(BrowserAppRefocusTest, MAYBE_WindowBeforeTab) { SetUpExtensionApp(); ASSERT_EQ(1, browser()->tab_count()); // Open a tab with the app. Browser::OpenApplicationTab(profile_, extension_app_); ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser())); ASSERT_EQ(2, browser()->tab_count()); int app_tab_index = browser()->selected_index(); ASSERT_EQ(0, app_tab_index) << "App tab should be the left most tab."; // Open a window with the app. Browser::OpenApplicationWindow(profile_, extension_app_, Extension::LAUNCH_WINDOW, GURL()); Browser* app_window = BrowserList::GetLastActive(); ASSERT_TRUE(app_window); ASSERT_NE(app_window, browser()) << "New browser should have opened."; // Focus the initial browser. browser()->window()->Show(); // Open the app. Focus should move to the window. Browser::OpenApplication(profile_, extension_app_->id()); ASSERT_EQ(app_window, BrowserList::GetLastActive()); } // Test that if an app is opened while running in a panel and a tab, // the panel is focused. IN_PROC_BROWSER_TEST_F(BrowserAppRefocusTest, MAYBE_PanelBeforeTab) { SetUpExtensionApp(); ASSERT_EQ(1, browser()->tab_count()); // Open a tab with the app. TabContents* tab = Browser::OpenApplicationTab(profile_, extension_app_); ASSERT_TRUE(WaitForTab(tab)); ASSERT_EQ(2, browser()->tab_count()); int app_tab_index = browser()->selected_index(); ASSERT_EQ(0, app_tab_index) << "App tab should be the left most tab."; // Open a panel with the app. Browser::OpenApplicationWindow(profile_, extension_app_, Extension::LAUNCH_PANEL, GURL()); Browser* app_panel = BrowserList::GetLastActive(); ASSERT_TRUE(app_panel); ASSERT_NE(app_panel, browser()) << "New browser should have opened."; // Focus the initial browser. browser()->window()->Show(); // Open the app. Focus should move to the panel. Browser::OpenApplication(profile_, extension_app_->id()); ASSERT_EQ(app_panel, BrowserList::GetLastActive()); } // Test that if multiple tabs host an app, and that app is opened, // the tab in the current window gets focus. IN_PROC_BROWSER_TEST_F(BrowserAppRefocusTest, MAYBE_TabInFocusedWindow) { SetUpExtensionApp(); ASSERT_EQ(1, browser()->tab_count()); Browser::OpenApplicationTab(profile_, extension_app_); ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser())); ASSERT_EQ(2, browser()->tab_count()); int app_tab_index = browser()->selected_index(); ASSERT_EQ(0, app_tab_index) << "App tab should be the left most tab."; // Open a new browser window, add an app tab. Browser* extra_browser = CreateBrowser(profile_); ASSERT_EQ(extra_browser, BrowserList::GetLastActive()); Browser::OpenApplicationTab(profile_, extension_app_); ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(extra_browser)); ASSERT_EQ(2, extra_browser->tab_count()); app_tab_index = extra_browser->selected_index(); ASSERT_EQ(0, app_tab_index) << "App tab should be the left most tab"; // Open the app. Focus should move to the panel. Browser::OpenApplication(profile_, extension_app_->id()); ASSERT_EQ(extra_browser, BrowserList::GetLastActive()); ASSERT_EQ(2, extra_browser->tab_count()); browser()->window()->Show(); Browser::OpenApplication(profile_, extension_app_->id()); ASSERT_EQ(browser(), BrowserList::GetLastActive()); ASSERT_EQ(2, browser()->tab_count()); } // TODO(ben): this test was never enabled. It has bit-rotted since being added. // It originally lived in browser_unittest.cc, but has been moved here to make // room for real browser unit tests. #if 0 class BrowserTest2 : public InProcessBrowserTest { public: BrowserTest2() { host_resolver_proc_ = new net::RuleBasedHostResolverProc(NULL); // Avoid making external DNS lookups. In this test we don't need this // to succeed. host_resolver_proc_->AddSimulatedFailure("*.google.com"); scoped_host_resolver_proc_.Init(host_resolver_proc_.get()); } private: scoped_refptr host_resolver_proc_; net::ScopedDefaultHostResolverProc scoped_host_resolver_proc_; }; IN_PROC_BROWSER_TEST_F(BrowserTest2, NoTabsInPopups) { Browser::RegisterAppPrefs(L"Test"); // We start with a normal browser with one tab. EXPECT_EQ(1, browser()->tab_count()); // Open a popup browser with a single blank foreground tab. Browser* popup_browser = browser()->CreateForPopup(browser()->profile()); popup_browser->AddBlankTab(true); EXPECT_EQ(1, popup_browser->tab_count()); // Now try opening another tab in the popup browser. popup_browser->AddTabWithURL( GURL(chrome::kAboutBlankURL), GURL(), PageTransition::TYPED, -1, TabStripModel::ADD_SELECTED, NULL, std::string()); // The popup should still only have one tab. EXPECT_EQ(1, popup_browser->tab_count()); // The normal browser should now have two. EXPECT_EQ(2, browser()->tab_count()); // Open an app frame browser with a single blank foreground tab. Browser* app_browser = browser()->CreateForApp(L"Test", browser()->profile(), false); app_browser->AddBlankTab(true); EXPECT_EQ(1, app_browser->tab_count()); // Now try opening another tab in the app browser. app_browser->AddTabWithURL( GURL(chrome::kAboutBlankURL), GURL(), PageTransition::TYPED, -1, TabStripModel::ADD_SELECTED, NULL, std::string()); // The popup should still only have one tab. EXPECT_EQ(1, app_browser->tab_count()); // The normal browser should now have three. EXPECT_EQ(3, browser()->tab_count()); // Open an app frame popup browser with a single blank foreground tab. Browser* app_popup_browser = browser()->CreateForApp(L"Test", browser()->profile(), false); app_popup_browser->AddBlankTab(true); EXPECT_EQ(1, app_popup_browser->tab_count()); // Now try opening another tab in the app popup browser. app_popup_browser->AddTabWithURL( GURL(chrome::kAboutBlankURL), GURL(), PageTransition::TYPED, -1, TabStripModel::ADD_SELECTED, NULL, std::string()); // The popup should still only have one tab. EXPECT_EQ(1, app_popup_browser->tab_count()); // The normal browser should now have four. EXPECT_EQ(4, browser()->tab_count()); // Close the additional browsers. popup_browser->CloseAllTabs(); app_browser->CloseAllTabs(); app_popup_browser->CloseAllTabs(); } #endif