summaryrefslogtreecommitdiffstats
path: root/chrome/browser/chromeos/tab_closeable_state_watcher_browsertest.cc
blob: d09c4bd3c0699287581f0b074f2c4ea1fed66a09 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
// Copyright (c) 2011 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 "chrome/browser/chromeos/tab_closeable_state_watcher.h"

#include "base/file_path.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
#include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "googleurl/src/gurl.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace chromeos {

class TabCloseableStateWatcherTest : public InProcessBrowserTest {
 public:
  TabCloseableStateWatcherTest() {
    // This test is testing TabCloseStateWatcher, so enable it.
    EnableTabCloseableStateWatcher();
    blank_url_ = GURL(chrome::kAboutBlankURL);
    ntp_url_ = GURL(chrome::kChromeUINewTabURL);
    other_url_ = ui_test_utils::GetTestUrl(
        FilePath(FilePath::kCurrentDirectory),
        FilePath(FILE_PATH_LITERAL("title2.html")));
  }

 protected:
  // Wrapper for Browser::AddTabWithURL
  void AddTabWithURL(Browser* browser, const GURL& url) {
    AddTabAtIndexToBrowser(browser, 0, url, PageTransition::TYPED);
    // Wait for page to finish loading.
    ui_test_utils::WaitForNavigation(
        &browser->GetSelectedTabContents()->controller());
  }

  // Wrapper for TabCloseableStateWatcher::CanCloseTab
  bool CanCloseTab(const Browser* browser) {
    return browser->tabstrip_model()->delegate()->CanCloseTab();
  }

  // Create popup browser.
  Browser* CreatePopupBrowser() {
    // This is mostly duplicated from InPocessBrowserTest::CreateBrowser,
    // except that a popup browser is created here.
    Browser* popup_browser = Browser::CreateForType(Browser::TYPE_POPUP,
                                                    browser()->profile());
    AddTabWithURL(popup_browser, ntp_url_);
    popup_browser->window()->Show();
    return popup_browser;
  }

  // Create incognito browser.
  Browser* CreateIncognitoBrowser() {
    // This is mostly duplicated from InPocessBrowserTest::CreateBrowser,
    // except that an incognito browser is created here.
    Browser* incognito_browser =
        Browser::Create(browser()->profile()->GetOffTheRecordProfile());
    AddTabWithURL(incognito_browser, ntp_url_);
    incognito_browser->window()->Show();
    return incognito_browser;
  }

  void NavigateToURL(const GURL& url) {
    ui_test_utils::NavigateToURL(browser(), url);
    ui_test_utils::RunAllPendingInMessageLoop();
  }

  // Navigate to URL with BeforeUnload handler.
  void NavigateToBeforeUnloadURL() {
    const std::string kBeforeUnloadHtml =
        "<html><head><title>beforeunload</title></head><body>"
        "<script>window.onbeforeunload=function(e){return 'foo'}</script>"
        "</body></html>";
    NavigateToURL(GURL("data:text/html," + kBeforeUnloadHtml));
  }

  // Data members.
  GURL blank_url_;
  GURL ntp_url_;
  GURL other_url_;
};

// This is used to block until a new tab in the specified browser is inserted.
class NewTabObserver : public TabStripModelObserver {
 public:
  explicit NewTabObserver(Browser* browser) : browser_(browser) {
    browser_->tabstrip_model()->AddObserver(this);
    ui_test_utils::RunMessageLoop();
  }
  virtual ~NewTabObserver() {
    browser_->tabstrip_model()->RemoveObserver(this);
  }

 private:
  virtual void TabInsertedAt(TabContentsWrapper* contents,
                             int index,
                             bool foreground) {
    MessageLoopForUI::current()->Quit();
  }

  Browser* browser_;
};

// Tests with the only tab in the only normal browser:
// - if tab is about:blank, it is closeable
// - if tab is NewTabPage, it is not closeable
// - if tab is other url, it is closeable
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,
                       OneNormalBrowserWithOneTab) {
  // Check that default about::blank tab is closeable.
  ASSERT_EQ(1, browser()->tab_count());
  EXPECT_TRUE(CanCloseTab(browser()));

  // Naviate tab to NewTabPage, and check that it's not closeable.
  NavigateToURL(ntp_url_);
  EXPECT_FALSE(CanCloseTab(browser()));

  // Navigate tab to any other URL, and check that it's closeable.
  NavigateToURL(other_url_);
  EXPECT_TRUE(CanCloseTab(browser()));
}

