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