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