1 // Copyright (c) 2012 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/chrome_notification_types.h" 12 #include "chrome/browser/extensions/browser_action_test_util.h" 13 #include "chrome/browser/extensions/extension_action.h" 14 #include "chrome/browser/extensions/extension_action_icon_factory.h" 15 #include "chrome/browser/extensions/extension_action_manager.h" 16 #include "chrome/browser/extensions/extension_apitest.h" 17 #include "chrome/browser/extensions/extension_service.h" 18 #include "chrome/browser/extensions/extension_system.h" 19 #include "chrome/browser/extensions/extension_tab_util.h" 20 #include "chrome/browser/profiles/profile.h" 21 #include "chrome/browser/ui/browser.h" 22 #include "chrome/browser/ui/browser_commands.h" 23 #include "chrome/browser/ui/browser_window.h" 24 #include "chrome/browser/ui/tabs/tab_strip_model.h" 25 #include "chrome/common/url_constants.h" 26 #include "chrome/test/base/ui_test_utils.h" 27 #include "content/public/browser/notification_service.h" 28 #include "content/public/browser/web_contents.h" 29 #include "content/public/test/browser_test_utils.h" 30 #include "grit/theme_resources.h" 31 #include "ui/base/resource/resource_bundle.h" 32 #include "ui/gfx/rect.h" 33 #include "ui/gfx/size.h" 34 #include "ui/gfx/image/image_skia.h" 35 #include "ui/gfx/image/image_skia_operations.h" 36 #include "ui/gfx/skia_util.h" 37 38 using content::WebContents; 39 40 namespace extensions { 41 namespace { 42 43 const char kEmptyImageDataError[] = 44 "The imageData property must contain an ImageData object or dictionary " 45 "of ImageData objects."; 46 const char kEmptyPathError[] = "The path property must not be empty."; 47 48 // Views implementation of browser action button will return icon whose 49 // background will be set. 50 gfx::ImageSkia AddBackgroundForViews(const gfx::ImageSkia& icon) { 51 #if defined(TOOLKIT_VIEWS) 52 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 53 gfx::ImageSkia bg = *rb.GetImageSkiaNamed(IDR_BROWSER_ACTION); 54 return gfx::ImageSkiaOperations::CreateSuperimposedImage(bg, icon); 55 #endif 56 57 return icon; 58 } 59 60 bool ImagesAreEqualAtScale(const gfx::ImageSkia& i1, 61 const gfx::ImageSkia& i2, 62 ui::ScaleFactor scale_factor) { 63 SkBitmap bitmap1 = i1.GetRepresentation(scale_factor).sk_bitmap(); 64 SkBitmap bitmap2 = i2.GetRepresentation(scale_factor).sk_bitmap(); 65 return gfx::BitmapsAreEqual(bitmap1, bitmap2); 66 } 67 68 class BrowserActionApiTest : public ExtensionApiTest { 69 public: 70 BrowserActionApiTest() {} 71 virtual ~BrowserActionApiTest() {} 72 73 protected: 74 BrowserActionTestUtil GetBrowserActionsBar() { 75 return BrowserActionTestUtil(browser()); 76 } 77 78 bool OpenPopup(int index) { 79 ResultCatcher catcher; 80 content::WindowedNotificationObserver popup_observer( 81 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, 82 content::NotificationService::AllSources()); 83 GetBrowserActionsBar().Press(index); 84 popup_observer.Wait(); 85 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 86 return GetBrowserActionsBar().HasPopup(); 87 } 88 89 ExtensionAction* GetBrowserAction(const Extension& extension) { 90 return ExtensionActionManager::Get(browser()->profile())-> 91 GetBrowserAction(extension); 92 } 93 }; 94 95 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, Basic) { 96 ASSERT_TRUE(test_server()->Start()); 97 ASSERT_TRUE(RunExtensionTest("browser_action/basics")) << message_; 98 const Extension* extension = GetSingleLoadedExtension(); 99 ASSERT_TRUE(extension) << message_; 100 101 // Test that there is a browser action in the toolbar. 102 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions()); 103 104 // Tell the extension to update the browser action state. 105 ResultCatcher catcher; 106 ui_test_utils::NavigateToURL(browser(), 107 GURL(extension->GetResourceURL("update.html"))); 108 ASSERT_TRUE(catcher.GetNextResult()) << catcher.message(); 109 110 // Test that we received the changes. 111 ExtensionAction* action = GetBrowserAction(*extension); 112 ASSERT_EQ("Modified", action->GetTitle(ExtensionAction::kDefaultTabId)); 113 ASSERT_EQ("badge", action->GetBadgeText(ExtensionAction::kDefaultTabId)); 114 ASSERT_EQ(SkColorSetARGB(255, 255, 255, 255), 115 action->GetBadgeBackgroundColor(ExtensionAction::kDefaultTabId)); 116 117 // Simulate the browser action being clicked. 118 ui_test_utils::NavigateToURL(browser(), 119 test_server()->GetURL("files/extensions/test_file.txt")); 120 121 ExtensionService* service = extensions::ExtensionSystem::Get( 122 browser()->profile())->extension_service(); 123 service->toolbar_model()->ExecuteBrowserAction(extension, browser(), NULL); 124 125 ASSERT_TRUE(catcher.GetNextResult()) << catcher.message(); 126 } 127 128 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, DynamicBrowserAction) { 129 ASSERT_TRUE(RunExtensionTest("browser_action/no_icon")) << message_; 130 const Extension* extension = GetSingleLoadedExtension(); 131 ASSERT_TRUE(extension) << message_; 132 133 #if defined (OS_MACOSX) 134 // We need this on mac so we don't loose 2x representations from browser icon 135 // in transformations gfx::ImageSkia -> NSImage -> gfx::ImageSkia. 136 std::vector<ui::ScaleFactor> supported_scale_factors; 137 supported_scale_factors.push_back(ui::SCALE_FACTOR_100P); 138 supported_scale_factors.push_back(ui::SCALE_FACTOR_200P); 139 ui::test::SetSupportedScaleFactors(supported_scale_factors); 140 #endif 141 142 // We should not be creating icons asynchronously, so we don't need an 143 // observer. 144 ExtensionActionIconFactory icon_factory( 145 profile(), 146 extension, 147 GetBrowserAction(*extension), 148 NULL); 149 // Test that there is a browser action in the toolbar. 150 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions()); 151 EXPECT_TRUE(GetBrowserActionsBar().HasIcon(0)); 152 153 gfx::Image action_icon = icon_factory.GetIcon(0); 154 uint32_t action_icon_last_id = action_icon.ToSkBitmap()->getGenerationID(); 155 156 // Let's check that |GetIcon| doesn't always return bitmap with new id. 157 ASSERT_EQ(action_icon_last_id, 158 icon_factory.GetIcon(0).ToSkBitmap()->getGenerationID()); 159 160 uint32_t action_icon_current_id = 0; 161 162 ResultCatcher catcher; 163 164 // Tell the extension to update the icon using ImageData object. 165 GetBrowserActionsBar().Press(0); 166 ASSERT_TRUE(catcher.GetNextResult()); 167 168 action_icon = icon_factory.GetIcon(0); 169 170 action_icon_current_id = action_icon.ToSkBitmap()->getGenerationID(); 171 EXPECT_GT(action_icon_current_id, action_icon_last_id); 172 action_icon_last_id = action_icon_current_id; 173 174 EXPECT_FALSE( 175 action_icon.ToImageSkia()->HasRepresentation(ui::SCALE_FACTOR_200P)); 176 177 EXPECT_TRUE(ImagesAreEqualAtScale( 178 AddBackgroundForViews(*action_icon.ToImageSkia()), 179 *GetBrowserActionsBar().GetIcon(0).ToImageSkia(), 180 ui::SCALE_FACTOR_100P)); 181 182 // Tell the extension to update the icon using path. 183 GetBrowserActionsBar().Press(0); 184 ASSERT_TRUE(catcher.GetNextResult()); 185 186 action_icon = icon_factory.GetIcon(0); 187 188 action_icon_current_id = action_icon.ToSkBitmap()->getGenerationID(); 189 EXPECT_GT(action_icon_current_id, action_icon_last_id); 190 action_icon_last_id = action_icon_current_id; 191 192 EXPECT_FALSE( 193 action_icon.ToImageSkia()->HasRepresentation(ui::SCALE_FACTOR_200P)); 194 195 EXPECT_TRUE(ImagesAreEqualAtScale( 196 AddBackgroundForViews(*action_icon.ToImageSkia()), 197 *GetBrowserActionsBar().GetIcon(0).ToImageSkia(), 198 ui::SCALE_FACTOR_100P)); 199 200 // Tell the extension to update the icon using dictionary of ImageData 201 // objects. 202 GetBrowserActionsBar().Press(0); 203 ASSERT_TRUE(catcher.GetNextResult()); 204 205 action_icon = icon_factory.GetIcon(0); 206 207 action_icon_current_id = action_icon.ToSkBitmap()->getGenerationID(); 208 EXPECT_GT(action_icon_current_id, action_icon_last_id); 209 action_icon_last_id = action_icon_current_id; 210 211 EXPECT_TRUE( 212 action_icon.ToImageSkia()->HasRepresentation(ui::SCALE_FACTOR_200P)); 213 214 EXPECT_TRUE(ImagesAreEqualAtScale( 215 AddBackgroundForViews(*action_icon.ToImageSkia()), 216 *GetBrowserActionsBar().GetIcon(0).ToImageSkia(), 217 ui::SCALE_FACTOR_100P)); 218 219 // Tell the extension to update the icon using dictionary of paths. 220 GetBrowserActionsBar().Press(0); 221 ASSERT_TRUE(catcher.GetNextResult()); 222 223 action_icon = icon_factory.GetIcon(0); 224 225 action_icon_current_id = action_icon.ToSkBitmap()->getGenerationID(); 226 EXPECT_GT(action_icon_current_id, action_icon_last_id); 227 action_icon_last_id = action_icon_current_id; 228 229 EXPECT_TRUE( 230 action_icon.ToImageSkia()->HasRepresentation(ui::SCALE_FACTOR_200P)); 231 232 EXPECT_TRUE(ImagesAreEqualAtScale( 233 AddBackgroundForViews(*action_icon.ToImageSkia()), 234 *GetBrowserActionsBar().GetIcon(0).ToImageSkia(), 235 ui::SCALE_FACTOR_100P)); 236 237 // Tell the extension to update the icon using dictionary of ImageData 238 // objects, but setting only size 19. 239 GetBrowserActionsBar().Press(0); 240 ASSERT_TRUE(catcher.GetNextResult()); 241 242 action_icon = icon_factory.GetIcon(0); 243 244 action_icon_current_id = action_icon.ToSkBitmap()->getGenerationID(); 245 EXPECT_GT(action_icon_current_id, action_icon_last_id); 246 action_icon_last_id = action_icon_current_id; 247 248 EXPECT_FALSE( 249 action_icon.ToImageSkia()->HasRepresentation(ui::SCALE_FACTOR_200P)); 250 251 EXPECT_TRUE(ImagesAreEqualAtScale( 252 AddBackgroundForViews(*action_icon.ToImageSkia()), 253 *GetBrowserActionsBar().GetIcon(0).ToImageSkia(), 254 ui::SCALE_FACTOR_100P)); 255 256 // Tell the extension to update the icon using dictionary of paths, but 257 // setting only size 19. 258 GetBrowserActionsBar().Press(0); 259 ASSERT_TRUE(catcher.GetNextResult()); 260 261 action_icon = icon_factory.GetIcon(0); 262 263 action_icon_current_id = action_icon.ToSkBitmap()->getGenerationID(); 264 EXPECT_GT(action_icon_current_id, action_icon_last_id); 265 action_icon_last_id = action_icon_current_id; 266 267 EXPECT_FALSE( 268 action_icon.ToImageSkia()->HasRepresentation(ui::SCALE_FACTOR_200P)); 269 270 EXPECT_TRUE(ImagesAreEqualAtScale( 271 AddBackgroundForViews(*action_icon.ToImageSkia()), 272 *GetBrowserActionsBar().GetIcon(0).ToImageSkia(), 273 ui::SCALE_FACTOR_100P)); 274 275 // Tell the extension to update the icon using dictionary of ImageData 276 // objects, but setting only size 38. 277 GetBrowserActionsBar().Press(0); 278 ASSERT_TRUE(catcher.GetNextResult()); 279 280 action_icon = icon_factory.GetIcon(0); 281 282 const gfx::ImageSkia* action_icon_skia = action_icon.ToImageSkia(); 283 284 EXPECT_FALSE(action_icon_skia->HasRepresentation(ui::SCALE_FACTOR_100P)); 285 EXPECT_TRUE(action_icon_skia->HasRepresentation(ui::SCALE_FACTOR_200P)); 286 287 action_icon_current_id = action_icon.ToSkBitmap()->getGenerationID(); 288 EXPECT_GT(action_icon_current_id, action_icon_last_id); 289 action_icon_last_id = action_icon_current_id; 290 291 EXPECT_TRUE(gfx::BitmapsAreEqual( 292 *action_icon.ToSkBitmap(), 293 action_icon_skia->GetRepresentation(ui::SCALE_FACTOR_200P).sk_bitmap())); 294 295 EXPECT_TRUE(ImagesAreEqualAtScale( 296 AddBackgroundForViews(*action_icon_skia), 297 *GetBrowserActionsBar().GetIcon(0).ToImageSkia(), 298 ui::SCALE_FACTOR_200P)); 299 300 // Try setting icon with empty dictionary of ImageData objects. 301 GetBrowserActionsBar().Press(0); 302 ASSERT_FALSE(catcher.GetNextResult()); 303 EXPECT_EQ(kEmptyImageDataError, catcher.message()); 304 305 // Try setting icon with empty dictionary of path objects. 306 GetBrowserActionsBar().Press(0); 307 ASSERT_FALSE(catcher.GetNextResult()); 308 EXPECT_EQ(kEmptyPathError, catcher.message()); 309 } 310 311 // This test is flaky as per http://crbug.com/74557. 312 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, 313 DISABLED_TabSpecificBrowserActionState) { 314 ASSERT_TRUE(RunExtensionTest("browser_action/tab_specific_state")) << 315 message_; 316 const Extension* extension = GetSingleLoadedExtension(); 317 ASSERT_TRUE(extension) << message_; 318 319 // Test that there is a browser action in the toolbar and that it has an icon. 320 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions()); 321 EXPECT_TRUE(GetBrowserActionsBar().HasIcon(0)); 322 323 // Execute the action, its title should change. 324 ResultCatcher catcher; 325 GetBrowserActionsBar().Press(0); 326 ASSERT_TRUE(catcher.GetNextResult()); 327 EXPECT_EQ("Showing icon 2", GetBrowserActionsBar().GetTooltip(0)); 328 329 // Open a new tab, the title should go back. 330 chrome::NewTab(browser()); 331 EXPECT_EQ("hi!", GetBrowserActionsBar().GetTooltip(0)); 332 333 // Go back to first tab, changed title should reappear. 334 browser()->tab_strip_model()->ActivateTabAt(0, true); 335 EXPECT_EQ("Showing icon 2", GetBrowserActionsBar().GetTooltip(0)); 336 337 // Reload that tab, default title should come back. 338 ui_test_utils::NavigateToURL(browser(), GURL("about:blank")); 339 EXPECT_EQ("hi!", GetBrowserActionsBar().GetTooltip(0)); 340 } 341 342 // http://code.google.com/p/chromium/issues/detail?id=70829 343 // Mac used to be ok, but then mac 10.5 started failing too. =( 344 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, DISABLED_BrowserActionPopup) { 345 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII( 346 "browser_action/popup"))); 347 BrowserActionTestUtil actions_bar = GetBrowserActionsBar(); 348 const Extension* extension = GetSingleLoadedExtension(); 349 ASSERT_TRUE(extension) << message_; 350 351 // The extension's popup's size grows by |growFactor| each click. 352 const int growFactor = 500; 353 gfx::Size minSize = BrowserActionTestUtil::GetMinPopupSize(); 354 gfx::Size middleSize = gfx::Size(growFactor, growFactor); 355 gfx::Size maxSize = BrowserActionTestUtil::GetMaxPopupSize(); 356 357 // Ensure that two clicks will exceed the maximum allowed size. 358 ASSERT_GT(minSize.height() + growFactor * 2, maxSize.height()); 359 ASSERT_GT(minSize.width() + growFactor * 2, maxSize.width()); 360 361 // Simulate a click on the browser action and verify the size of the resulting 362 // popup. The first one tries to be 0x0, so it should be the min values. 363 ASSERT_TRUE(OpenPopup(0)); 364 EXPECT_EQ(minSize, actions_bar.GetPopupBounds().size()); 365 EXPECT_TRUE(actions_bar.HidePopup()); 366 367 ASSERT_TRUE(OpenPopup(0)); 368 EXPECT_EQ(middleSize, actions_bar.GetPopupBounds().size()); 369 EXPECT_TRUE(actions_bar.HidePopup()); 370 371 // One more time, but this time it should be constrained by the max values. 372 ASSERT_TRUE(OpenPopup(0)); 373 EXPECT_EQ(maxSize, actions_bar.GetPopupBounds().size()); 374 EXPECT_TRUE(actions_bar.HidePopup()); 375 } 376 377 // Test that calling chrome.browserAction.setPopup() can enable and change 378 // a popup. 379 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, BrowserActionAddPopup) { 380 ASSERT_TRUE(RunExtensionTest("browser_action/add_popup")) << message_; 381 const Extension* extension = GetSingleLoadedExtension(); 382 ASSERT_TRUE(extension) << message_; 383 384 int tab_id = ExtensionTabUtil::GetTabId( 385 browser()->tab_strip_model()->GetActiveWebContents()); 386 387 ExtensionAction* browser_action = GetBrowserAction(*extension); 388 ASSERT_TRUE(browser_action) 389 << "Browser action test extension should have a browser action."; 390 391 ASSERT_FALSE(browser_action->HasPopup(tab_id)); 392 ASSERT_FALSE(browser_action->HasPopup(ExtensionAction::kDefaultTabId)); 393 394 // Simulate a click on the browser action icon. The onClicked handler 395 // will add a popup. 396 { 397 ResultCatcher catcher; 398 GetBrowserActionsBar().Press(0); 399 ASSERT_TRUE(catcher.GetNextResult()); 400 } 401 402 // The call to setPopup in background.html set a tab id, so the 403 // current tab's setting should have changed, but the default setting 404 // should not have changed. 405 ASSERT_TRUE(browser_action->HasPopup(tab_id)) 406 << "Clicking on the browser action should have caused a popup to " 407 << "be added."; 408 ASSERT_FALSE(browser_action->HasPopup(ExtensionAction::kDefaultTabId)) 409 << "Clicking on the browser action should not have set a default " 410 << "popup."; 411 412 ASSERT_STREQ("/a_popup.html", 413 browser_action->GetPopupUrl(tab_id).path().c_str()); 414 415 // Now change the popup from a_popup.html to another_popup.html by loading 416 // a page which removes the popup using chrome.browserAction.setPopup(). 417 { 418 ResultCatcher catcher; 419 ui_test_utils::NavigateToURL( 420 browser(), 421 GURL(extension->GetResourceURL("change_popup.html"))); 422 ASSERT_TRUE(catcher.GetNextResult()); 423 } 424 425 // The call to setPopup in change_popup.html did not use a tab id, 426 // so the default setting should have changed as well as the current tab. 427 ASSERT_TRUE(browser_action->HasPopup(tab_id)); 428 ASSERT_TRUE(browser_action->HasPopup(ExtensionAction::kDefaultTabId)); 429 ASSERT_STREQ("/another_popup.html", 430 browser_action->GetPopupUrl(tab_id).path().c_str()); 431 } 432 433 // Test that calling chrome.browserAction.setPopup() can remove a popup. 434 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, BrowserActionRemovePopup) { 435 // Load the extension, which has a browser action with a default popup. 436 ASSERT_TRUE(RunExtensionTest("browser_action/remove_popup")) << message_; 437 const Extension* extension = GetSingleLoadedExtension(); 438 ASSERT_TRUE(extension) << message_; 439 440 int tab_id = ExtensionTabUtil::GetTabId( 441 browser()->tab_strip_model()->GetActiveWebContents()); 442 443 ExtensionAction* browser_action = GetBrowserAction(*extension); 444 ASSERT_TRUE(browser_action) 445 << "Browser action test extension should have a browser action."; 446 447 ASSERT_TRUE(browser_action->HasPopup(tab_id)) 448 << "Expect a browser action popup before the test removes it."; 449 ASSERT_TRUE(browser_action->HasPopup(ExtensionAction::kDefaultTabId)) 450 << "Expect a browser action popup is the default for all tabs."; 451 452 // Load a page which removes the popup using chrome.browserAction.setPopup(). 453 { 454 ResultCatcher catcher; 455 ui_test_utils::NavigateToURL( 456 browser(), 457 GURL(extension->GetResourceURL("remove_popup.html"))); 458 ASSERT_TRUE(catcher.GetNextResult()); 459 } 460 461 ASSERT_FALSE(browser_action->HasPopup(tab_id)) 462 << "Browser action popup should have been removed."; 463 ASSERT_TRUE(browser_action->HasPopup(ExtensionAction::kDefaultTabId)) 464 << "Browser action popup default should not be changed by setting " 465 << "a specific tab id."; 466 } 467 468 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, IncognitoBasic) { 469 ASSERT_TRUE(test_server()->Start()); 470 471 ASSERT_TRUE(RunExtensionTest("browser_action/basics")) << message_; 472 const Extension* extension = GetSingleLoadedExtension(); 473 ASSERT_TRUE(extension) << message_; 474 475 // Test that there is a browser action in the toolbar. 476 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions()); 477 478 // Open an incognito window and test that the browser action isn't there by 479 // default. 480 Profile* incognito_profile = browser()->profile()->GetOffTheRecordProfile(); 481 Browser* incognito_browser = 482 new Browser(Browser::CreateParams(incognito_profile, 483 browser()->host_desktop_type())); 484 485 ASSERT_EQ(0, 486 BrowserActionTestUtil(incognito_browser).NumberOfBrowserActions()); 487 488 // Now enable the extension in incognito mode, and test that the browser 489 // action shows up. Note that we don't update the existing window at the 490 // moment, so we just create a new one. 491 extensions::ExtensionSystem::Get(browser()->profile())->extension_service()-> 492 extension_prefs()->SetIsIncognitoEnabled(extension->id(), true); 493 494 chrome::CloseWindow(incognito_browser); 495 incognito_browser = 496 new Browser(Browser::CreateParams(incognito_profile, 497 browser()->host_desktop_type())); 498 ASSERT_EQ(1, 499 BrowserActionTestUtil(incognito_browser).NumberOfBrowserActions()); 500 501 // TODO(mpcomplete): simulate a click and have it do the right thing in 502 // incognito. 503 } 504 505 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, IncognitoDragging) { 506 ExtensionService* service = extensions::ExtensionSystem::Get( 507 browser()->profile())->extension_service(); 508 509 // The tooltips for each respective browser action. 510 const char kTooltipA[] = "Make this page red"; 511 const char kTooltipB[] = "grow"; 512 const char kTooltipC[] = "Test setPopup()"; 513 514 const size_t size_before = service->extensions()->size(); 515 516 const Extension* extension_a = LoadExtension(test_data_dir_.AppendASCII( 517 "browser_action/basics")); 518 const Extension* extension_b = LoadExtension(test_data_dir_.AppendASCII( 519 "browser_action/popup")); 520 const Extension* extension_c = LoadExtension(test_data_dir_.AppendASCII( 521 "browser_action/add_popup")); 522 ASSERT_TRUE(extension_a); 523 ASSERT_TRUE(extension_b); 524 ASSERT_TRUE(extension_c); 525 526 // Test that there are 3 browser actions in the toolbar. 527 ASSERT_EQ(size_before + 3, service->extensions()->size()); 528 ASSERT_EQ(3, GetBrowserActionsBar().NumberOfBrowserActions()); 529 530 // Now enable 2 of the extensions in incognito mode, and test that the browser 531 // actions show up. 532 service->extension_prefs()->SetIsIncognitoEnabled(extension_a->id(), true); 533 service->extension_prefs()->SetIsIncognitoEnabled(extension_c->id(), true); 534 535 Profile* incognito_profile = browser()->profile()->GetOffTheRecordProfile(); 536 Browser* incognito_browser = 537 new Browser(Browser::CreateParams(incognito_profile, 538 browser()->host_desktop_type())); 539 BrowserActionTestUtil incognito_bar(incognito_browser); 540 541 // Navigate just to have a tab in this window, otherwise wonky things happen. 542 ui_test_utils::OpenURLOffTheRecord(browser()->profile(), GURL("about:blank")); 543 544 ASSERT_EQ(2, incognito_bar.NumberOfBrowserActions()); 545 546 // Ensure that the browser actions are in the right order (ABC). 547 EXPECT_EQ(kTooltipA, GetBrowserActionsBar().GetTooltip(0)); 548 EXPECT_EQ(kTooltipB, GetBrowserActionsBar().GetTooltip(1)); 549 EXPECT_EQ(kTooltipC, GetBrowserActionsBar().GetTooltip(2)); 550 551 EXPECT_EQ(kTooltipA, incognito_bar.GetTooltip(0)); 552 EXPECT_EQ(kTooltipC, incognito_bar.GetTooltip(1)); 553 554 // Now rearrange them and ensure that they are rearranged correctly in both 555 // regular and incognito mode. 556 557 // ABC -> CAB 558 service->toolbar_model()->MoveBrowserAction(extension_c, 0); 559 560 EXPECT_EQ(kTooltipC, GetBrowserActionsBar().GetTooltip(0)); 561 EXPECT_EQ(kTooltipA, GetBrowserActionsBar().GetTooltip(1)); 562 EXPECT_EQ(kTooltipB, GetBrowserActionsBar().GetTooltip(2)); 563 564 EXPECT_EQ(kTooltipC, incognito_bar.GetTooltip(0)); 565 EXPECT_EQ(kTooltipA, incognito_bar.GetTooltip(1)); 566 567 // CAB -> CBA 568 service->toolbar_model()->MoveBrowserAction(extension_b, 1); 569 570 EXPECT_EQ(kTooltipC, GetBrowserActionsBar().GetTooltip(0)); 571 EXPECT_EQ(kTooltipB, GetBrowserActionsBar().GetTooltip(1)); 572 EXPECT_EQ(kTooltipA, GetBrowserActionsBar().GetTooltip(2)); 573 574 EXPECT_EQ(kTooltipC, incognito_bar.GetTooltip(0)); 575 EXPECT_EQ(kTooltipA, incognito_bar.GetTooltip(1)); 576 } 577 578 // Disabled because of failures (crashes) on ASAN bot. 579 // See http://crbug.com/98861. 580 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, DISABLED_CloseBackgroundPage) { 581 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII( 582 "browser_action/close_background"))); 583 const Extension* extension = GetSingleLoadedExtension(); 584 585 // There is a background page and a browser action with no badge text. 586 ExtensionProcessManager* manager = 587 extensions::ExtensionSystem::Get(browser()->profile())->process_manager(); 588 ASSERT_TRUE(manager->GetBackgroundHostForExtension(extension->id())); 589 ExtensionAction* action = GetBrowserAction(*extension); 590 ASSERT_EQ("", action->GetBadgeText(ExtensionAction::kDefaultTabId)); 591 592 content::WindowedNotificationObserver host_destroyed_observer( 593 chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, 594 content::NotificationService::AllSources()); 595 596 // Click the browser action. 597 extensions::ExtensionSystem::Get(browser()->profile())->extension_service()-> 598 toolbar_model()->ExecuteBrowserAction(extension, browser(), NULL); 599 600 // It can take a moment for the background page to actually get destroyed 601 // so we wait for the notification before checking that it's really gone 602 // and the badge text has been set. 603 host_destroyed_observer.Wait(); 604 ASSERT_FALSE(manager->GetBackgroundHostForExtension(extension->id())); 605 ASSERT_EQ("X", action->GetBadgeText(ExtensionAction::kDefaultTabId)); 606 } 607 608 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, BadgeBackgroundColor) { 609 ASSERT_TRUE(test_server()->Start()); 610 ASSERT_TRUE(RunExtensionTest("browser_action/color")) << message_; 611 const Extension* extension = GetSingleLoadedExtension(); 612 ASSERT_TRUE(extension) << message_; 613 614 // Test that there is a browser action in the toolbar. 615 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions()); 616 617 // Test that CSS values (#FF0000) set color correctly. 618 ExtensionAction* action = GetBrowserAction(*extension); 619 ASSERT_EQ(SkColorSetARGB(255, 255, 0, 0), 620 action->GetBadgeBackgroundColor(ExtensionAction::kDefaultTabId)); 621 622 // Tell the extension to update the browser action state. 623 ResultCatcher catcher; 624 ui_test_utils::NavigateToURL(browser(), 625 GURL(extension->GetResourceURL("update.html"))); 626 ASSERT_TRUE(catcher.GetNextResult()); 627 628 // Test that CSS values (#0F0) set color correctly. 629 ASSERT_EQ(SkColorSetARGB(255, 0, 255, 0), 630 action->GetBadgeBackgroundColor(ExtensionAction::kDefaultTabId)); 631 632 ui_test_utils::NavigateToURL(browser(), 633 GURL(extension->GetResourceURL("update2.html"))); 634 ASSERT_TRUE(catcher.GetNextResult()); 635 636 // Test that array values set color correctly. 637 ASSERT_EQ(SkColorSetARGB(255, 255, 255, 255), 638 action->GetBadgeBackgroundColor(ExtensionAction::kDefaultTabId)); 639 } 640 641 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, Getters) { 642 ASSERT_TRUE(RunExtensionTest("browser_action/getters")) << message_; 643 const Extension* extension = GetSingleLoadedExtension(); 644 ASSERT_TRUE(extension) << message_; 645 646 // Test that there is a browser action in the toolbar. 647 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions()); 648 649 // Test the getters for defaults. 650 ResultCatcher catcher; 651 ui_test_utils::NavigateToURL(browser(), 652 GURL(extension->GetResourceURL("update.html"))); 653 ASSERT_TRUE(catcher.GetNextResult()); 654 655 // Test the getters for a specific tab. 656 ui_test_utils::NavigateToURL(browser(), 657 GURL(extension->GetResourceURL("update2.html"))); 658 ASSERT_TRUE(catcher.GetNextResult()); 659 } 660 661 // Verify triggering browser action. 662 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, TestTriggerBrowserAction) { 663 ASSERT_TRUE(test_server()->Start()); 664 665 ASSERT_TRUE(RunExtensionTest("trigger_actions/browser_action")) << message_; 666 const Extension* extension = GetSingleLoadedExtension(); 667 ASSERT_TRUE(extension) << message_; 668 669 // Test that there is a browser action in the toolbar. 670 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions()); 671 672 ui_test_utils::NavigateToURL( 673 browser(), 674 test_server()->GetURL("files/simple.html")); 675 676 ExtensionAction* browser_action = GetBrowserAction(*extension); 677 EXPECT_TRUE(browser_action != NULL); 678 679 // Simulate a click on the browser action icon. 680 { 681 ResultCatcher catcher; 682 GetBrowserActionsBar().Press(0); 683 EXPECT_TRUE(catcher.GetNextResult()); 684 } 685 686 WebContents* tab = 687 browser()->tab_strip_model()->GetActiveWebContents(); 688 EXPECT_TRUE(tab != NULL); 689 690 // Verify that the browser action turned the background color red. 691 const std::string script = 692 "window.domAutomationController.send(document.body.style." 693 "backgroundColor);"; 694 std::string result; 695 const std::string frame_xpath; 696 EXPECT_TRUE(content::ExecuteScriptInFrameAndExtractString( 697 tab, frame_xpath, script, &result)); 698 EXPECT_EQ(result, "red"); 699 } 700 701 } // namespace 702 } // namespace extensions 703