// Copyright 2013 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/ui/views/frame/browser_view.h" #include "base/macros.h" #include "chrome/browser/devtools/devtools_window_testing.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h" #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view_observer.h" #include "chrome/common/url_constants.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/bookmarks/common/bookmark_pref_names.h" #include "components/prefs/pref_service.h" #include "content/public/browser/invalidate_type.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" class BrowserViewTest : public InProcessBrowserTest { public: BrowserViewTest() : InProcessBrowserTest(), devtools_(nullptr) {} protected: BrowserView* browser_view() { return BrowserView::GetBrowserViewForBrowser(browser()); } views::WebView* devtools_web_view() { return browser_view()->GetDevToolsWebViewForTest(); } views::WebView* contents_web_view() { return browser_view()->GetContentsWebViewForTest(); } void OpenDevToolsWindow(bool docked) { devtools_ = DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), docked); } void CloseDevToolsWindow() { DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_); } void SetDevToolsBounds(const gfx::Rect& bounds) { DevToolsWindowTesting::Get(devtools_)->SetInspectedPageBounds(bounds); } DevToolsWindow* devtools_; private: DISALLOW_COPY_AND_ASSIGN(BrowserViewTest); }; namespace { // Used to simulate scenario in a crash. When WebContentsDestroyed() is invoked // updates the navigation state of another tab. class TestWebContentsObserver : public content::WebContentsObserver { public: TestWebContentsObserver(content::WebContents* source, content::WebContents* other) : content::WebContentsObserver(source), other_(other) {} ~TestWebContentsObserver() override {} void WebContentsDestroyed() override { other_->NotifyNavigationStateChanged(static_cast( content::INVALIDATE_TYPE_URL | content::INVALIDATE_TYPE_LOAD)); } private: content::WebContents* other_; DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver); }; } // namespace // Verifies don't crash when CloseNow() is invoked with two tabs in a browser. // Additionally when one of the tabs is destroyed NotifyNavigationStateChanged() // is invoked on the other. IN_PROC_BROWSER_TEST_F(BrowserViewTest, CloseWithTabs) { Browser* browser2 = new Browser(Browser::CreateParams(browser()->profile())); chrome::AddTabAt(browser2, GURL(), -1, true); chrome::AddTabAt(browser2, GURL(), -1, true); TestWebContentsObserver observer( browser2->tab_strip_model()->GetWebContentsAt(0), browser2->tab_strip_model()->GetWebContentsAt(1)); BrowserView::GetBrowserViewForBrowser(browser2)->GetWidget()->CloseNow(); } // Same as CloseWithTabs, but activates the first tab, which is the first tab // BrowserView will destroy. IN_PROC_BROWSER_TEST_F(BrowserViewTest, CloseWithTabsStartWithActive) { Browser* browser2 = new Browser(Browser::CreateParams(browser()->profile())); chrome::AddTabAt(browser2, GURL(), -1, true); chrome::AddTabAt(browser2, GURL(), -1, true); browser2->tab_strip_model()->ActivateTabAt(0, true); TestWebContentsObserver observer( browser2->tab_strip_model()->GetWebContentsAt(0), browser2->tab_strip_model()->GetWebContentsAt(1)); BrowserView::GetBrowserViewForBrowser(browser2)->GetWidget()->CloseNow(); } // Verifies that page and devtools WebViews are being correctly layed out // when DevTools is opened/closed/updated/undocked. IN_PROC_BROWSER_TEST_F(BrowserViewTest, DevToolsUpdatesBrowserWindow) { gfx::Rect full_bounds = browser_view()->GetContentsContainerForTest()->GetLocalBounds(); gfx::Rect small_bounds(10, 20, 30, 40); browser_view()->UpdateDevTools(); EXPECT_FALSE(devtools_web_view()->web_contents()); EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); EXPECT_EQ(full_bounds, contents_web_view()->bounds()); // Docked. OpenDevToolsWindow(true); EXPECT_TRUE(devtools_web_view()->web_contents()); EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); SetDevToolsBounds(small_bounds); EXPECT_TRUE(devtools_web_view()->web_contents()); EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); EXPECT_EQ(small_bounds, contents_web_view()->bounds()); browser_view()->UpdateDevTools(); EXPECT_TRUE(devtools_web_view()->web_contents()); EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); EXPECT_EQ(small_bounds, contents_web_view()->bounds()); CloseDevToolsWindow(); EXPECT_FALSE(devtools_web_view()->web_contents()); EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); EXPECT_EQ(full_bounds, contents_web_view()->bounds()); browser_view()->UpdateDevTools(); EXPECT_FALSE(devtools_web_view()->web_contents()); EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); EXPECT_EQ(full_bounds, contents_web_view()->bounds()); // Undocked. OpenDevToolsWindow(false); EXPECT_TRUE(devtools_web_view()->web_contents()); EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); SetDevToolsBounds(small_bounds); EXPECT_TRUE(devtools_web_view()->web_contents()); EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); EXPECT_EQ(small_bounds, contents_web_view()->bounds()); browser_view()->UpdateDevTools(); EXPECT_TRUE(devtools_web_view()->web_contents()); EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); EXPECT_EQ(small_bounds, contents_web_view()->bounds()); CloseDevToolsWindow(); EXPECT_FALSE(devtools_web_view()->web_contents()); EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); EXPECT_EQ(full_bounds, contents_web_view()->bounds()); browser_view()->UpdateDevTools(); EXPECT_FALSE(devtools_web_view()->web_contents()); EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); EXPECT_EQ(full_bounds, contents_web_view()->bounds()); } class BookmarkBarViewObserverImpl : public BookmarkBarViewObserver { public: BookmarkBarViewObserverImpl() : change_count_(0) { } int change_count() const { return change_count_; } void clear_change_count() { change_count_ = 0; } // BookmarkBarViewObserver: void OnBookmarkBarVisibilityChanged() override { change_count_++; } private: int change_count_; DISALLOW_COPY_AND_ASSIGN(BookmarkBarViewObserverImpl); }; // Verifies we don't unnecessarily change the visibility of the BookmarkBarView. IN_PROC_BROWSER_TEST_F(BrowserViewTest, AvoidUnnecessaryVisibilityChanges) { // Create two tabs, the first empty and the second the ntp. Make it so the // BookmarkBarView isn't shown (meaning it'll only be shown when on the ntp). browser()->profile()->GetPrefs()->SetBoolean( bookmarks::prefs::kShowBookmarkBar, false); GURL new_tab_url(chrome::kChromeUINewTabURL); chrome::AddTabAt(browser(), GURL(), -1, true); ui_test_utils::NavigateToURL(browser(), new_tab_url); ASSERT_TRUE(browser_view()->bookmark_bar()); BookmarkBarViewObserverImpl observer; BookmarkBarView* bookmark_bar = browser_view()->bookmark_bar(); bookmark_bar->AddObserver(&observer); EXPECT_TRUE(bookmark_bar->visible()); // Go to empty tab. Bookmark bar should hide. browser()->tab_strip_model()->ActivateTabAt(0, true); EXPECT_FALSE(bookmark_bar->visible()); EXPECT_EQ(1, observer.change_count()); observer.clear_change_count(); // Go to ntp tab. Bookmark bar should show. browser()->tab_strip_model()->ActivateTabAt(1, true); EXPECT_TRUE(bookmark_bar->visible()); EXPECT_EQ(1, observer.change_count()); observer.clear_change_count(); // Repeat with the bookmark bar always visible. browser()->profile()->GetPrefs()->SetBoolean( bookmarks::prefs::kShowBookmarkBar, true); browser()->tab_strip_model()->ActivateTabAt(1, true); EXPECT_TRUE(bookmark_bar->visible()); observer.clear_change_count(); browser()->tab_strip_model()->ActivateTabAt(0, true); EXPECT_TRUE(bookmark_bar->visible()); EXPECT_EQ(0, observer.change_count()); observer.clear_change_count(); browser()->tab_strip_model()->ActivateTabAt(1, true); EXPECT_TRUE(bookmark_bar->visible()); EXPECT_EQ(0, observer.change_count()); observer.clear_change_count(); browser_view()->bookmark_bar()->RemoveObserver(&observer); }