// Tests with 2 tabs in the only normal browser
// - as long as there's > 1 tab, all tabs in the browser are always closeable
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,
                       OneNormalBrowserWithTwoTabs) {
  // 1 NewTabPage with any other tab are closeable.
  // First, set up the first NewTabPage.
  NavigateToURL(ntp_url_);
  EXPECT_FALSE(CanCloseTab(browser()));

  // Add the 2nd tab with blank page.
  AddTabWithURL(browser(), blank_url_);
  ASSERT_EQ(2, browser()->tab_count());
  EXPECT_TRUE(CanCloseTab(browser()));

  // Navigate 2nd tab to other URL.
  NavigateToURL(other_url_);
  EXPECT_TRUE(CanCloseTab(browser()));

  // Navigate 2nd tab to NewTabPage.
  NavigateToURL(ntp_url_);
  EXPECT_TRUE(CanCloseTab(browser()));

  // Close 1st NewTabPage.
  browser()->tabstrip_model()->CloseTabContentsAt(0,
      TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
  EXPECT_FALSE(CanCloseTab(browser()));
}

// Tests with one tab in one normal browser and another non-normal browser.
// - non-normal browser with any tab(s) is always closeable.
// - non-normal browser does not affect closeable state of tab(s) in normal
// browser(s).
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest, SecondNonNormalBrowser) {
  // Open non-normal browser.
  Browser* popup_browser = CreatePopupBrowser();
  EXPECT_TRUE(CanCloseTab(browser()));
  EXPECT_TRUE(CanCloseTab(popup_browser));

  // Navigate to NewTabPage for 1st browser.
  NavigateToURL(ntp_url_);
  EXPECT_FALSE(CanCloseTab(browser()));
  EXPECT_TRUE(CanCloseTab(popup_browser));

  // Close non-normal browser.
  popup_browser->CloseWindow();
  EXPECT_FALSE(CanCloseTab(browser()));
}

// Tests closing a closeable tab - tab should be closed, browser should remain
// opened with a NewTabPage.
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest, CloseCloseableTab) {
  EXPECT_EQ(1, browser()->tab_count());
  EXPECT_TRUE(CanCloseTab(browser()));
  browser()->CloseTab();
  EXPECT_EQ(1, browser()->tab_count());
  EXPECT_EQ(ntp_url_, browser()->GetSelectedTabContents()->GetURL());
}

// Tests closing a closeable browser - all tabs in browser should be closed,
// browser should remain opened with a NewTabPage.
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest, CloseCloseableBrowser) {
  EXPECT_EQ(1, browser()->tab_count());
  EXPECT_TRUE(CanCloseTab(browser()));
  browser()->CloseWindow();
  EXPECT_EQ(1u, BrowserList::size());
  EXPECT_EQ(browser(), *(BrowserList::begin()));
  EXPECT_EQ(1, browser()->tab_count());
  EXPECT_EQ(ntp_url_, browser()->GetSelectedTabContents()->GetURL());
}

// Tests closing a non-closeable tab and hence non-closeable browser - tab and
// browser should remain opened.
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,
                       CloseNonCloseableTabAndBrowser) {
  // Close non-closeable tab.
  EXPECT_EQ(1, browser()->tab_count());
  NavigateToURL(ntp_url_);
  EXPECT_FALSE(CanCloseTab(browser()));
  TabContents* tab_contents = browser()->GetSelectedTabContents();
  browser()->CloseTab();
  EXPECT_EQ(1, browser()->tab_count());
  EXPECT_EQ(tab_contents, browser()->GetSelectedTabContents());

  // Close browser with non-closeable tab.
  browser()->CloseWindow();
  EXPECT_EQ(1u, BrowserList::size());
  EXPECT_EQ(browser(), *(BrowserList::begin()));
  EXPECT_EQ(1, browser()->tab_count());
  EXPECT_EQ(tab_contents, browser()->GetSelectedTabContents());
}

