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/toolbar/browser_actions_container.h" 6 7 #include "chrome/browser/chrome_notification_types.h" 8 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" 9 #include "chrome/browser/extensions/browser_action_test_util.h" 10 #include "chrome/browser/extensions/extension_browsertest.h" 11 #include "chrome/browser/extensions/extension_toolbar_model.h" 12 #include "chrome/browser/ui/browser_window.h" 13 #include "chrome/browser/ui/views/toolbar/browser_action_view.h" 14 #include "chrome/browser/ui/views/toolbar/toolbar_view.h" 15 #include "content/public/test/test_utils.h" 16 #include "extensions/browser/extension_prefs.h" 17 #include "extensions/common/extension.h" 18 #include "ui/gfx/geometry/point.h" 19 #include "ui/views/view.h" 20 21 class BrowserActionsContainerTest : public ExtensionBrowserTest { 22 public: 23 BrowserActionsContainerTest() { 24 } 25 virtual ~BrowserActionsContainerTest() {} 26 27 virtual void SetUpOnMainThread() OVERRIDE { 28 browser_actions_bar_.reset(new BrowserActionTestUtil(browser())); 29 } 30 31 BrowserActionTestUtil* browser_actions_bar() { 32 return browser_actions_bar_.get(); 33 } 34 35 // Make sure extension with index |extension_index| has an icon. 36 void EnsureExtensionHasIcon(int extension_index) { 37 if (!browser_actions_bar_->HasIcon(extension_index)) { 38 // The icon is loaded asynchronously and a notification is then sent to 39 // observers. So we wait on it. 40 ExtensionAction* browser_action = 41 browser_actions_bar_->GetExtensionAction(extension_index); 42 43 content::WindowedNotificationObserver observer( 44 chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED, 45 content::Source<ExtensionAction>(browser_action)); 46 observer.Wait(); 47 } 48 EXPECT_TRUE(browser_actions_bar()->HasIcon(extension_index)); 49 } 50 51 private: 52 scoped_ptr<BrowserActionTestUtil> browser_actions_bar_; 53 }; 54 55 // Test the basic functionality. 56 // http://crbug.com/120770 57 #if defined(OS_WIN) 58 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, DISABLED_Basic) { 59 #else 60 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, Basic) { 61 #endif 62 BrowserActionsContainer::disable_animations_during_testing_ = true; 63 64 // Load an extension with no browser action. 65 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 66 .AppendASCII("browser_action") 67 .AppendASCII("none"))); 68 // This extension should not be in the model (has no browser action). 69 EXPECT_EQ(0, browser_actions_bar()->NumberOfBrowserActions()); 70 71 // Load an extension with a browser action. 72 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 73 .AppendASCII("browser_action") 74 .AppendASCII("basics"))); 75 EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions()); 76 EnsureExtensionHasIcon(0); 77 78 // Unload the extension. 79 std::string id = browser_actions_bar()->GetExtensionId(0); 80 UnloadExtension(id); 81 EXPECT_EQ(0, browser_actions_bar()->NumberOfBrowserActions()); 82 } 83 84 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, Visibility) { 85 BrowserActionsContainer::disable_animations_during_testing_ = true; 86 87 // Load extension A (contains browser action). 88 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 89 .AppendASCII("browser_action") 90 .AppendASCII("basics"))); 91 EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions()); 92 EnsureExtensionHasIcon(0); 93 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 94 std::string idA = browser_actions_bar()->GetExtensionId(0); 95 96 // Load extension B (contains browser action). 97 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 98 .AppendASCII("browser_action") 99 .AppendASCII("add_popup"))); 100 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions()); 101 EnsureExtensionHasIcon(0); 102 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions()); 103 std::string idB = browser_actions_bar()->GetExtensionId(1); 104 105 EXPECT_NE(idA, idB); 106 107 // Load extension C (contains browser action). 108 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 109 .AppendASCII("browser_action") 110 .AppendASCII("remove_popup"))); 111 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions()); 112 EnsureExtensionHasIcon(2); 113 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions()); 114 std::string idC = browser_actions_bar()->GetExtensionId(2); 115 116 // Change container to show only one action, rest in overflow: A, [B, C]. 117 browser_actions_bar()->SetIconVisibilityCount(1); 118 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 119 120 // Disable extension A (should disappear). State becomes: B [C]. 121 DisableExtension(idA); 122 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions()); 123 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 124 EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0)); 125 126 // Enable A again. A should get its spot in the same location and the bar 127 // should not grow (chevron is showing). For details: http://crbug.com/35349. 128 // State becomes: A, [B, C]. 129 EnableExtension(idA); 130 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions()); 131 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 132 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0)); 133 134 // Disable C (in overflow). State becomes: A, [B]. 135 DisableExtension(idC); 136 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions()); 137 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 138 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0)); 139 140 // Enable C again. State becomes: A, [B, C]. 141 EnableExtension(idC); 142 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions()); 143 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 144 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0)); 145 146 // Now we have 3 extensions. Make sure they are all visible. State: A, B, C. 147 browser_actions_bar()->SetIconVisibilityCount(3); 148 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions()); 149 150 // Disable extension A (should disappear). State becomes: B, C. 151 DisableExtension(idA); 152 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions()); 153 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions()); 154 EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0)); 155 156 // Disable extension B (should disappear). State becomes: C. 157 DisableExtension(idB); 158 EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions()); 159 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 160 EXPECT_EQ(idC, browser_actions_bar()->GetExtensionId(0)); 161 162 // Enable B. State becomes: B, C. 163 EnableExtension(idB); 164 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions()); 165 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions()); 166 EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0)); 167 168 // Enable A. State becomes: A, B, C. 169 EnableExtension(idA); 170 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions()); 171 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions()); 172 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0)); 173 } 174 175 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, ForceHide) { 176 BrowserActionsContainer::disable_animations_during_testing_ = true; 177 178 // Load extension A (contains browser action). 179 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 180 .AppendASCII("browser_action") 181 .AppendASCII("basics"))); 182 EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions()); 183 EnsureExtensionHasIcon(0); 184 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 185 std::string idA = browser_actions_bar()->GetExtensionId(0); 186 187 // Force hide this browser action. 188 extensions::ExtensionActionAPI::SetBrowserActionVisibility( 189 extensions::ExtensionPrefs::Get(browser()->profile()), idA, false); 190 EXPECT_EQ(0, browser_actions_bar()->VisibleBrowserActions()); 191 } 192 193 // Test that the BrowserActionsContainer responds correctly when the underlying 194 // model enters highlight mode, and that browser actions are undraggable in 195 // highlight mode. (Highlight mode itself it tested more thoroughly in the 196 // ExtensionToolbarModel browsertests). 197 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, HighlightMode) { 198 BrowserActionsContainer::disable_animations_during_testing_ = true; 199 200 // Load three extensions with browser actions. 201 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 202 .AppendASCII("browser_action") 203 .AppendASCII("basics"))); 204 std::string id_a = browser_actions_bar()->GetExtensionId(0); 205 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 206 .AppendASCII("browser_action") 207 .AppendASCII("add_popup"))); 208 std::string id_b = browser_actions_bar()->GetExtensionId(1); 209 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 210 .AppendASCII("browser_action") 211 .AppendASCII("remove_popup"))); 212 213 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions()); 214 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions()); 215 216 BrowserActionsContainer* container = browser() 217 ->window() 218 ->GetBrowserWindowTesting() 219 ->GetToolbarView() 220 ->browser_actions(); 221 222 // Currently, dragging should be enabled. 223 BrowserActionView* action_view = container->GetBrowserActionViewAt(0); 224 ASSERT_TRUE(action_view); 225 gfx::Point point(action_view->x(), action_view->y()); 226 EXPECT_TRUE(container->CanStartDragForView(action_view, point, point)); 227 228 extensions::ExtensionToolbarModel* model = 229 extensions::ExtensionToolbarModel::Get(profile()); 230 231 extensions::ExtensionIdList extension_ids; 232 extension_ids.push_back(id_a); 233 extension_ids.push_back(id_b); 234 model->HighlightExtensions(extension_ids); 235 236 // Only two browser actions should be visible. 237 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions()); 238 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions()); 239 240 // We shouldn't be able to drag in highlight mode. 241 action_view = container->GetBrowserActionViewAt(0); 242 EXPECT_FALSE(container->CanStartDragForView(action_view, point, point)); 243 244 // We should go back to normal after leaving highlight mode. 245 model->StopHighlighting(); 246 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions()); 247 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions()); 248 action_view = container->GetBrowserActionViewAt(0); 249 EXPECT_TRUE(container->CanStartDragForView(action_view, point, point)); 250 } 251