// 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