Index: chrome/browser/lifetime/browser_close_manager_browsertest.cc |
diff --git a/chrome/browser/lifetime/browser_close_manager_browsertest.cc b/chrome/browser/lifetime/browser_close_manager_browsertest.cc |
index 5016975f28aac66cc2100356702899f7b700315f..2e18057cb8eb55aebf01388a4dca0ec766cdea0f 100644 |
--- a/chrome/browser/lifetime/browser_close_manager_browsertest.cc |
+++ b/chrome/browser/lifetime/browser_close_manager_browsertest.cc |
@@ -27,6 +27,7 @@ |
#include "chrome/browser/prefs/session_startup_pref.h" |
#include "chrome/browser/profiles/profile.h" |
#include "chrome/browser/profiles/profile_manager.h" |
+#include "chrome/browser/sessions/tab_restore_service_factory.h" |
#include "chrome/browser/ui/browser.h" |
#include "chrome/browser/ui/browser_commands.h" |
#include "chrome/browser/ui/browser_list.h" |
@@ -38,6 +39,8 @@ |
#include "chrome/test/base/ui_test_utils.h" |
#include "components/app_modal/javascript_app_modal_dialog.h" |
#include "components/app_modal/native_app_modal_dialog.h" |
+#include "components/sessions/core/tab_restore_service.h" |
+#include "components/sessions/core/tab_restore_service_observer.h" |
#include "content/public/browser/browser_context.h" |
#include "content/public/browser/download_item.h" |
#include "content/public/browser/download_manager.h" |
@@ -45,6 +48,7 @@ |
#include "content/public/browser/render_view_host.h" |
#include "content/public/browser/render_widget_host.h" |
#include "content/public/browser/web_contents.h" |
+#include "content/public/test/browser_test_utils.h" |
#include "content/public/test/download_test_observer.h" |
#include "content/public/test/test_navigation_observer.h" |
#include "net/test/embedded_test_server/embedded_test_server.h" |
@@ -113,6 +117,39 @@ class RepeatedNotificationObserver : public content::NotificationObserver { |
DISALLOW_COPY_AND_ASSIGN(RepeatedNotificationObserver); |
}; |
+class TabRestoreServiceChangesObserver |
+ : public sessions::TabRestoreServiceObserver { |
+ public: |
+ explicit TabRestoreServiceChangesObserver(Profile* profile) |
+ : service_(TabRestoreServiceFactory::GetForProfile(profile)) { |
+ if (service_) |
+ service_->AddObserver(this); |
+ } |
+ |
+ ~TabRestoreServiceChangesObserver() override { |
+ if (service_) |
+ service_->RemoveObserver(this); |
+ } |
+ |
+ size_t changes_count() const { return changes_count_; } |
+ |
+ private: |
+ // sessions::TabRestoreServiceObserver: |
+ void TabRestoreServiceChanged(sessions::TabRestoreService*) override { |
+ changes_count_++; |
+ } |
+ |
+ // sessions::TabRestoreServiceObserver: |
+ void TabRestoreServiceDestroyed(sessions::TabRestoreService*) override { |
+ service_ = nullptr; |
+ } |
+ |
+ sessions::TabRestoreService* service_ = nullptr; |
+ size_t changes_count_ = 0; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TabRestoreServiceChangesObserver); |
+}; |
+ |
class TestBrowserCloseManager : public BrowserCloseManager { |
public: |
enum UserChoice { |
@@ -708,6 +745,103 @@ IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest, |
} |
IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest, |
+ AddBeforeUnloadDuringClosing) { |
+ // TODO(crbug.com/250305): Currently FastUnloadController is broken. |
+ // And it is difficult to fix this issue without fixing that one. |
+ if (GetParam()) |
+ return; |
+ |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |
+ browser(), embedded_test_server()->GetURL("/title1.html"))); |
+ |
+ // Open second window. |
+ ui_test_utils::NavigateToURLWithDisposition( |
+ browser(), embedded_test_server()->GetURL("/beforeunload.html"), |
+ WindowOpenDisposition::NEW_WINDOW, |
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER); |
+ EXPECT_EQ(2u, BrowserList::GetInstance()->size()); |
+ auto* browser2 = BrowserList::GetInstance()->get(0) != browser() |
+ ? BrowserList::GetInstance()->get(0) |
+ : BrowserList::GetInstance()->get(1); |
+ content::WaitForLoadStop(browser2->tab_strip_model()->GetWebContentsAt(0)); |
+ |
+ // Let's work with second window only. |
+ // This page has beforeunload handler already. |
+ EXPECT_TRUE(browser2->tab_strip_model() |
+ ->GetWebContentsAt(0) |
+ ->NeedToFireBeforeUnload()); |
+ // This page doesn't have beforeunload handler. Yet. |
+ ui_test_utils::NavigateToURLWithDisposition( |
+ browser2, embedded_test_server()->GetURL("/title2.html"), |
+ WindowOpenDisposition::NEW_FOREGROUND_TAB, |
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); |
+ content::WaitForLoadStop(browser2->tab_strip_model()->GetWebContentsAt(1)); |
+ EXPECT_FALSE(browser2->tab_strip_model() |
+ ->GetWebContentsAt(1) |
+ ->NeedToFireBeforeUnload()); |
+ EXPECT_EQ(2, browser2->tab_strip_model()->count()); |
+ |
+ DisableHangMonitor(browser2); |
+ |
+ // The test. |
+ |
+ TabRestoreServiceChangesObserver restore_observer(browser2->profile()); |
+ content::WindowedNotificationObserver observer( |
+ chrome::NOTIFICATION_BROWSER_CLOSED, |
+ content::NotificationService::AllSources()); |
+ chrome::CloseWindow(browser2); |
+ // Just to be sure CloseWindow doesn't have asynchronous tasks |
+ // that could have an impact. |
+ content::RunAllPendingInMessageLoop(); |
+ |
+ // Closing browser shouldn't happen because of beforeunload handler. |
+ EXPECT_EQ(2u, BrowserList::GetInstance()->size()); |
+ // Add beforeunload handler for the 2nd (title2.html) tab which haven't had it |
+ // yet. |
+ ASSERT_TRUE(content::ExecuteScript( |
+ browser2->tab_strip_model()->GetWebContentsAt(1)->GetRenderViewHost(), |
+ "window.addEventListener('beforeunload', " |
+ "function(event) { event.returnValue = 'Foo'; });")); |
+ EXPECT_TRUE(browser2->tab_strip_model() |
+ ->GetWebContentsAt(1) |
+ ->NeedToFireBeforeUnload()); |
+ // Accept closing the first tab. |
+ ASSERT_NO_FATAL_FAILURE(AcceptClose()); |
+ // Just to be sure accepting a dialog doesn't have asynchronous tasks |
+ // that could have an impact. |
+ content::RunAllPendingInMessageLoop(); |
+ // It shouldn't close the whole window/browser. |
+ EXPECT_EQ(2u, BrowserList::GetInstance()->size()); |
+ EXPECT_EQ(2, browser2->tab_strip_model()->count()); |
+ // Accept closing the second tab. |
+ ASSERT_NO_FATAL_FAILURE(AcceptClose()); |
+ observer.Wait(); |
+ // Now the second window/browser should be closed. |
+ EXPECT_EQ(1u, BrowserList::GetInstance()->size()); |
+ EXPECT_EQ(browser(), BrowserList::GetInstance()->get(0)); |
+ EXPECT_EQ(1u, restore_observer.changes_count()); |
+ |
+ // Restore the closed browser. |
+ content::WindowedNotificationObserver open_window_observer( |
+ chrome::NOTIFICATION_BROWSER_OPENED, |
+ content::NotificationService::AllSources()); |
+ chrome::OpenWindowWithRestoredTabs(browser()->profile()); |
+ open_window_observer.Wait(); |
+ EXPECT_EQ(2u, BrowserList::GetInstance()->size()); |
+ browser2 = BrowserList::GetInstance()->get(0) != browser() |
+ ? BrowserList::GetInstance()->get(0) |
+ : BrowserList::GetInstance()->get(1); |
+ |
+ // Check the restored browser contents. |
+ EXPECT_EQ(2, browser2->tab_strip_model()->count()); |
+ EXPECT_EQ(embedded_test_server()->GetURL("/beforeunload.html"), |
+ browser2->tab_strip_model()->GetWebContentsAt(0)->GetURL()); |
+ EXPECT_EQ(embedded_test_server()->GetURL("/title2.html"), |
+ browser2->tab_strip_model()->GetWebContentsAt(1)->GetURL()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest, |
TestCloseTabDuringShutdown) { |
ASSERT_TRUE(embedded_test_server()->Start()); |
ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( |