Home | History | Annotate | Download | only in extension_action
      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