1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <string> 6 7 #include "base/compiler_specific.h" 8 #include "base/file_path.h" 9 #include "base/sys_info.h" 10 #include "base/utf_string_conversions.h" 11 #include "chrome/app/chrome_command_ids.h" 12 #include "chrome/browser/defaults.h" 13 #include "chrome/browser/extensions/extension_browsertest.h" 14 #include "chrome/browser/extensions/extension_service.h" 15 #include "chrome/browser/extensions/extension_tab_helper.h" 16 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/tabs/pinned_tab_codec.h" 18 #include "chrome/browser/tabs/tab_strip_model.h" 19 #include "chrome/browser/translate/translate_tab_helper.h" 20 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h" 21 #include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h" 22 #include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h" 23 #include "chrome/browser/ui/browser.h" 24 #include "chrome/browser/ui/browser_init.h" 25 #include "chrome/browser/ui/browser_list.h" 26 #include "chrome/browser/ui/browser_navigator.h" 27 #include "chrome/browser/ui/browser_window.h" 28 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 29 #include "chrome/common/chrome_switches.h" 30 #include "chrome/common/extensions/extension.h" 31 #include "chrome/common/url_constants.h" 32 #include "chrome/test/in_process_browser_test.h" 33 #include "chrome/test/ui_test_utils.h" 34 #include "content/browser/renderer_host/render_process_host.h" 35 #include "content/browser/renderer_host/render_view_host.h" 36 #include "content/browser/tab_contents/tab_contents.h" 37 #include "content/common/notification_source.h" 38 #include "content/common/page_transition_types.h" 39 #include "grit/chromium_strings.h" 40 #include "grit/generated_resources.h" 41 #include "net/base/mock_host_resolver.h" 42 #include "net/test/test_server.h" 43 #include "ui/base/l10n/l10n_util.h" 44 45 #if defined(OS_WIN) 46 #include "base/i18n/rtl.h" 47 #include "chrome/browser/browser_process.h" 48 #endif 49 50 namespace { 51 52 const char* kBeforeUnloadHTML = 53 "<html><head><title>beforeunload</title></head><body>" 54 "<script>window.onbeforeunload=function(e){return 'foo'}</script>" 55 "</body></html>"; 56 57 const char* kOpenNewBeforeUnloadPage = 58 "w=window.open(); w.onbeforeunload=function(e){return 'foo'};"; 59 60 const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html"); 61 const FilePath::CharType* kTitle2File = FILE_PATH_LITERAL("title2.html"); 62 63 const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data"); 64 65 // Given a page title, returns the expected window caption string. 66 std::wstring WindowCaptionFromPageTitle(std::wstring page_title) { 67 #if defined(OS_MACOSX) || defined(OS_CHROMEOS) 68 // On Mac or ChromeOS, we don't want to suffix the page title with 69 // the application name. 70 if (page_title.empty()) { 71 return UTF16ToWideHack( 72 l10n_util::GetStringUTF16(IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED)); 73 } 74 return page_title; 75 #else 76 if (page_title.empty()) 77 return UTF16ToWideHack(l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); 78 79 return UTF16ToWideHack( 80 l10n_util::GetStringFUTF16(IDS_BROWSER_WINDOW_TITLE_FORMAT, 81 WideToUTF16Hack(page_title))); 82 #endif 83 } 84 85 // Returns the number of active RenderProcessHosts. 86 int CountRenderProcessHosts() { 87 int result = 0; 88 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); 89 !i.IsAtEnd(); i.Advance()) 90 ++result; 91 return result; 92 } 93 94 class MockTabStripModelObserver : public TabStripModelObserver { 95 public: 96 MockTabStripModelObserver() : closing_count_(0) {} 97 98 virtual void TabClosingAt(TabStripModel* tab_strip_model, 99 TabContentsWrapper* contents, 100 int index) { 101 closing_count_++; 102 } 103 104 int closing_count() const { return closing_count_; } 105 106 private: 107 int closing_count_; 108 109 DISALLOW_COPY_AND_ASSIGN(MockTabStripModelObserver); 110 }; 111 112 // Used by CloseWithAppMenuOpen. Invokes CloseWindow on the supplied browser. 113 class CloseWindowTask : public Task { 114 public: 115 explicit CloseWindowTask(Browser* browser) : browser_(browser) {} 116 117 virtual void Run() { 118 browser_->CloseWindow(); 119 } 120 121 private: 122 Browser* browser_; 123 124 DISALLOW_COPY_AND_ASSIGN(CloseWindowTask); 125 }; 126 127 // Used by CloseWithAppMenuOpen. Posts a CloseWindowTask and shows the app menu. 128 class RunCloseWithAppMenuTask : public Task { 129 public: 130 explicit RunCloseWithAppMenuTask(Browser* browser) : browser_(browser) {} 131 132 virtual void Run() { 133 // ShowAppMenu is modal under views. Schedule a task that closes the window. 134 MessageLoop::current()->PostTask(FROM_HERE, new CloseWindowTask(browser_)); 135 browser_->ShowAppMenu(); 136 } 137 138 private: 139 Browser* browser_; 140 141 DISALLOW_COPY_AND_ASSIGN(RunCloseWithAppMenuTask); 142 }; 143 144 } // namespace 145 146 class BrowserTest : public ExtensionBrowserTest { 147 protected: 148 // In RTL locales wrap the page title with RTL embedding characters so that it 149 // matches the value returned by GetWindowTitle(). 150 std::wstring LocaleWindowCaptionFromPageTitle( 151 const std::wstring& expected_title) { 152 std::wstring page_title = WindowCaptionFromPageTitle(expected_title); 153 #if defined(OS_WIN) 154 std::string locale = g_browser_process->GetApplicationLocale(); 155 if (base::i18n::GetTextDirectionForLocale(locale.c_str()) == 156 base::i18n::RIGHT_TO_LEFT) { 157 base::i18n::WrapStringWithLTRFormatting(&page_title); 158 } 159 160 return page_title; 161 #else 162 // Do we need to use the above code on POSIX as well? 163 return page_title; 164 #endif 165 } 166 167 // Returns the app extension aptly named "App Test". 168 const Extension* GetExtension() { 169 const ExtensionList* extensions = 170 browser()->profile()->GetExtensionService()->extensions(); 171 for (size_t i = 0; i < extensions->size(); ++i) { 172 if ((*extensions)[i]->name() == "App Test") 173 return (*extensions)[i]; 174 } 175 NOTREACHED(); 176 return NULL; 177 } 178 }; 179 180 // Launch the app on a page with no title, check that the app title was set 181 // correctly. 182 IN_PROC_BROWSER_TEST_F(BrowserTest, NoTitle) { 183 ui_test_utils::NavigateToURL(browser(), 184 ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), 185 FilePath(kTitle1File))); 186 EXPECT_EQ(LocaleWindowCaptionFromPageTitle(L"title1.html"), 187 UTF16ToWideHack(browser()->GetWindowTitleForCurrentTab())); 188 string16 tab_title; 189 ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(), &tab_title)); 190 EXPECT_EQ(ASCIIToUTF16("title1.html"), tab_title); 191 } 192 193 // Launch the app, navigate to a page with a title, check that the app title 194 // was set correctly. 195 IN_PROC_BROWSER_TEST_F(BrowserTest, Title) { 196 ui_test_utils::NavigateToURL(browser(), 197 ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), 198 FilePath(kTitle2File))); 199 const std::wstring test_title(L"Title Of Awesomeness"); 200 EXPECT_EQ(LocaleWindowCaptionFromPageTitle(test_title), 201 UTF16ToWideHack(browser()->GetWindowTitleForCurrentTab())); 202 string16 tab_title; 203 ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(), &tab_title)); 204 EXPECT_EQ(WideToUTF16(test_title), tab_title); 205 } 206 207 IN_PROC_BROWSER_TEST_F(BrowserTest, JavascriptAlertActivatesTab) { 208 GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), 209 FilePath(kTitle1File))); 210 ui_test_utils::NavigateToURL(browser(), url); 211 AddTabAtIndex(0, url, PageTransition::TYPED); 212 EXPECT_EQ(2, browser()->tab_count()); 213 EXPECT_EQ(0, browser()->active_index()); 214 TabContents* second_tab = browser()->GetTabContentsAt(1); 215 ASSERT_TRUE(second_tab); 216 second_tab->render_view_host()->ExecuteJavascriptInWebFrame( 217 string16(), 218 ASCIIToUTF16("alert('Activate!');")); 219 AppModalDialog* alert = ui_test_utils::WaitForAppModalDialog(); 220 alert->CloseModalDialog(); 221 EXPECT_EQ(2, browser()->tab_count()); 222 EXPECT_EQ(1, browser()->active_index()); 223 } 224 225 226 227 #if defined(OS_WIN) 228 // http://crbug.com/75274. On XP crashes inside 229 // URLFetcher::Core::Registry::RemoveURLFetcherCore. 230 #define MAYBE_ThirtyFourTabs FLAKY_ThirtyFourTabs 231 #else 232 #define MAYBE_ThirtyFourTabs ThirtyFourTabs 233 #endif 234 235 // Create 34 tabs and verify that a lot of processes have been created. The 236 // exact number of processes depends on the amount of memory. Previously we 237 // had a hard limit of 31 processes and this test is mainly directed at 238 // verifying that we don't crash when we pass this limit. 239 // Warning: this test can take >30 seconds when running on a slow (low 240 // memory?) Mac builder. 241 IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_ThirtyFourTabs) { 242 GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), 243 FilePath(kTitle2File))); 244 245 // There is one initial tab. 246 for (int ix = 0; ix != 33; ++ix) 247 browser()->AddSelectedTabWithURL(url, PageTransition::TYPED); 248 EXPECT_EQ(34, browser()->tab_count()); 249 250 // See browser\renderer_host\render_process_host.cc for the algorithm to 251 // decide how many processes to create. 252 if (base::SysInfo::AmountOfPhysicalMemoryMB() >= 2048) { 253 EXPECT_GE(CountRenderProcessHosts(), 24); 254 } else { 255 EXPECT_LE(CountRenderProcessHosts(), 23); 256 } 257 } 258 259 // Test for crbug.com/22004. Reloading a page with a before unload handler and 260 // then canceling the dialog should not leave the throbber spinning. 261 IN_PROC_BROWSER_TEST_F(BrowserTest, ReloadThenCancelBeforeUnload) { 262 GURL url(std::string("data:text/html,") + kBeforeUnloadHTML); 263 ui_test_utils::NavigateToURL(browser(), url); 264 265 // Navigate to another page, but click cancel in the dialog. Make sure that 266 // the throbber stops spinning. 267 browser()->Reload(CURRENT_TAB); 268 AppModalDialog* alert = ui_test_utils::WaitForAppModalDialog(); 269 alert->CloseModalDialog(); 270 EXPECT_FALSE(browser()->GetSelectedTabContents()->is_loading()); 271 272 // Clear the beforeunload handler so the test can easily exit. 273 browser()->GetSelectedTabContents()->render_view_host()-> 274 ExecuteJavascriptInWebFrame(string16(), 275 ASCIIToUTF16("onbeforeunload=null;")); 276 } 277 278 // Crashy on mac. http://crbug.com/38522 279 #if defined(OS_MACOSX) 280 #define MAYBE_SingleBeforeUnloadAfterWindowClose \ 281 DISABLED_SingleBeforeUnloadAfterWindowClose 282 #else 283 #define MAYBE_SingleBeforeUnloadAfterWindowClose \ 284 SingleBeforeUnloadAfterWindowClose 285 #endif 286 287 // Test for crbug.com/11647. A page closed with window.close() should not have 288 // two beforeunload dialogs shown. 289 IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_SingleBeforeUnloadAfterWindowClose) { 290 browser()->GetSelectedTabContents()->render_view_host()-> 291 ExecuteJavascriptInWebFrame(string16(), 292 ASCIIToUTF16(kOpenNewBeforeUnloadPage)); 293 294 // Close the new window with JavaScript, which should show a single 295 // beforeunload dialog. Then show another alert, to make it easy to verify 296 // that a second beforeunload dialog isn't shown. 297 browser()->GetTabContentsAt(0)->render_view_host()-> 298 ExecuteJavascriptInWebFrame(string16(), 299 ASCIIToUTF16("w.close(); alert('bar');")); 300 AppModalDialog* alert = ui_test_utils::WaitForAppModalDialog(); 301 alert->native_dialog()->AcceptAppModalDialog(); 302 303 alert = ui_test_utils::WaitForAppModalDialog(); 304 EXPECT_FALSE(static_cast<JavaScriptAppModalDialog*>(alert)-> 305 is_before_unload_dialog()); 306 alert->native_dialog()->AcceptAppModalDialog(); 307 } 308 309 // Test that get_process_idle_time() returns reasonable values when compared 310 // with time deltas measured locally. 311 IN_PROC_BROWSER_TEST_F(BrowserTest, RenderIdleTime) { 312 base::TimeTicks start = base::TimeTicks::Now(); 313 ui_test_utils::NavigateToURL(browser(), 314 ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), 315 FilePath(kTitle1File))); 316 RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator()); 317 for (; !it.IsAtEnd(); it.Advance()) { 318 base::TimeDelta renderer_td = 319 it.GetCurrentValue()->get_child_process_idle_time(); 320 base::TimeDelta browser_td = base::TimeTicks::Now() - start; 321 EXPECT_TRUE(browser_td >= renderer_td); 322 } 323 } 324 325 // Test IDC_CREATE_SHORTCUTS command is enabled for url scheme file, ftp, http 326 // and https and disabled for chrome://, about:// etc. 327 // TODO(pinkerton): Disable app-mode in the model until we implement it 328 // on the Mac. http://crbug.com/13148 329 #if !defined(OS_MACOSX) 330 IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutFile) { 331 CommandUpdater* command_updater = browser()->command_updater(); 332 333 static const FilePath::CharType* kEmptyFile = FILE_PATH_LITERAL("empty.html"); 334 GURL file_url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), 335 FilePath(kEmptyFile))); 336 ASSERT_TRUE(file_url.SchemeIs(chrome::kFileScheme)); 337 ui_test_utils::NavigateToURL(browser(), file_url); 338 EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); 339 } 340 341 IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutHttp) { 342 CommandUpdater* command_updater = browser()->command_updater(); 343 344 ASSERT_TRUE(test_server()->Start()); 345 GURL http_url(test_server()->GetURL("")); 346 ASSERT_TRUE(http_url.SchemeIs(chrome::kHttpScheme)); 347 ui_test_utils::NavigateToURL(browser(), http_url); 348 EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); 349 } 350 351 IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutHttps) { 352 CommandUpdater* command_updater = browser()->command_updater(); 353 354 net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath(kDocRoot)); 355 ASSERT_TRUE(test_server.Start()); 356 GURL https_url(test_server.GetURL("/")); 357 ASSERT_TRUE(https_url.SchemeIs(chrome::kHttpsScheme)); 358 ui_test_utils::NavigateToURL(browser(), https_url); 359 EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); 360 } 361 362 IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutFtp) { 363 CommandUpdater* command_updater = browser()->command_updater(); 364 365 net::TestServer test_server(net::TestServer::TYPE_FTP, FilePath(kDocRoot)); 366 ASSERT_TRUE(test_server.Start()); 367 GURL ftp_url(test_server.GetURL("")); 368 ASSERT_TRUE(ftp_url.SchemeIs(chrome::kFtpScheme)); 369 ui_test_utils::NavigateToURL(browser(), ftp_url); 370 EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); 371 } 372 373 IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutInvalid) { 374 CommandUpdater* command_updater = browser()->command_updater(); 375 376 // Urls that should not have shortcuts. 377 GURL new_tab_url(chrome::kChromeUINewTabURL); 378 ui_test_utils::NavigateToURL(browser(), new_tab_url); 379 EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); 380 381 GURL history_url(chrome::kChromeUIHistoryURL); 382 ui_test_utils::NavigateToURL(browser(), history_url); 383 EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); 384 385 GURL downloads_url(chrome::kChromeUIDownloadsURL); 386 ui_test_utils::NavigateToURL(browser(), downloads_url); 387 EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); 388 389 GURL blank_url(chrome::kAboutBlankURL); 390 ui_test_utils::NavigateToURL(browser(), blank_url); 391 EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS)); 392 } 393 394 // Change a tab into an application window. 395 // DISABLED: http://crbug.com/72310 396 IN_PROC_BROWSER_TEST_F(BrowserTest, DISABLED_ConvertTabToAppShortcut) { 397 ASSERT_TRUE(test_server()->Start()); 398 GURL http_url(test_server()->GetURL("")); 399 ASSERT_TRUE(http_url.SchemeIs(chrome::kHttpScheme)); 400 401 ASSERT_EQ(1, browser()->tab_count()); 402 TabContents* initial_tab = browser()->GetTabContentsAt(0); 403 TabContents* app_tab = browser()->AddSelectedTabWithURL( 404 http_url, PageTransition::TYPED)->tab_contents(); 405 ASSERT_EQ(2, browser()->tab_count()); 406 ASSERT_EQ(1u, BrowserList::GetBrowserCount(browser()->profile())); 407 408 // Normal tabs should accept load drops. 409 EXPECT_TRUE(initial_tab->GetMutableRendererPrefs()->can_accept_load_drops); 410 EXPECT_TRUE(app_tab->GetMutableRendererPrefs()->can_accept_load_drops); 411 412 // Turn |app_tab| into a tab in an app panel. 413 browser()->ConvertContentsToApplication(app_tab); 414 415 // The launch should have created a new browser. 416 ASSERT_EQ(2u, BrowserList::GetBrowserCount(browser()->profile())); 417 418 // Find the new browser. 419 Browser* app_browser = NULL; 420 for (BrowserList::const_iterator i = BrowserList::begin(); 421 i != BrowserList::end() && !app_browser; ++i) { 422 if (*i != browser()) 423 app_browser = *i; 424 } 425 ASSERT_TRUE(app_browser); 426 427 // Check that the tab contents is in the new browser, and not in the old. 428 ASSERT_EQ(1, browser()->tab_count()); 429 ASSERT_EQ(initial_tab, browser()->GetTabContentsAt(0)); 430 431 // Check that the appliaction browser has a single tab, and that tab contains 432 // the content that we app-ified. 433 ASSERT_EQ(1, app_browser->tab_count()); 434 ASSERT_EQ(app_tab, app_browser->GetTabContentsAt(0)); 435 436 // Normal tabs should accept load drops. 437 EXPECT_TRUE(initial_tab->GetMutableRendererPrefs()->can_accept_load_drops); 438 439 // The tab in an app window should not. 440 EXPECT_FALSE(app_tab->GetMutableRendererPrefs()->can_accept_load_drops); 441 } 442 443 #endif // !defined(OS_MACOSX) 444 445 // Test RenderView correctly send back favicon url for web page that redirects 446 // to an anchor in javascript body.onload handler. 447 IN_PROC_BROWSER_TEST_F(BrowserTest, FaviconOfOnloadRedirectToAnchorPage) { 448 ASSERT_TRUE(test_server()->Start()); 449 GURL url(test_server()->GetURL("files/onload_redirect_to_anchor.html")); 450 GURL expected_favicon_url(test_server()->GetURL("files/test.png")); 451 452 ui_test_utils::NavigateToURL(browser(), url); 453 454 NavigationEntry* entry = browser()->GetSelectedTabContents()-> 455 controller().GetActiveEntry(); 456 EXPECT_EQ(expected_favicon_url.spec(), entry->favicon().url().spec()); 457 } 458 459 // Test that an icon can be changed from JS. 460 IN_PROC_BROWSER_TEST_F(BrowserTest, FaviconChange) { 461 static const FilePath::CharType* kFile = 462 FILE_PATH_LITERAL("onload_change_favicon.html"); 463 GURL file_url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), 464 FilePath(kFile))); 465 ASSERT_TRUE(file_url.SchemeIs(chrome::kFileScheme)); 466 ui_test_utils::NavigateToURL(browser(), file_url); 467 468 NavigationEntry* entry = browser()->GetSelectedTabContents()-> 469 controller().GetActiveEntry(); 470 static const FilePath::CharType* kIcon = 471 FILE_PATH_LITERAL("test1.png"); 472 GURL expected_favicon_url( 473 ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), 474 FilePath(kIcon))); 475 EXPECT_EQ(expected_favicon_url.spec(), entry->favicon().url().spec()); 476 } 477 478 // Makes sure TabClosing is sent when uninstalling an extension that is an app 479 // tab. 480 IN_PROC_BROWSER_TEST_F(BrowserTest, TabClosingWhenRemovingExtension) { 481 ASSERT_TRUE(test_server()->Start()); 482 host_resolver()->AddRule("www.example.com", "127.0.0.1"); 483 GURL url(test_server()->GetURL("empty.html")); 484 TabStripModel* model = browser()->tabstrip_model(); 485 486 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/"))); 487 488 const Extension* extension_app = GetExtension(); 489 490 ui_test_utils::NavigateToURL(browser(), url); 491 492 TabContentsWrapper* app_contents = 493 Browser::TabContentsFactory(browser()->profile(), NULL, 494 MSG_ROUTING_NONE, NULL, NULL); 495 app_contents->extension_tab_helper()->SetExtensionApp(extension_app); 496 497 model->AddTabContents(app_contents, 0, 0, TabStripModel::ADD_NONE); 498 model->SetTabPinned(0, true); 499 ui_test_utils::NavigateToURL(browser(), url); 500 501 MockTabStripModelObserver observer; 502 model->AddObserver(&observer); 503 504 // Uninstall the extension and make sure TabClosing is sent. 505 ExtensionService* service = browser()->profile()->GetExtensionService(); 506 service->UninstallExtension(GetExtension()->id(), false, NULL); 507 EXPECT_EQ(1, observer.closing_count()); 508 509 model->RemoveObserver(&observer); 510 511 // There should only be one tab now. 512 ASSERT_EQ(1, browser()->tab_count()); 513 } 514 515 #if !defined(OS_MACOSX) 516 // Open with --app-id=<id>, and see that an app window opens. 517 IN_PROC_BROWSER_TEST_F(BrowserTest, AppIdSwitch) { 518 ASSERT_TRUE(test_server()->Start()); 519 520 // Load an app. 521 host_resolver()->AddRule("www.example.com", "127.0.0.1"); 522 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/"))); 523 const Extension* extension_app = GetExtension(); 524 525 CommandLine command_line(CommandLine::NO_PROGRAM); 526 command_line.AppendSwitchASCII(switches::kAppId, extension_app->id()); 527 528 BrowserInit::LaunchWithProfile launch(FilePath(), command_line); 529 ASSERT_TRUE(launch.OpenApplicationWindow(browser()->profile())); 530 531 // Check that the new browser has an app name. 532 // The launch should have created a new browser. 533 ASSERT_EQ(2u, BrowserList::GetBrowserCount(browser()->profile())); 534 535 // Find the new browser. 536 Browser* new_browser = NULL; 537 for (BrowserList::const_iterator i = BrowserList::begin(); 538 i != BrowserList::end() && !new_browser; ++i) { 539 if (*i != browser()) 540 new_browser = *i; 541 } 542 ASSERT_TRUE(new_browser); 543 ASSERT_TRUE(new_browser != browser()); 544 545 // The browser's app_name should include the app's ID. 546 ASSERT_NE( 547 new_browser->app_name_.find(extension_app->id()), 548 std::string::npos) << new_browser->app_name_; 549 550 } 551 #endif 552 553 #if defined(OS_WIN) 554 // http://crbug.com/46198. On XP/Vista, the failure rate is 5 ~ 6%. 555 #define MAYBE_PageLanguageDetection FLAKY_PageLanguageDetection 556 #else 557 #define MAYBE_PageLanguageDetection PageLanguageDetection 558 #endif 559 // Tests that the CLD (Compact Language Detection) works properly. 560 IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_PageLanguageDetection) { 561 ASSERT_TRUE(test_server()->Start()); 562 563 TabContents* current_tab = browser()->GetSelectedTabContents(); 564 TabContentsWrapper* wrapper = browser()->GetSelectedTabContentsWrapper(); 565 TranslateTabHelper* helper = wrapper->translate_tab_helper(); 566 Source<TabContents> source(current_tab); 567 568 // Navigate to a page in English. 569 ui_test_utils::WindowedNotificationObserverWithDetails<std::string> 570 en_language_detected_signal(NotificationType::TAB_LANGUAGE_DETERMINED, 571 source); 572 ui_test_utils::NavigateToURL( 573 browser(), GURL(test_server()->GetURL("files/english_page.html"))); 574 EXPECT_TRUE(helper->language_state().original_language().empty()); 575 en_language_detected_signal.Wait(); 576 std::string lang; 577 EXPECT_TRUE(en_language_detected_signal.GetDetailsFor( 578 source.map_key(), &lang)); 579 EXPECT_EQ("en", lang); 580 EXPECT_EQ("en", helper->language_state().original_language()); 581 582 // Now navigate to a page in French. 583 ui_test_utils::WindowedNotificationObserverWithDetails<std::string> 584 fr_language_detected_signal(NotificationType::TAB_LANGUAGE_DETERMINED, 585 source); 586 ui_test_utils::NavigateToURL( 587 browser(), GURL(test_server()->GetURL("files/french_page.html"))); 588 EXPECT_TRUE(helper->language_state().original_language().empty()); 589 fr_language_detected_signal.Wait(); 590 lang.clear(); 591 EXPECT_TRUE(fr_language_detected_signal.GetDetailsFor( 592 source.map_key(), &lang)); 593 EXPECT_EQ("fr", lang); 594 EXPECT_EQ("fr", helper->language_state().original_language()); 595 } 596 597 // Chromeos defaults to restoring the last session, so this test isn't 598 // applicable. 599 #if !defined(OS_CHROMEOS) 600 #if defined(OS_MACOSX) 601 // Crashy, http://crbug.com/38522 602 #define RestorePinnedTabs DISABLED_RestorePinnedTabs 603 #endif 604 // Makes sure pinned tabs are restored correctly on start. 605 IN_PROC_BROWSER_TEST_F(BrowserTest, RestorePinnedTabs) { 606 ASSERT_TRUE(test_server()->Start()); 607 608 // Add an pinned app tab. 609 host_resolver()->AddRule("www.example.com", "127.0.0.1"); 610 GURL url(test_server()->GetURL("empty.html")); 611 TabStripModel* model = browser()->tabstrip_model(); 612 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/"))); 613 const Extension* extension_app = GetExtension(); 614 ui_test_utils::NavigateToURL(browser(), url); 615 TabContentsWrapper* app_contents = 616 Browser::TabContentsFactory(browser()->profile(), NULL, 617 MSG_ROUTING_NONE, NULL, NULL); 618 app_contents->extension_tab_helper()->SetExtensionApp(extension_app); 619 model->AddTabContents(app_contents, 0, 0, TabStripModel::ADD_NONE); 620 model->SetTabPinned(0, true); 621 ui_test_utils::NavigateToURL(browser(), url); 622 623 // Add a non pinned tab. 624 browser()->NewTab(); 625 626 // Add a pinned non-app tab. 627 browser()->NewTab(); 628 ui_test_utils::NavigateToURL(browser(), GURL("about:blank")); 629 model->SetTabPinned(2, true); 630 631 // Write out the pinned tabs. 632 PinnedTabCodec::WritePinnedTabs(browser()->profile()); 633 634 // Simulate launching again. 635 CommandLine dummy(CommandLine::NO_PROGRAM); 636 BrowserInit::LaunchWithProfile launch(FilePath(), dummy); 637 launch.profile_ = browser()->profile(); 638 launch.ProcessStartupURLs(std::vector<GURL>()); 639 640 // The launch should have created a new browser. 641 ASSERT_EQ(2u, BrowserList::GetBrowserCount(browser()->profile())); 642 643 // Find the new browser. 644 Browser* new_browser = NULL; 645 for (BrowserList::const_iterator i = BrowserList::begin(); 646 i != BrowserList::end() && !new_browser; ++i) { 647 if (*i != browser()) 648 new_browser = *i; 649 } 650 ASSERT_TRUE(new_browser); 651 ASSERT_TRUE(new_browser != browser()); 652 653 // We should get back an additional tab for the app, and another for the 654 // default home page. 655 ASSERT_EQ(3, new_browser->tab_count()); 656 657 // Make sure the state matches. 658 TabStripModel* new_model = new_browser->tabstrip_model(); 659 EXPECT_TRUE(new_model->IsAppTab(0)); 660 EXPECT_FALSE(new_model->IsAppTab(1)); 661 EXPECT_FALSE(new_model->IsAppTab(2)); 662 663 EXPECT_TRUE(new_model->IsTabPinned(0)); 664 EXPECT_TRUE(new_model->IsTabPinned(1)); 665 EXPECT_FALSE(new_model->IsTabPinned(2)); 666 667 EXPECT_EQ(browser()->GetHomePage(), 668 new_model->GetTabContentsAt(2)->tab_contents()->GetURL()); 669 670 EXPECT_TRUE( 671 new_model->GetTabContentsAt(0)->extension_tab_helper()->extension_app() == 672 extension_app); 673 } 674 #endif // !defined(OS_CHROMEOS) 675 676 // This test verifies we don't crash when closing the last window and the app 677 // menu is showing. 678 IN_PROC_BROWSER_TEST_F(BrowserTest, CloseWithAppMenuOpen) { 679 if (browser_defaults::kBrowserAliveWithNoWindows) 680 return; 681 682 // We need a message loop running for menus on windows. 683 MessageLoop::current()->PostTask(FROM_HERE, 684 new RunCloseWithAppMenuTask(browser())); 685 } 686 687 #if !defined(OS_MACOSX) 688 IN_PROC_BROWSER_TEST_F(BrowserTest, OpenAppWindowLikeNtp) { 689 ASSERT_TRUE(test_server()->Start()); 690 691 // Load an app 692 host_resolver()->AddRule("www.example.com", "127.0.0.1"); 693 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/"))); 694 const Extension* extension_app = GetExtension(); 695 696 // Launch it in a window, as AppLauncherHandler::HandleLaunchApp() would. 697 TabContents* app_window = Browser::OpenApplication( 698 browser()->profile(), extension_app, extension_misc::LAUNCH_WINDOW, NULL); 699 ASSERT_TRUE(app_window); 700 701 // Apps launched in a window from the NTP do not have extension_app set in 702 // tab contents. 703 TabContentsWrapper* wrapper = 704 TabContentsWrapper::GetCurrentWrapperForContents(app_window); 705 EXPECT_FALSE(wrapper->extension_tab_helper()->extension_app()); 706 EXPECT_EQ(extension_app->GetFullLaunchURL(), app_window->GetURL()); 707 708 // The launch should have created a new browser. 709 ASSERT_EQ(2u, BrowserList::GetBrowserCount(browser()->profile())); 710 711 // Find the new browser. 712 Browser* new_browser = NULL; 713 for (BrowserList::const_iterator i = BrowserList::begin(); 714 i != BrowserList::end() && !new_browser; ++i) { 715 if (*i != browser()) 716 new_browser = *i; 717 } 718 ASSERT_TRUE(new_browser); 719 ASSERT_TRUE(new_browser != browser()); 720 721 EXPECT_EQ(Browser::TYPE_APP, new_browser->type()); 722 723 // The browser's app name should include the extension's id. 724 std::string app_name = new_browser->app_name_; 725 EXPECT_NE(app_name.find(extension_app->id()), std::string::npos) 726 << "Name " << app_name << " should contain id "<< extension_app->id(); 727 } 728 #endif // !defined(OS_MACOSX) 729 730 // TODO(ben): this test was never enabled. It has bit-rotted since being added. 731 // It originally lived in browser_unittest.cc, but has been moved here to make 732 // room for real browser unit tests. 733 #if 0 734 class BrowserTest2 : public InProcessBrowserTest { 735 public: 736 BrowserTest2() { 737 host_resolver_proc_ = new net::RuleBasedHostResolverProc(NULL); 738 // Avoid making external DNS lookups. In this test we don't need this 739 // to succeed. 740 host_resolver_proc_->AddSimulatedFailure("*.google.com"); 741 scoped_host_resolver_proc_.Init(host_resolver_proc_.get()); 742 } 743 744 private: 745 scoped_refptr<net::RuleBasedHostResolverProc> host_resolver_proc_; 746 net::ScopedDefaultHostResolverProc scoped_host_resolver_proc_; 747 }; 748 749 IN_PROC_BROWSER_TEST_F(BrowserTest2, NoTabsInPopups) { 750 Browser::RegisterAppPrefs(L"Test"); 751 752 // We start with a normal browser with one tab. 753 EXPECT_EQ(1, browser()->tab_count()); 754 755 // Open a popup browser with a single blank foreground tab. 756 Browser* popup_browser = browser()->CreateForType(Browser::TYPE_POPUP, 757 browser()->profile()); 758 popup_browser->AddBlankTab(true); 759 EXPECT_EQ(1, popup_browser->tab_count()); 760 761 // Now try opening another tab in the popup browser. 762 AddTabWithURLParams params1(url, PageTransition::TYPED); 763 popup_browser->AddTabWithURL(¶ms1); 764 EXPECT_EQ(popup_browser, params1.target); 765 766 // The popup should still only have one tab. 767 EXPECT_EQ(1, popup_browser->tab_count()); 768 769 // The normal browser should now have two. 770 EXPECT_EQ(2, browser()->tab_count()); 771 772 // Open an app frame browser with a single blank foreground tab. 773 Browser* app_browser = 774 browser()->CreateForApp(L"Test", browser()->profile(), false); 775 app_browser->AddBlankTab(true); 776 EXPECT_EQ(1, app_browser->tab_count()); 777 778 // Now try opening another tab in the app browser. 779 AddTabWithURLParams params2(GURL(chrome::kAboutBlankURL), 780 PageTransition::TYPED); 781 app_browser->AddTabWithURL(¶ms2); 782 EXPECT_EQ(app_browser, params2.target); 783 784 // The popup should still only have one tab. 785 EXPECT_EQ(1, app_browser->tab_count()); 786 787 // The normal browser should now have three. 788 EXPECT_EQ(3, browser()->tab_count()); 789 790 // Open an app frame popup browser with a single blank foreground tab. 791 Browser* app_popup_browser = 792 browser()->CreateForApp(L"Test", browser()->profile(), false); 793 app_popup_browser->AddBlankTab(true); 794 EXPECT_EQ(1, app_popup_browser->tab_count()); 795 796 // Now try opening another tab in the app popup browser. 797 AddTabWithURLParams params3(GURL(chrome::kAboutBlankURL), 798 PageTransition::TYPED); 799 app_popup_browser->AddTabWithURL(¶ms3); 800 EXPECT_EQ(app_popup_browser, params3.target); 801 802 // The popup should still only have one tab. 803 EXPECT_EQ(1, app_popup_browser->tab_count()); 804 805 // The normal browser should now have four. 806 EXPECT_EQ(4, browser()->tab_count()); 807 808 // Close the additional browsers. 809 popup_browser->CloseAllTabs(); 810 app_browser->CloseAllTabs(); 811 app_popup_browser->CloseAllTabs(); 812 } 813 #endif 814