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 "chrome/browser/chromeos/tab_closeable_state_watcher.h"
6
7#include "base/file_path.h"
8#include "chrome/browser/profiles/profile.h"
9#include "chrome/browser/tabs/tab_strip_model.h"
10#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
11#include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
12#include "chrome/browser/ui/browser.h"
13#include "chrome/browser/ui/browser_list.h"
14#include "chrome/browser/ui/browser_window.h"
15#include "chrome/common/url_constants.h"
16#include "chrome/test/in_process_browser_test.h"
17#include "chrome/test/ui_test_utils.h"
18#include "content/browser/tab_contents/tab_contents.h"
19#include "googleurl/src/gurl.h"
20#include "testing/gmock/include/gmock/gmock.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23namespace chromeos {
24
25class TabCloseableStateWatcherTest : public InProcessBrowserTest {
26 public:
27  TabCloseableStateWatcherTest() {
28    // This test is testing TabCloseStateWatcher, so enable it.
29    EnableTabCloseableStateWatcher();
30    blank_url_ = GURL(chrome::kAboutBlankURL);
31    ntp_url_ = GURL(chrome::kChromeUINewTabURL);
32    other_url_ = ui_test_utils::GetTestUrl(
33        FilePath(FilePath::kCurrentDirectory),
34        FilePath(FILE_PATH_LITERAL("title2.html")));
35  }
36
37 protected:
38  // Wrapper for Browser::AddTabWithURL
39  void AddTabWithURL(Browser* browser, const GURL& url) {
40    AddTabAtIndexToBrowser(browser, 0, url, PageTransition::TYPED);
41    // Wait for page to finish loading.
42    ui_test_utils::WaitForNavigation(
43        &browser->GetSelectedTabContents()->controller());
44  }
45
46  // Wrapper for TabCloseableStateWatcher::CanCloseTab
47  bool CanCloseTab(const Browser* browser) {
48    return browser->tabstrip_model()->delegate()->CanCloseTab();
49  }
50
51  // Create popup browser.
52  Browser* CreatePopupBrowser() {
53    // This is mostly duplicated from InPocessBrowserTest::CreateBrowser,
54    // except that a popup browser is created here.
55    Browser* popup_browser = Browser::CreateForType(Browser::TYPE_POPUP,
56                                                    browser()->profile());
57    AddTabWithURL(popup_browser, ntp_url_);
58    popup_browser->window()->Show();
59    return popup_browser;
60  }
61
62  // Create incognito browser.
63  Browser* CreateIncognitoBrowser() {
64    // This is mostly duplicated from InPocessBrowserTest::CreateBrowser,
65    // except that an incognito browser is created here.
66    Browser* incognito_browser =
67        Browser::Create(browser()->profile()->GetOffTheRecordProfile());
68    AddTabWithURL(incognito_browser, ntp_url_);
69    incognito_browser->window()->Show();
70    return incognito_browser;
71  }
72
73  void NavigateToURL(const GURL& url) {
74    ui_test_utils::NavigateToURL(browser(), url);
75    ui_test_utils::RunAllPendingInMessageLoop();
76  }
77
78  // Navigate to URL with BeforeUnload handler.
79  void NavigateToBeforeUnloadURL() {
80    const std::string kBeforeUnloadHtml =
81        "<html><head><title>beforeunload</title></head><body>"
82        "<script>window.onbeforeunload=function(e){return 'foo'}</script>"
83        "</body></html>";
84    NavigateToURL(GURL("data:text/html," + kBeforeUnloadHtml));
85  }
86
87  // Data members.
88  GURL blank_url_;
89  GURL ntp_url_;
90  GURL other_url_;
91};
92
93// This is used to block until a new tab in the specified browser is inserted.
94class NewTabObserver : public TabStripModelObserver {
95 public:
96  explicit NewTabObserver(Browser* browser) : browser_(browser) {
97    browser_->tabstrip_model()->AddObserver(this);
98    ui_test_utils::RunMessageLoop();
99  }
100  virtual ~NewTabObserver() {
101    browser_->tabstrip_model()->RemoveObserver(this);
102  }
103
104 private:
105  virtual void TabInsertedAt(TabContentsWrapper* contents,
106                             int index,
107                             bool foreground) {
108    MessageLoopForUI::current()->Quit();
109  }
110
111  Browser* browser_;
112};
113
114// Tests with the only tab in the only normal browser:
115// - if tab is about:blank, it is closeable
116// - if tab is NewTabPage, it is not closeable
117// - if tab is other url, it is closeable
118IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,
119                       OneNormalBrowserWithOneTab) {
120  // Check that default about::blank tab is closeable.
121  ASSERT_EQ(1, browser()->tab_count());
122  EXPECT_TRUE(CanCloseTab(browser()));
123
124  // Naviate tab to NewTabPage, and check that it's not closeable.
125  NavigateToURL(ntp_url_);
126  EXPECT_FALSE(CanCloseTab(browser()));
127
128  // Navigate tab to any other URL, and check that it's closeable.
129  NavigateToURL(other_url_);
130  EXPECT_TRUE(CanCloseTab(browser()));
131}
132
133// Tests with 2 tabs in the only normal browser
134// - as long as there's > 1 tab, all tabs in the browser are always closeable
135IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,
136                       OneNormalBrowserWithTwoTabs) {
137  // 1 NewTabPage with any other tab are closeable.
138  // First, set up the first NewTabPage.
139  NavigateToURL(ntp_url_);
140  EXPECT_FALSE(CanCloseTab(browser()));
141
142  // Add the 2nd tab with blank page.
143  AddTabWithURL(browser(), blank_url_);
144  ASSERT_EQ(2, browser()->tab_count());
145  EXPECT_TRUE(CanCloseTab(browser()));
146
147  // Navigate 2nd tab to other URL.
148  NavigateToURL(other_url_);
149  EXPECT_TRUE(CanCloseTab(browser()));
150
151  // Navigate 2nd tab to NewTabPage.
152  NavigateToURL(ntp_url_);
153  EXPECT_TRUE(CanCloseTab(browser()));
154
155  // Close 1st NewTabPage.
156  browser()->tabstrip_model()->CloseTabContentsAt(0,
157      TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
158  EXPECT_FALSE(CanCloseTab(browser()));
159}
160
161// Tests with one tab in one normal browser and another non-normal browser.
162// - non-normal browser with any tab(s) is always closeable.
163// - non-normal browser does not affect closeable state of tab(s) in normal
164// browser(s).
165IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest, SecondNonNormalBrowser) {
166  // Open non-normal browser.
167  Browser* popup_browser = CreatePopupBrowser();
168  EXPECT_TRUE(CanCloseTab(browser()));
169  EXPECT_TRUE(CanCloseTab(popup_browser));
170
171  // Navigate to NewTabPage for 1st browser.
172  NavigateToURL(ntp_url_);
173  EXPECT_FALSE(CanCloseTab(browser()));
174  EXPECT_TRUE(CanCloseTab(popup_browser));
175
176  // Close non-normal browser.
177  popup_browser->CloseWindow();
178  EXPECT_FALSE(CanCloseTab(browser()));
179}
180
181// Tests closing a closeable tab - tab should be closed, browser should remain
182// opened with a NewTabPage.
183IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest, CloseCloseableTab) {
184  EXPECT_EQ(1, browser()->tab_count());
185  EXPECT_TRUE(CanCloseTab(browser()));
186  browser()->CloseTab();
187  EXPECT_EQ(1, browser()->tab_count());
188  EXPECT_EQ(ntp_url_, browser()->GetSelectedTabContents()->GetURL());
189}
190
191// Tests closing a closeable browser - all tabs in browser should be closed,
192// browser should remain opened with a NewTabPage.
193IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest, CloseCloseableBrowser) {
194  EXPECT_EQ(1, browser()->tab_count());
195  EXPECT_TRUE(CanCloseTab(browser()));
196  browser()->CloseWindow();
197  EXPECT_EQ(1u, BrowserList::size());
198  EXPECT_EQ(browser(), *(BrowserList::begin()));
199  EXPECT_EQ(1, browser()->tab_count());
200  EXPECT_EQ(ntp_url_, browser()->GetSelectedTabContents()->GetURL());
201}
202
203// Tests closing a non-closeable tab and hence non-closeable browser - tab and
204// browser should remain opened.
205IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,
206                       CloseNonCloseableTabAndBrowser) {
207  // Close non-closeable tab.
208  EXPECT_EQ(1, browser()->tab_count());
209  NavigateToURL(ntp_url_);
210  EXPECT_FALSE(CanCloseTab(browser()));
211  TabContents* tab_contents = browser()->GetSelectedTabContents();
212  browser()->CloseTab();
213  EXPECT_EQ(1, browser()->tab_count());
214  EXPECT_EQ(tab_contents, browser()->GetSelectedTabContents());
215
216  // Close browser with non-closeable tab.
217  browser()->CloseWindow();
218  EXPECT_EQ(1u, BrowserList::size());
219  EXPECT_EQ(browser(), *(BrowserList::begin()));
220  EXPECT_EQ(1, browser()->tab_count());
221  EXPECT_EQ(tab_contents, browser()->GetSelectedTabContents());
222}
223
224// Tests an incognito browsr with a normal browser.
225// - when incognito browser is opened, all browsers (including previously
226//   non-clsoeable normal browsers) become closeable.
227// - when incognito browser is closed, normal browsers return to adhering to the
228//   original closebable rules.
229IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest, SecondIncognitoBrowser) {
230  NavigateToURL(ntp_url_);
231  EXPECT_FALSE(CanCloseTab(browser()));
232
233  // Open an incognito browser.
234  Browser* incognito_browser = CreateIncognitoBrowser();
235  EXPECT_TRUE(incognito_browser->profile()->IsOffTheRecord());
236  EXPECT_EQ(2u, BrowserList::size());
237  EXPECT_TRUE(CanCloseTab(browser()));
238  EXPECT_TRUE(CanCloseTab(incognito_browser));
239
240  // Close incognito browser.
241  incognito_browser->CloseWindow();
242  ui_test_utils::RunAllPendingInMessageLoop();
243  EXPECT_EQ(1u, BrowserList::size());
244  EXPECT_EQ(browser(), *(BrowserList::begin()));
245  EXPECT_FALSE(CanCloseTab(browser()));
246}
247
248// Tests closing an incognito browser - the incognito browser should close,
249// and a new normal browser opened with a NewTabPage (which is not closeable).
250IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest, CloseIncognitoBrowser) {
251  NavigateToURL(ntp_url_);
252
253  // Open an incognito browser.
254  Browser* incognito_browser = CreateIncognitoBrowser();
255  EXPECT_TRUE(incognito_browser->profile()->IsOffTheRecord());
256  EXPECT_EQ(2u, BrowserList::size());
257
258  // Close 1st normal browser.
259  browser()->CloseWindow();
260  ui_test_utils::RunAllPendingInMessageLoop();
261  EXPECT_EQ(1u, BrowserList::size());
262  EXPECT_EQ(incognito_browser, *(BrowserList::begin()));
263  EXPECT_TRUE(CanCloseTab(incognito_browser));
264
265  // Close incognito browser.
266  incognito_browser->CloseWindow();
267  Browser* new_browser = ui_test_utils::WaitForNewBrowser();
268  EXPECT_EQ(1u, BrowserList::size());
269  EXPECT_FALSE(new_browser->profile()->IsOffTheRecord());
270  EXPECT_EQ(1, new_browser->tab_count());
271  EXPECT_EQ(ntp_url_, new_browser->GetSelectedTabContents()->GetURL());
272}
273
274// Tests closing of browser with BeforeUnload handler where user clicks cancel
275// (i.e. stay on the page and cancel closing) - browser and its tabs should stay
276// the same.
277// Sporadically crashing test. See http://crbug.com/79333
278IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,
279                       DISABLED_CloseBrowserWithBeforeUnloadHandlerCancel) {
280  // Navigate to URL with BeforeUnload handler.
281  NavigateToBeforeUnloadURL();
282  EXPECT_TRUE(CanCloseTab(browser()));
283
284  // Close browser, click Cancel in BeforeUnload confirm dialog.
285  TabContents* tab_contents = browser()->GetSelectedTabContents();
286  browser()->CloseWindow();
287  AppModalDialog* confirm = ui_test_utils::WaitForAppModalDialog();
288  confirm->native_dialog()->CancelAppModalDialog();
289  ui_test_utils::RunAllPendingInMessageLoop();
290  EXPECT_EQ(1u, BrowserList::size());
291  EXPECT_EQ(browser(), *(BrowserList::begin()));
292  EXPECT_EQ(1, browser()->tab_count());
293  EXPECT_EQ(tab_contents, browser()->GetSelectedTabContents());
294
295  // Close the browser.
296  browser()->CloseWindow();
297  confirm = ui_test_utils::WaitForAppModalDialog();
298  confirm->native_dialog()->AcceptAppModalDialog();
299  ui_test_utils::RunAllPendingInMessageLoop();
300}
301
302// Tests closing of browser with BeforeUnload handler where user clicks OK (i.e.
303// leave the page and proceed with closing), all tabs in browser should close,
304// browser remains opened with a NewTabPage.
305IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,
306                       CloseBrowserWithBeforeUnloadHandlerOK) {
307  // Navigate to URL with BeforeUnload handler.
308  NavigateToBeforeUnloadURL();
309  EXPECT_TRUE(CanCloseTab(browser()));
310
311  // Close browser, click OK in BeforeUnload confirm dialog.
312  browser()->CloseWindow();
313  AppModalDialog* confirm = ui_test_utils::WaitForAppModalDialog();
314  confirm->native_dialog()->AcceptAppModalDialog();
315  NewTabObserver new_tab_observer(browser());
316  EXPECT_EQ(1u, BrowserList::size());
317  EXPECT_EQ(browser(), *(BrowserList::begin()));
318  EXPECT_EQ(1, browser()->tab_count());
319  EXPECT_EQ(ntp_url_, browser()->GetSelectedTabContents()->GetURL());
320}
321
322}  // namespace chromeos
323