1 // Copyright (c) 2011 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 "build/build_config.h" 6 7 #if defined(TOOLKIT_GTK) 8 #include <gtk/gtk.h> 9 #endif 10 11 #include "chrome/browser/extensions/browser_action_test_util.h" 12 #include "chrome/browser/extensions/extension_apitest.h" 13 #include "chrome/browser/extensions/extension_browser_event_router.h" 14 #include "chrome/browser/extensions/extension_service.h" 15 #include "chrome/browser/extensions/extension_tabs_module.h" 16 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/ui/browser.h" 18 #include "chrome/browser/ui/browser_window.h" 19 #include "chrome/common/extensions/extension_action.h" 20 #include "chrome/common/url_constants.h" 21 #include "chrome/test/ui_test_utils.h" 22 #include "content/browser/tab_contents/tab_contents.h" 23 #include "ui/gfx/rect.h" 24 #include "ui/gfx/size.h" 25 26 class BrowserActionApiTest : public ExtensionApiTest { 27 public: 28 BrowserActionApiTest() {} 29 virtual ~BrowserActionApiTest() {} 30 31 protected: 32 BrowserActionTestUtil GetBrowserActionsBar() { 33 return BrowserActionTestUtil(browser()); 34 } 35 36 bool OpenPopup(int index) { 37 ResultCatcher catcher; 38 GetBrowserActionsBar().Press(index); 39 ui_test_utils::WaitForNotification( 40 NotificationType::EXTENSION_POPUP_VIEW_READY); 41 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 42 return GetBrowserActionsBar().HasPopup(); 43 } 44 }; 45 46 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, Basic) { 47 ASSERT_TRUE(test_server()->Start()); 48 ASSERT_TRUE(RunExtensionTest("browser_action/basics")) << message_; 49 const Extension* extension = GetSingleLoadedExtension(); 50 ASSERT_TRUE(extension) << message_; 51 52 // Test that there is a browser action in the toolbar. 53 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions()); 54 55 // Tell the extension to update the browser action state. 56 ResultCatcher catcher; 57 ui_test_utils::NavigateToURL(browser(), 58 GURL(extension->GetResourceURL("update.html"))); 59 ASSERT_TRUE(catcher.GetNextResult()); 60 61 // Test that we received the changes. 62 ExtensionAction* action = extension->browser_action(); 63 ASSERT_EQ("Modified", action->GetTitle(ExtensionAction::kDefaultTabId)); 64 ASSERT_EQ("badge", action->GetBadgeText(ExtensionAction::kDefaultTabId)); 65 ASSERT_EQ(SkColorSetARGB(255, 255, 255, 255), 66 action->GetBadgeBackgroundColor(ExtensionAction::kDefaultTabId)); 67 68 // Simulate the browser action being clicked. 69 ui_test_utils::NavigateToURL(browser(), 70 test_server()->GetURL("files/extensions/test_file.txt")); 71 72 ExtensionService* service = browser()->profile()->GetExtensionService(); 73 service->browser_event_router()->BrowserActionExecuted( 74 browser()->profile(), action->extension_id(), browser()); 75 76 // Verify the command worked. 77 TabContents* tab = browser()->GetSelectedTabContents(); 78 bool result = false; 79 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( 80 tab->render_view_host(), L"", 81 L"setInterval(function(){" 82 L" if(document.body.bgColor == 'red'){" 83 L" window.domAutomationController.send(true)}}, 100)", 84 &result)); 85 ASSERT_TRUE(result); 86 } 87 88 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, DynamicBrowserAction) { 89 ASSERT_TRUE(RunExtensionTest("browser_action/no_icon")) << message_; 90 const Extension* extension = GetSingleLoadedExtension(); 91 ASSERT_TRUE(extension) << message_; 92 93 // Test that there is a browser action in the toolbar and that it has no icon. 94 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions()); 95 EXPECT_FALSE(GetBrowserActionsBar().HasIcon(0)); 96 97 // Tell the extension to update the icon using setIcon({imageData:...}). 98 ResultCatcher catcher; 99 ui_test_utils::NavigateToURL(browser(), 100 GURL(extension->GetResourceURL("update.html"))); 101 ASSERT_TRUE(catcher.GetNextResult()); 102 103 // Test that we received the changes. 104 EXPECT_TRUE(GetBrowserActionsBar().HasIcon(0)); 105 106 // Tell the extension to update using setIcon({path:...}); 107 ui_test_utils::NavigateToURL(browser(), 108 GURL(extension->GetResourceURL("update2.html"))); 109 ASSERT_TRUE(catcher.GetNextResult()); 110 111 // Test that we received the changes. 112 EXPECT_TRUE(GetBrowserActionsBar().HasIcon(0)); 113 114 // TODO(aa): Would be nice here to actually compare that the pixels change. 115 } 116 117 // This test is flaky as per http://crbug.com/74557. 118 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, 119 FLAKY_TabSpecificBrowserActionState) { 120 ASSERT_TRUE(RunExtensionTest("browser_action/tab_specific_state")) << 121 message_; 122 const Extension* extension = GetSingleLoadedExtension(); 123 ASSERT_TRUE(extension) << message_; 124 125 // Test that there is a browser action in the toolbar and that it has an icon. 126 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions()); 127 EXPECT_TRUE(GetBrowserActionsBar().HasIcon(0)); 128 129 // Execute the action, its title should change. 130 ResultCatcher catcher; 131 GetBrowserActionsBar().Press(0); 132 ASSERT_TRUE(catcher.GetNextResult()); 133 EXPECT_EQ("Showing icon 2", GetBrowserActionsBar().GetTooltip(0)); 134 135 // Open a new tab, the title should go back. 136 browser()->NewTab(); 137 EXPECT_EQ("hi!", GetBrowserActionsBar().GetTooltip(0)); 138 139 // Go back to first tab, changed title should reappear. 140 browser()->ActivateTabAt(0, true); 141 EXPECT_EQ("Showing icon 2", GetBrowserActionsBar().GetTooltip(0)); 142 143 // Reload that tab, default title should come back. 144 ui_test_utils::NavigateToURL(browser(), GURL("about:blank")); 145 EXPECT_EQ("hi!", GetBrowserActionsBar().GetTooltip(0)); 146 } 147 148 // http://code.google.com/p/chromium/issues/detail?id=70829 149 // Only mac is okay. 150 #if !defined(OS_MACOSX) 151 #define MAYBE_BrowserActionPopup DISABLED_BrowserActionPopup 152 #else 153 #define MAYBE_BrowserActionPopup BrowserActionPopup 154 #endif 155 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, MAYBE_BrowserActionPopup) { 156 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII( 157 "browser_action/popup"))); 158 BrowserActionTestUtil actions_bar = GetBrowserActionsBar(); 159 const Extension* extension = GetSingleLoadedExtension(); 160 ASSERT_TRUE(extension) << message_; 161 162 // The extension's popup's size grows by |growFactor| each click. 163 const int growFactor = 500; 164 gfx::Size minSize = BrowserActionTestUtil::GetMinPopupSize(); 165 gfx::Size middleSize = gfx::Size(growFactor, growFactor); 166 gfx::Size maxSize = BrowserActionTestUtil::GetMaxPopupSize(); 167 168 // Ensure that two clicks will exceed the maximum allowed size. 169 ASSERT_GT(minSize.height() + growFactor * 2, maxSize.height()); 170 ASSERT_GT(minSize.width() + growFactor * 2, maxSize.width()); 171 172 // Simulate a click on the browser action and verify the size of the resulting 173 // popup. The first one tries to be 0x0, so it should be the min values. 174 ASSERT_TRUE(OpenPopup(0)); 175 EXPECT_EQ(minSize, actions_bar.GetPopupBounds().size()); 176 EXPECT_TRUE(actions_bar.HidePopup()); 177 178 ASSERT_TRUE(OpenPopup(0)); 179 EXPECT_EQ(middleSize, actions_bar.GetPopupBounds().size()); 180 EXPECT_TRUE(actions_bar.HidePopup()); 181 182 // One more time, but this time it should be constrained by the max values. 183 ASSERT_TRUE(OpenPopup(0)); 184 EXPECT_EQ(maxSize, actions_bar.GetPopupBounds().size()); 185 EXPECT_TRUE(actions_bar.HidePopup()); 186 } 187 188 // Test that calling chrome.browserAction.setPopup() can enable and change 189 // a popup. 190 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, BrowserActionAddPopup) { 191 ASSERT_TRUE(RunExtensionTest("browser_action/add_popup")) << message_; 192 const Extension* extension = GetSingleLoadedExtension(); 193 ASSERT_TRUE(extension) << message_; 194 195 int tab_id = ExtensionTabUtil::GetTabId(browser()->GetSelectedTabContents()); 196 197 ExtensionAction* browser_action = extension->browser_action(); 198 ASSERT_TRUE(browser_action) 199 << "Browser action test extension should have a browser action."; 200 201 ASSERT_FALSE(browser_action->HasPopup(tab_id)); 202 ASSERT_FALSE(browser_action->HasPopup(ExtensionAction::kDefaultTabId)); 203 204 // Simulate a click on the browser action icon. The onClicked handler 205 // will add a popup. 206 { 207 ResultCatcher catcher; 208 GetBrowserActionsBar().Press(0); 209 ASSERT_TRUE(catcher.GetNextResult()); 210 } 211 212 // The call to setPopup in background.html set a tab id, so the 213 // current tab's setting should have changed, but the default setting 214 // should not have changed. 215 ASSERT_TRUE(browser_action->HasPopup(tab_id)) 216 << "Clicking on the browser action should have caused a popup to " 217 << "be added."; 218 ASSERT_FALSE(browser_action->HasPopup(ExtensionAction::kDefaultTabId)) 219 << "Clicking on the browser action should not have set a default " 220 << "popup."; 221 222 ASSERT_STREQ("/a_popup.html", 223 browser_action->GetPopupUrl(tab_id).path().c_str()); 224 225 // Now change the popup from a_popup.html to another_popup.html by loading 226 // a page which removes the popup using chrome.browserAction.setPopup(). 227 { 228 ResultCatcher catcher; 229 ui_test_utils::NavigateToURL( 230 browser(), 231 GURL(extension->GetResourceURL("change_popup.html"))); 232 ASSERT_TRUE(catcher.GetNextResult()); 233 } 234 235 // The call to setPopup in change_popup.html did not use a tab id, 236 // so the default setting should have changed as well as the current tab. 237 ASSERT_TRUE(browser_action->HasPopup(tab_id)); 238 ASSERT_TRUE(browser_action->HasPopup(ExtensionAction::kDefaultTabId)); 239 ASSERT_STREQ("/another_popup.html", 240 browser_action->GetPopupUrl(tab_id).path().c_str()); 241 } 242 243 // Test that calling chrome.browserAction.setPopup() can remove a popup. 244 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, BrowserActionRemovePopup) { 245 // Load the extension, which has a browser action with a default popup. 246 ASSERT_TRUE(RunExtensionTest("browser_action/remove_popup")) << message_; 247 const Extension* extension = GetSingleLoadedExtension(); 248 ASSERT_TRUE(extension) << message_; 249 250 int tab_id = ExtensionTabUtil::GetTabId(browser()->GetSelectedTabContents()); 251 252 ExtensionAction* browser_action = extension->browser_action(); 253 ASSERT_TRUE(browser_action) 254 << "Browser action test extension should have a browser action."; 255 256 ASSERT_TRUE(browser_action->HasPopup(tab_id)) 257 << "Expect a browser action popup before the test removes it."; 258 ASSERT_TRUE(browser_action->HasPopup(ExtensionAction::kDefaultTabId)) 259 << "Expect a browser action popup is the default for all tabs."; 260 261 // Load a page which removes the popup using chrome.browserAction.setPopup(). 262 { 263 ResultCatcher catcher; 264 ui_test_utils::NavigateToURL( 265 browser(), 266 GURL(extension->GetResourceURL("remove_popup.html"))); 267 ASSERT_TRUE(catcher.GetNextResult()); 268 } 269 270 ASSERT_FALSE(browser_action->HasPopup(tab_id)) 271 << "Browser action popup should have been removed."; 272 ASSERT_TRUE(browser_action->HasPopup(ExtensionAction::kDefaultTabId)) 273 << "Browser action popup default should not be changed by setting " 274 << "a specific tab id."; 275 } 276 277 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, IncognitoBasic) { 278 ASSERT_TRUE(test_server()->Start()); 279 280 ASSERT_TRUE(RunExtensionTest("browser_action/basics")) << message_; 281 const Extension* extension = GetSingleLoadedExtension(); 282 ASSERT_TRUE(extension) << message_; 283 284 // Test that there is a browser action in the toolbar. 285 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions()); 286 287 // Open an incognito window and test that the browser action isn't there by 288 // default. 289 Profile* incognito_profile = browser()->profile()->GetOffTheRecordProfile(); 290 Browser* incognito_browser = Browser::Create(incognito_profile); 291 292 ASSERT_EQ(0, 293 BrowserActionTestUtil(incognito_browser).NumberOfBrowserActions()); 294 295 // Now enable the extension in incognito mode, and test that the browser 296 // action shows up. Note that we don't update the existing window at the 297 // moment, so we just create a new one. 298 browser()->profile()->GetExtensionService()->extension_prefs()-> 299 SetIsIncognitoEnabled(extension->id(), true); 300 301 incognito_browser->CloseWindow(); 302 incognito_browser = Browser::Create(incognito_profile); 303 ASSERT_EQ(1, 304 BrowserActionTestUtil(incognito_browser).NumberOfBrowserActions()); 305 306 // TODO(mpcomplete): simulate a click and have it do the right thing in 307 // incognito. 308 } 309 310 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, IncognitoDragging) { 311 ExtensionService* service = browser()->profile()->GetExtensionService(); 312 313 // The tooltips for each respective browser action. 314 const char kTooltipA[] = "Make this page red"; 315 const char kTooltipB[] = "grow"; 316 const char kTooltipC[] = "Test setPopup()"; 317 318 const size_t size_before = service->extensions()->size(); 319 320 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII( 321 "browser_action/basics"))); 322 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII( 323 "browser_action/popup"))); 324 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII( 325 "browser_action/add_popup"))); 326 327 // Test that there are 3 browser actions in the toolbar. 328 ASSERT_EQ(size_before + 3, service->extensions()->size()); 329 ASSERT_EQ(3, GetBrowserActionsBar().NumberOfBrowserActions()); 330 331 // Now enable 2 of the extensions in incognito mode, and test that the browser 332 // actions show up. 333 service->extension_prefs()->SetIsIncognitoEnabled( 334 service->extensions()->at(size_before)->id(), true); 335 service->extension_prefs()->SetIsIncognitoEnabled( 336 service->extensions()->at(size_before + 2)->id(), true); 337 338 Profile* incognito_profile = browser()->profile()->GetOffTheRecordProfile(); 339 Browser* incognito_browser = Browser::Create(incognito_profile); 340 BrowserActionTestUtil incognito_bar(incognito_browser); 341 342 // Navigate just to have a tab in this window, otherwise wonky things happen. 343 ui_test_utils::OpenURLOffTheRecord(browser()->profile(), 344 GURL(chrome::kChromeUIExtensionsURL)); 345 346 ASSERT_EQ(2, incognito_bar.NumberOfBrowserActions()); 347 348 // Ensure that the browser actions are in the right order (ABC). 349 EXPECT_EQ(kTooltipA, GetBrowserActionsBar().GetTooltip(0)); 350 EXPECT_EQ(kTooltipB, GetBrowserActionsBar().GetTooltip(1)); 351 EXPECT_EQ(kTooltipC, GetBrowserActionsBar().GetTooltip(2)); 352 353 EXPECT_EQ(kTooltipA, incognito_bar.GetTooltip(0)); 354 EXPECT_EQ(kTooltipC, incognito_bar.GetTooltip(1)); 355 356 // Now rearrange them and ensure that they are rearranged correctly in both 357 // regular and incognito mode. 358 359 // ABC -> CAB 360 service->toolbar_model()->MoveBrowserAction( 361 service->extensions()->at(size_before + 2), 0); 362 363 EXPECT_EQ(kTooltipC, GetBrowserActionsBar().GetTooltip(0)); 364 EXPECT_EQ(kTooltipA, GetBrowserActionsBar().GetTooltip(1)); 365 EXPECT_EQ(kTooltipB, GetBrowserActionsBar().GetTooltip(2)); 366 367 EXPECT_EQ(kTooltipC, incognito_bar.GetTooltip(0)); 368 EXPECT_EQ(kTooltipA, incognito_bar.GetTooltip(1)); 369 370 // CAB -> CBA 371 service->toolbar_model()->MoveBrowserAction( 372 service->extensions()->at(size_before + 1), 1); 373 374 EXPECT_EQ(kTooltipC, GetBrowserActionsBar().GetTooltip(0)); 375 EXPECT_EQ(kTooltipB, GetBrowserActionsBar().GetTooltip(1)); 376 EXPECT_EQ(kTooltipA, GetBrowserActionsBar().GetTooltip(2)); 377 378 EXPECT_EQ(kTooltipC, incognito_bar.GetTooltip(0)); 379 EXPECT_EQ(kTooltipA, incognito_bar.GetTooltip(1)); 380 } 381