1// Copyright 2013 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/ui/views/frame/browser_view.h" 6 7#include "base/prefs/pref_service.h" 8#include "chrome/browser/devtools/devtools_window_testing.h" 9#include "chrome/browser/ui/browser.h" 10#include "chrome/browser/ui/browser_tabstrip.h" 11#include "chrome/browser/ui/tabs/tab_strip_model.h" 12#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h" 13#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view_observer.h" 14#include "chrome/common/url_constants.h" 15#include "chrome/test/base/in_process_browser_test.h" 16#include "chrome/test/base/ui_test_utils.h" 17#include "components/bookmarks/common/bookmark_pref_names.h" 18#include "content/public/browser/invalidate_type.h" 19#include "content/public/browser/web_contents.h" 20#include "content/public/browser/web_contents_observer.h" 21 22class BrowserViewTest : public InProcessBrowserTest { 23 public: 24 BrowserViewTest() : InProcessBrowserTest(), devtools_(NULL) {} 25 26 protected: 27 BrowserView* browser_view() { 28 return BrowserView::GetBrowserViewForBrowser(browser()); 29 } 30 31 views::WebView* devtools_web_view() { 32 return browser_view()->GetDevToolsWebViewForTest(); 33 } 34 35 views::WebView* contents_web_view() { 36 return browser_view()->GetContentsWebViewForTest(); 37 } 38 39 void OpenDevToolsWindow(bool docked) { 40 devtools_ = 41 DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), docked); 42 } 43 44 void CloseDevToolsWindow() { 45 DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_); 46 } 47 48 void SetDevToolsBounds(const gfx::Rect& bounds) { 49 DevToolsWindowTesting::Get(devtools_)->SetInspectedPageBounds(bounds); 50 } 51 52 DevToolsWindow* devtools_; 53 54 private: 55 DISALLOW_COPY_AND_ASSIGN(BrowserViewTest); 56}; 57 58namespace { 59 60// Used to simulate scenario in a crash. When WebContentsDestroyed() is invoked 61// updates the navigation state of another tab. 62class TestWebContentsObserver : public content::WebContentsObserver { 63 public: 64 TestWebContentsObserver(content::WebContents* source, 65 content::WebContents* other) 66 : content::WebContentsObserver(source), 67 other_(other) {} 68 virtual ~TestWebContentsObserver() {} 69 70 virtual void WebContentsDestroyed() OVERRIDE { 71 other_->NotifyNavigationStateChanged(static_cast<content::InvalidateTypes>( 72 content::INVALIDATE_TYPE_URL | content::INVALIDATE_TYPE_LOAD)); 73 } 74 75 private: 76 content::WebContents* other_; 77 78 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver); 79}; 80 81} // namespace 82 83// Verifies don't crash when CloseNow() is invoked with two tabs in a browser. 84// Additionally when one of the tabs is destroyed NotifyNavigationStateChanged() 85// is invoked on the other. 86IN_PROC_BROWSER_TEST_F(BrowserViewTest, CloseWithTabs) { 87 Browser* browser2 = 88 new Browser(Browser::CreateParams(browser()->profile(), 89 browser()->host_desktop_type())); 90 chrome::AddTabAt(browser2, GURL(), -1, true); 91 chrome::AddTabAt(browser2, GURL(), -1, true); 92 TestWebContentsObserver observer( 93 browser2->tab_strip_model()->GetWebContentsAt(0), 94 browser2->tab_strip_model()->GetWebContentsAt(1)); 95 BrowserView::GetBrowserViewForBrowser(browser2)->GetWidget()->CloseNow(); 96} 97 98// Same as CloseWithTabs, but activates the first tab, which is the first tab 99// BrowserView will destroy. 100IN_PROC_BROWSER_TEST_F(BrowserViewTest, CloseWithTabsStartWithActive) { 101 Browser* browser2 = 102 new Browser(Browser::CreateParams(browser()->profile(), 103 browser()->host_desktop_type())); 104 chrome::AddTabAt(browser2, GURL(), -1, true); 105 chrome::AddTabAt(browser2, GURL(), -1, true); 106 browser2->tab_strip_model()->ActivateTabAt(0, true); 107 TestWebContentsObserver observer( 108 browser2->tab_strip_model()->GetWebContentsAt(0), 109 browser2->tab_strip_model()->GetWebContentsAt(1)); 110 BrowserView::GetBrowserViewForBrowser(browser2)->GetWidget()->CloseNow(); 111} 112 113// Verifies that page and devtools WebViews are being correctly layed out 114// when DevTools is opened/closed/updated/undocked. 115IN_PROC_BROWSER_TEST_F(BrowserViewTest, DevToolsUpdatesBrowserWindow) { 116 gfx::Rect full_bounds = 117 browser_view()->GetContentsContainerForTest()->GetLocalBounds(); 118 gfx::Rect small_bounds(10, 20, 30, 40); 119 120 browser_view()->UpdateDevTools(); 121 EXPECT_FALSE(devtools_web_view()->web_contents()); 122 EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); 123 EXPECT_EQ(full_bounds, contents_web_view()->bounds()); 124 125 // Docked. 126 OpenDevToolsWindow(true); 127 EXPECT_TRUE(devtools_web_view()->web_contents()); 128 EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); 129 130 SetDevToolsBounds(small_bounds); 131 EXPECT_TRUE(devtools_web_view()->web_contents()); 132 EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); 133 EXPECT_EQ(small_bounds, contents_web_view()->bounds()); 134 135 browser_view()->UpdateDevTools(); 136 EXPECT_TRUE(devtools_web_view()->web_contents()); 137 EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); 138 EXPECT_EQ(small_bounds, contents_web_view()->bounds()); 139 140 CloseDevToolsWindow(); 141 EXPECT_FALSE(devtools_web_view()->web_contents()); 142 EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); 143 EXPECT_EQ(full_bounds, contents_web_view()->bounds()); 144 145 browser_view()->UpdateDevTools(); 146 EXPECT_FALSE(devtools_web_view()->web_contents()); 147 EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); 148 EXPECT_EQ(full_bounds, contents_web_view()->bounds()); 149 150 // Undocked. 151 OpenDevToolsWindow(false); 152 EXPECT_TRUE(devtools_web_view()->web_contents()); 153 EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); 154 155 SetDevToolsBounds(small_bounds); 156 EXPECT_TRUE(devtools_web_view()->web_contents()); 157 EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); 158 EXPECT_EQ(small_bounds, contents_web_view()->bounds()); 159 160 browser_view()->UpdateDevTools(); 161 EXPECT_TRUE(devtools_web_view()->web_contents()); 162 EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); 163 EXPECT_EQ(small_bounds, contents_web_view()->bounds()); 164 165 CloseDevToolsWindow(); 166 EXPECT_FALSE(devtools_web_view()->web_contents()); 167 EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); 168 EXPECT_EQ(full_bounds, contents_web_view()->bounds()); 169 170 browser_view()->UpdateDevTools(); 171 EXPECT_FALSE(devtools_web_view()->web_contents()); 172 EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); 173 EXPECT_EQ(full_bounds, contents_web_view()->bounds()); 174} 175 176class BookmarkBarViewObserverImpl : public BookmarkBarViewObserver { 177 public: 178 BookmarkBarViewObserverImpl() : change_count_(0) { 179 } 180 181 int change_count() const { return change_count_; } 182 void clear_change_count() { change_count_ = 0; } 183 184 // BookmarkBarViewObserver: 185 virtual void OnBookmarkBarVisibilityChanged() OVERRIDE { 186 change_count_++; 187 } 188 189 private: 190 int change_count_; 191 192 DISALLOW_COPY_AND_ASSIGN(BookmarkBarViewObserverImpl); 193}; 194 195// Verifies we don't unnecessarily change the visibility of the BookmarkBarView. 196IN_PROC_BROWSER_TEST_F(BrowserViewTest, AvoidUnnecessaryVisibilityChanges) { 197 // Create two tabs, the first empty and the second the ntp. Make it so the 198 // BookmarkBarView isn't shown (meaning it'll only be shown when on the ntp). 199 browser()->profile()->GetPrefs()->SetBoolean( 200 bookmarks::prefs::kShowBookmarkBar, false); 201 GURL new_tab_url(chrome::kChromeUINewTabURL); 202 chrome::AddTabAt(browser(), GURL(), -1, true); 203 ui_test_utils::NavigateToURL(browser(), new_tab_url); 204 205 ASSERT_TRUE(browser_view()->bookmark_bar()); 206 BookmarkBarViewObserverImpl observer; 207 BookmarkBarView* bookmark_bar = browser_view()->bookmark_bar(); 208 bookmark_bar->AddObserver(&observer); 209 EXPECT_TRUE(bookmark_bar->visible()); 210 211 // Go to empty tab. Bookmark bar should hide. 212 browser()->tab_strip_model()->ActivateTabAt(0, true); 213 EXPECT_FALSE(bookmark_bar->visible()); 214 EXPECT_EQ(1, observer.change_count()); 215 observer.clear_change_count(); 216 217 // Go to ntp tab. Bookmark bar should show. 218 browser()->tab_strip_model()->ActivateTabAt(1, true); 219 EXPECT_TRUE(bookmark_bar->visible()); 220 EXPECT_EQ(1, observer.change_count()); 221 observer.clear_change_count(); 222 223 // Repeat with the bookmark bar always visible. 224 browser()->profile()->GetPrefs()->SetBoolean( 225 bookmarks::prefs::kShowBookmarkBar, true); 226 browser()->tab_strip_model()->ActivateTabAt(1, true); 227 EXPECT_TRUE(bookmark_bar->visible()); 228 observer.clear_change_count(); 229 230 browser()->tab_strip_model()->ActivateTabAt(0, true); 231 EXPECT_TRUE(bookmark_bar->visible()); 232 EXPECT_EQ(0, observer.change_count()); 233 observer.clear_change_count(); 234 235 browser()->tab_strip_model()->ActivateTabAt(1, true); 236 EXPECT_TRUE(bookmark_bar->visible()); 237 EXPECT_EQ(0, observer.change_count()); 238 observer.clear_change_count(); 239 240 browser_view()->bookmark_bar()->RemoveObserver(&observer); 241} 242