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
23 namespace chromeos {
24
25 class TabCloseableStateWatcherTest : public InProcessBrowserTest {
26 public:
TabCloseableStateWatcherTest()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
AddTabWithURL(Browser * browser,const GURL & url)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
CanCloseTab(const Browser * browser)47 bool CanCloseTab(const Browser* browser) {
48 return browser->tabstrip_model()->delegate()->CanCloseTab();
49 }
50
51 // Create popup browser.
CreatePopupBrowser()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.
CreateIncognitoBrowser()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
NavigateToURL(const GURL & url)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.
NavigateToBeforeUnloadURL()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.
94 class NewTabObserver : public TabStripModelObserver {
95 public:
NewTabObserver(Browser * browser)96 explicit NewTabObserver(Browser* browser) : browser_(browser) {
97 browser_->tabstrip_model()->AddObserver(this);
98 ui_test_utils::RunMessageLoop();
99 }
~NewTabObserver()100 virtual ~NewTabObserver() {
101 browser_->tabstrip_model()->RemoveObserver(this);
102 }
103
104 private:
TabInsertedAt(TabContentsWrapper * contents,int index,bool foreground)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
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,OneNormalBrowserWithOneTab)118 IN_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
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,OneNormalBrowserWithTwoTabs)135 IN_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).
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,SecondNonNormalBrowser)165 IN_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.
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,CloseCloseableTab)183 IN_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.
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,CloseCloseableBrowser)193 IN_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.
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,CloseNonCloseableTabAndBrowser)205 IN_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.
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,SecondIncognitoBrowser)229 IN_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).
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,CloseIncognitoBrowser)250 IN_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
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,DISABLED_CloseBrowserWithBeforeUnloadHandlerCancel)278 IN_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.
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,CloseBrowserWithBeforeUnloadHandlerOK)305 IN_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