// Tests an incognito browsr with a normal browser.
// - when incognito browser is opened, all browsers (including previously
//   non-clsoeable normal browsers) become closeable.
// - when incognito browser is closed, normal browsers return to adhering to the
//   original closebable rules.
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest, SecondIncognitoBrowser) {
  NavigateToURL(ntp_url_);
  EXPECT_FALSE(CanCloseTab(browser()));

  // Open an incognito browser.
  Browser* incognito_browser = CreateIncognitoBrowser();
  EXPECT_TRUE(incognito_browser->profile()->IsOffTheRecord());
  EXPECT_EQ(2u, BrowserList::size());
  EXPECT_TRUE(CanCloseTab(browser()));
  EXPECT_TRUE(CanCloseTab(incognito_browser));

  // Close incognito browser.
  incognito_browser->CloseWindow();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_EQ(1u, BrowserList::size());
  EXPECT_EQ(browser(), *(BrowserList::begin()));
  EXPECT_FALSE(CanCloseTab(browser()));
}

// Tests closing an incognito browser - the incognito browser should close,
// and a new normal browser opened with a NewTabPage (which is not closeable).
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest, CloseIncognitoBrowser) {
  NavigateToURL(ntp_url_);

  // Open an incognito browser.
  Browser* incognito_browser = CreateIncognitoBrowser();
  EXPECT_TRUE(incognito_browser->profile()->IsOffTheRecord());
  EXPECT_EQ(2u, BrowserList::size());

  // Close 1st normal browser.
  browser()->CloseWindow();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_EQ(1u, BrowserList::size());
  EXPECT_EQ(incognito_browser, *(BrowserList::begin()));
  EXPECT_TRUE(CanCloseTab(incognito_browser));

  // Close incognito browser.
  incognito_browser->CloseWindow();
  Browser* new_browser = ui_test_utils::WaitForNewBrowser();
  EXPECT_EQ(1u, BrowserList::size());
  EXPECT_FALSE(new_browser->profile()->IsOffTheRecord());
  EXPECT_EQ(1, new_browser->tab_count());
  EXPECT_EQ(ntp_url_, new_browser->GetSelectedTabContents()->GetURL());
}

// Tests closing of browser with BeforeUnload handler where user clicks cancel
// (i.e. stay on the page and cancel closing) - browser and its tabs should stay
// the same.
// Sporadically crashing test. See http://crbug.com/79333
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,
                       DISABLED_CloseBrowserWithBeforeUnloadHandlerCancel) {
  // Navigate to URL with BeforeUnload handler.
  NavigateToBeforeUnloadURL();
  EXPECT_TRUE(CanCloseTab(browser()));

  // Close browser, click Cancel in BeforeUnload confirm dialog.
  TabContents* tab_contents = browser()->GetSelectedTabContents();
  browser()->CloseWindow();
  AppModalDialog* confirm = ui_test_utils::WaitForAppModalDialog();
  confirm->native_dialog()->CancelAppModalDialog();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_EQ(1u, BrowserList::size());
  EXPECT_EQ(browser(), *(BrowserList::begin()));
  EXPECT_EQ(1, browser()->tab_count());
  EXPECT_EQ(tab_contents, browser()->GetSelectedTabContents());

  // Close the browser.
  browser()->CloseWindow();
  confirm = ui_test_utils::WaitForAppModalDialog();
  confirm->native_dialog()->AcceptAppModalDialog();
  ui_test_utils::RunAllPendingInMessageLoop();
}

// Tests closing of browser with BeforeUnload handler where user clicks OK (i.e.
// leave the page and proceed with closing), all tabs in browser should close,
// browser remains opened with a NewTabPage.
IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,
                       CloseBrowserWithBeforeUnloadHandlerOK) {
  // Navigate to URL with BeforeUnload handler.
  NavigateToBeforeUnloadURL();
  EXPECT_TRUE(CanCloseTab(browser()));

  // Close browser, click OK in BeforeUnload confirm dialog.
  browser()->CloseWindow();
  AppModalDialog* confirm = ui_test_utils::WaitForAppModalDialog();
  confirm->native_dialog()->AcceptAppModalDialog();
  NewTabObserver new_tab_observer(browser());
  EXPECT_EQ(1u, BrowserList::size());
  EXPECT_EQ(browser(), *(BrowserList::begin()));
  EXPECT_EQ(1, browser()->tab_count());
  EXPECT_EQ(ntp_url_, browser()->GetSelectedTabContents()->GetURL());
}

}  // namespace chromeos