Home | History | Annotate | Download | only in panels
      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 "chrome/browser/ui/panels/base_panel_browser_test.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/memory/weak_ptr.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/path_service.h"
     12 #include "base/strings/string_number_conversions.h"
     13 #include "chrome/browser/chrome_notification_types.h"
     14 #include "chrome/browser/extensions/extension_service.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "chrome/browser/ui/browser.h"
     17 #include "chrome/browser/ui/browser_window.h"
     18 #include "chrome/browser/ui/panels/detached_panel_collection.h"
     19 #include "chrome/browser/ui/panels/native_panel.h"
     20 #include "chrome/browser/ui/panels/panel_collection.h"
     21 #include "chrome/browser/ui/panels/panel_mouse_watcher.h"
     22 #include "chrome/browser/ui/panels/stacked_panel_collection.h"
     23 #include "chrome/browser/ui/panels/test_panel_active_state_observer.h"
     24 #include "chrome/browser/ui/panels/test_panel_mouse_watcher.h"
     25 #include "chrome/common/chrome_paths.h"
     26 #include "chrome/common/chrome_switches.h"
     27 #include "chrome/test/base/interactive_test_utils.h"
     28 #include "chrome/test/base/ui_test_utils.h"
     29 #include "content/public/browser/notification_service.h"
     30 #include "content/public/common/url_constants.h"
     31 #include "content/public/test/web_contents_tester.h"
     32 #include "extensions/browser/extension_prefs.h"
     33 #include "extensions/browser/install_flag.h"
     34 #include "extensions/common/manifest_constants.h"
     35 #include "sync/api/string_ordinal.h"
     36 
     37 #if defined(OS_LINUX)
     38 #include "chrome/browser/ui/browser_window.h"
     39 #include "ui/base/x/x11_util.h"
     40 #endif
     41 
     42 #if defined(OS_MACOSX)
     43 #include "base/mac/scoped_nsautorelease_pool.h"
     44 #include "chrome/browser/ui/cocoa/run_loop_testing.h"
     45 #endif
     46 
     47 using content::WebContentsTester;
     48 using extensions::Extension;
     49 
     50 namespace {
     51 
     52 const gfx::Rect kTestingPrimaryDisplayArea = gfx::Rect(0, 0, 800, 600);
     53 const gfx::Rect kTestingPrimaryWorkArea = gfx::Rect(0, 0, 800, 580);
     54 
     55 struct MockDesktopBar {
     56   bool auto_hiding_enabled;
     57   DisplaySettingsProvider::DesktopBarVisibility visibility;
     58   int thickness;
     59 };
     60 
     61 class MockDisplaySettingsProviderImpl :
     62     public BasePanelBrowserTest::MockDisplaySettingsProvider {
     63  public:
     64   explicit MockDisplaySettingsProviderImpl();
     65   virtual ~MockDisplaySettingsProviderImpl() { }
     66 
     67   // Overridden from DisplaySettingsProvider:
     68   virtual gfx::Rect GetPrimaryDisplayArea() const OVERRIDE;
     69   virtual gfx::Rect GetPrimaryWorkArea() const OVERRIDE;
     70   virtual gfx::Rect GetDisplayAreaMatching(
     71       const gfx::Rect& bounds) const OVERRIDE;
     72   virtual gfx::Rect GetWorkAreaMatching(
     73       const gfx::Rect& bounds) const OVERRIDE;
     74   virtual bool IsAutoHidingDesktopBarEnabled(
     75       DesktopBarAlignment alignment) OVERRIDE;
     76   virtual int GetDesktopBarThickness(
     77       DesktopBarAlignment alignment) const OVERRIDE;
     78   virtual DesktopBarVisibility GetDesktopBarVisibility(
     79       DesktopBarAlignment alignment) const OVERRIDE;
     80   virtual bool IsFullScreen() OVERRIDE;
     81 
     82   // Overridden from MockDisplaySettingsProvider:
     83   virtual void SetPrimaryDisplay(
     84       const gfx::Rect& display_area, const gfx::Rect& work_area) OVERRIDE;
     85   virtual void SetSecondaryDisplay(
     86       const gfx::Rect& display_area, const gfx::Rect& work_area) OVERRIDE;
     87   virtual void EnableAutoHidingDesktopBar(DesktopBarAlignment alignment,
     88                                           bool enabled,
     89                                           int thickness) OVERRIDE;
     90   virtual void SetDesktopBarVisibility(
     91       DesktopBarAlignment alignment, DesktopBarVisibility visibility) OVERRIDE;
     92   virtual void SetDesktopBarThickness(DesktopBarAlignment alignment,
     93                                       int thickness) OVERRIDE;
     94   virtual void EnableFullScreenMode(bool enabled) OVERRIDE;
     95 
     96  private:
     97   gfx::Rect primary_display_area_;
     98   gfx::Rect primary_work_area_;
     99   gfx::Rect secondary_display_area_;
    100   gfx::Rect secondary_work_area_;
    101   MockDesktopBar mock_desktop_bars[3];
    102   bool full_screen_enabled_;
    103 
    104   DISALLOW_COPY_AND_ASSIGN(MockDisplaySettingsProviderImpl);
    105 };
    106 
    107 
    108 MockDisplaySettingsProviderImpl::MockDisplaySettingsProviderImpl()
    109     : full_screen_enabled_(false) {
    110   memset(mock_desktop_bars, 0, sizeof(mock_desktop_bars));
    111 }
    112 
    113 gfx::Rect MockDisplaySettingsProviderImpl::GetPrimaryDisplayArea() const {
    114   return primary_display_area_;
    115 }
    116 
    117 gfx::Rect MockDisplaySettingsProviderImpl::GetPrimaryWorkArea() const {
    118   return primary_work_area_;
    119 }
    120 
    121 gfx::Rect MockDisplaySettingsProviderImpl::GetDisplayAreaMatching(
    122     const gfx::Rect& bounds) const {
    123   if (secondary_display_area_.IsEmpty())
    124     return primary_display_area_;
    125 
    126   gfx::Rect primary_intersection =
    127       gfx::IntersectRects(bounds, primary_display_area_);
    128   int primary_intersection_size =
    129       primary_intersection.width() * primary_intersection.height();
    130 
    131   gfx::Rect secondary_intersection =
    132       gfx::IntersectRects(bounds, secondary_display_area_);
    133   int secondary_intersection_size =
    134       secondary_intersection.width() * secondary_intersection.height();
    135 
    136   return primary_intersection_size >= secondary_intersection_size ?
    137       primary_display_area_ : secondary_display_area_;
    138 }
    139 
    140 gfx::Rect MockDisplaySettingsProviderImpl::GetWorkAreaMatching(
    141     const gfx::Rect& bounds) const {
    142   if (secondary_work_area_.IsEmpty())
    143     return primary_work_area_;
    144 
    145   gfx::Rect primary_intersection =
    146       gfx::IntersectRects(bounds, primary_work_area_);
    147   int primary_intersection_size =
    148       primary_intersection.width() * primary_intersection.height();
    149 
    150   gfx::Rect secondary_intersection =
    151       gfx::IntersectRects(bounds, secondary_work_area_);
    152   int secondary_intersection_size =
    153       secondary_intersection.width() * secondary_intersection.height();
    154 
    155   return primary_intersection_size >= secondary_intersection_size ?
    156       primary_work_area_ : secondary_work_area_;
    157 }
    158 
    159 bool MockDisplaySettingsProviderImpl::IsAutoHidingDesktopBarEnabled(
    160     DesktopBarAlignment alignment) {
    161   return mock_desktop_bars[static_cast<int>(alignment)].auto_hiding_enabled;
    162 }
    163 
    164 int MockDisplaySettingsProviderImpl::GetDesktopBarThickness(
    165     DesktopBarAlignment alignment) const {
    166   return mock_desktop_bars[static_cast<int>(alignment)].thickness;
    167 }
    168 
    169 DisplaySettingsProvider::DesktopBarVisibility
    170 MockDisplaySettingsProviderImpl::GetDesktopBarVisibility(
    171     DesktopBarAlignment alignment) const {
    172   return mock_desktop_bars[static_cast<int>(alignment)].visibility;
    173 }
    174 
    175 bool MockDisplaySettingsProviderImpl::IsFullScreen() {
    176   return full_screen_enabled_;
    177 }
    178 
    179 void MockDisplaySettingsProviderImpl::EnableAutoHidingDesktopBar(
    180     DesktopBarAlignment alignment, bool enabled, int thickness) {
    181   MockDesktopBar* bar = &(mock_desktop_bars[static_cast<int>(alignment)]);
    182   bar->auto_hiding_enabled = enabled;
    183   bar->thickness = thickness;
    184 }
    185 
    186 void MockDisplaySettingsProviderImpl::SetPrimaryDisplay(
    187     const gfx::Rect& display_area, const gfx::Rect& work_area) {
    188   DCHECK(display_area.Contains(work_area));
    189   primary_display_area_ = display_area;
    190   primary_work_area_ = work_area;
    191   OnDisplaySettingsChanged();
    192 }
    193 
    194 void MockDisplaySettingsProviderImpl::SetSecondaryDisplay(
    195     const gfx::Rect& display_area, const gfx::Rect& work_area) {
    196   DCHECK(display_area.Contains(work_area));
    197   secondary_display_area_ = display_area;
    198   secondary_work_area_ = work_area;
    199   OnDisplaySettingsChanged();
    200 }
    201 
    202 void MockDisplaySettingsProviderImpl::SetDesktopBarVisibility(
    203     DesktopBarAlignment alignment, DesktopBarVisibility visibility) {
    204   MockDesktopBar* bar = &(mock_desktop_bars[static_cast<int>(alignment)]);
    205   if (!bar->auto_hiding_enabled)
    206     return;
    207   if (visibility == bar->visibility)
    208     return;
    209   bar->visibility = visibility;
    210   FOR_EACH_OBSERVER(
    211       DesktopBarObserver,
    212       desktop_bar_observers(),
    213       OnAutoHidingDesktopBarVisibilityChanged(alignment, visibility));
    214 }
    215 
    216 void MockDisplaySettingsProviderImpl::SetDesktopBarThickness(
    217     DesktopBarAlignment alignment, int thickness) {
    218   MockDesktopBar* bar = &(mock_desktop_bars[static_cast<int>(alignment)]);
    219   if (!bar->auto_hiding_enabled)
    220     return;
    221   if (thickness == bar->thickness)
    222     return;
    223   bar->thickness = thickness;
    224   FOR_EACH_OBSERVER(
    225       DesktopBarObserver,
    226       desktop_bar_observers(),
    227       OnAutoHidingDesktopBarThicknessChanged(alignment, thickness));
    228 }
    229 
    230 void MockDisplaySettingsProviderImpl::EnableFullScreenMode(bool enabled) {
    231   full_screen_enabled_ = enabled;
    232   CheckFullScreenMode(PERFORM_FULLSCREEN_CHECK);
    233 }
    234 
    235 }  // namespace
    236 
    237 const base::FilePath::CharType* BasePanelBrowserTest::kTestDir =
    238     FILE_PATH_LITERAL("panels");
    239 
    240 BasePanelBrowserTest::BasePanelBrowserTest()
    241     : InProcessBrowserTest(),
    242       mock_display_settings_enabled_(true) {
    243 }
    244 
    245 BasePanelBrowserTest::~BasePanelBrowserTest() {
    246 }
    247 
    248 bool BasePanelBrowserTest::SkipTestIfIceWM() {
    249 #if defined(OS_LINUX)
    250   return ui::GuessWindowManager() == ui::WM_ICE_WM;
    251 #else
    252   return false;
    253 #endif
    254 }
    255 
    256 bool BasePanelBrowserTest::SkipTestIfCompizWM() {
    257 #if defined(OS_LINUX)
    258   return ui::GuessWindowManager() == ui::WM_COMPIZ;
    259 #else
    260   return false;
    261 #endif
    262 }
    263 
    264 void BasePanelBrowserTest::SetUpCommandLine(CommandLine* command_line) {
    265   command_line->AppendSwitch(switches::kEnablePanels);
    266 }
    267 
    268 void BasePanelBrowserTest::SetUpOnMainThread() {
    269   InProcessBrowserTest::SetUpOnMainThread();
    270 
    271   // Setup the work area and desktop bar so that we have consistent testing
    272   // environment for all panel related tests.
    273   if (mock_display_settings_enabled_) {
    274     mock_display_settings_provider_ = new MockDisplaySettingsProviderImpl();
    275     mock_display_settings_provider_->SetPrimaryDisplay(
    276         kTestingPrimaryDisplayArea, kTestingPrimaryWorkArea);
    277     PanelManager::SetDisplaySettingsProviderForTesting(
    278         mock_display_settings_provider_);
    279   }
    280 
    281   PanelManager* panel_manager = PanelManager::GetInstance();
    282   panel_manager->enable_auto_sizing(false);
    283 
    284   PanelManager::shorten_time_intervals_for_testing();
    285 
    286   // Simulate the mouse movement so that tests are not affected by actual mouse
    287   // events.
    288   PanelMouseWatcher* mouse_watcher = new TestPanelMouseWatcher();
    289   panel_manager->SetMouseWatcherForTesting(mouse_watcher);
    290 
    291   // This is needed so the subsequently created panels can be activated.
    292   // On a Mac, it transforms background-only test process into foreground one.
    293   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    294 }
    295 
    296 void BasePanelBrowserTest::WaitForPanelActiveState(
    297     Panel* panel, ActiveState expected_state) {
    298   DCHECK(expected_state == SHOW_AS_ACTIVE ||
    299          expected_state == SHOW_AS_INACTIVE);
    300 
    301 #if defined(OS_MACOSX)
    302   scoped_ptr<NativePanelTesting> panel_testing(
    303       CreateNativePanelTesting(panel));
    304   ASSERT_TRUE(panel_testing->EnsureApplicationRunOnForeground()) <<
    305       "Failed to bring application to foreground. Bail out.";
    306 #endif
    307 
    308   PanelActiveStateObserver signal(panel, expected_state == SHOW_AS_ACTIVE);
    309   signal.Wait();
    310 }
    311 
    312 void BasePanelBrowserTest::WaitForWindowSizeAvailable(Panel* panel) {
    313   scoped_ptr<NativePanelTesting> panel_testing(
    314       CreateNativePanelTesting(panel));
    315   content::WindowedNotificationObserver signal(
    316       chrome::NOTIFICATION_PANEL_WINDOW_SIZE_KNOWN,
    317       content::Source<Panel>(panel));
    318   if (panel_testing->IsWindowSizeKnown())
    319     return;
    320   signal.Wait();
    321   EXPECT_TRUE(panel_testing->IsWindowSizeKnown());
    322 }
    323 
    324 void BasePanelBrowserTest::WaitForBoundsAnimationFinished(Panel* panel) {
    325   scoped_ptr<NativePanelTesting> panel_testing(
    326       CreateNativePanelTesting(panel));
    327   // Sometimes there are several animations in sequence due to content
    328   // auto resizing. Wait for all animations to finish.
    329   while (panel_testing->IsAnimatingBounds()) {
    330     content::WindowedNotificationObserver signal(
    331         chrome::NOTIFICATION_PANEL_BOUNDS_ANIMATIONS_FINISHED,
    332         content::Source<Panel>(panel));
    333     if (!panel_testing->IsAnimatingBounds())
    334       return;
    335     signal.Wait();
    336   }
    337 }
    338 
    339 BasePanelBrowserTest::CreatePanelParams::CreatePanelParams(
    340     const std::string& name,
    341     const gfx::Rect& bounds,
    342     ActiveState show_flag)
    343     : name(name),
    344       bounds(bounds),
    345       show_flag(show_flag),
    346       wait_for_fully_created(true),
    347       expected_active_state(show_flag),
    348       create_mode(PanelManager::CREATE_AS_DOCKED),
    349       profile(NULL) {
    350 }
    351 
    352 Panel* BasePanelBrowserTest::CreatePanelWithParams(
    353     const CreatePanelParams& params) {
    354 #if defined(OS_MACOSX)
    355   // Opening panels on a Mac causes NSWindowController of the Panel window
    356   // to be autoreleased. We need a pool drained after it's done so the test
    357   // can close correctly. The NSWindowController of the Panel window controls
    358   // lifetime of the Panel object so we want to release it as soon as
    359   // possible. In real Chrome, this is done by message pump.
    360   // On non-Mac platform, this is an empty class.
    361   base::mac::ScopedNSAutoreleasePool autorelease_pool;
    362 #endif
    363 
    364   content::WindowedNotificationObserver observer(
    365       content::NOTIFICATION_LOAD_STOP,
    366       content::NotificationService::AllSources());
    367 
    368   PanelManager* manager = PanelManager::GetInstance();
    369   Panel* panel = manager->CreatePanel(
    370       params.name,
    371       params.profile ? params.profile : browser()->profile(),
    372       params.url,
    373       params.bounds,
    374       params.create_mode);
    375 
    376   if (!params.url.is_empty())
    377     observer.Wait();
    378 
    379   if (!manager->auto_sizing_enabled() ||
    380       params.bounds.width() || params.bounds.height()) {
    381     EXPECT_FALSE(panel->auto_resizable());
    382   } else {
    383     EXPECT_TRUE(panel->auto_resizable());
    384   }
    385 
    386   if (params.show_flag == SHOW_AS_ACTIVE) {
    387     panel->Show();
    388   } else {
    389     panel->ShowInactive();
    390   }
    391 
    392   if (params.wait_for_fully_created) {
    393     base::MessageLoopForUI::current()->RunUntilIdle();
    394 
    395 #if defined(OS_LINUX)
    396     // On bots, we might have a simple window manager which always activates new
    397     // windows, and can't always deactivate them. Re-activate the main tabbed
    398     // browser to "deactivate" the newly created panel.
    399     if (params.expected_active_state == SHOW_AS_INACTIVE &&
    400         ui::GuessWindowManager() == ui::WM_ICE_WM) {
    401       // Wait for new panel to become active before deactivating to ensure
    402       // the activated notification is consumed before we wait for the panel
    403       // to become inactive.
    404       WaitForPanelActiveState(panel, SHOW_AS_ACTIVE);
    405       browser()->window()->Activate();
    406     }
    407 #endif
    408     // More waiting, because gaining or losing focus may require inter-process
    409     // asynchronous communication, and it is not enough to just run the local
    410     // message loop to make sure this activity has completed.
    411     WaitForPanelActiveState(panel, params.expected_active_state);
    412 
    413     // On Linux, window size is not available right away and we should wait
    414     // before moving forward with the test.
    415     WaitForWindowSizeAvailable(panel);
    416 
    417     // Wait for the bounds animations on creation to finish.
    418     WaitForBoundsAnimationFinished(panel);
    419   }
    420 
    421   return panel;
    422 }
    423 
    424 Panel* BasePanelBrowserTest::CreatePanelWithBounds(
    425     const std::string& panel_name, const gfx::Rect& bounds) {
    426   CreatePanelParams params(panel_name, bounds, SHOW_AS_ACTIVE);
    427   return CreatePanelWithParams(params);
    428 }
    429 
    430 Panel* BasePanelBrowserTest::CreatePanel(const std::string& panel_name) {
    431   CreatePanelParams params(panel_name, gfx::Rect(), SHOW_AS_ACTIVE);
    432   return CreatePanelWithParams(params);
    433 }
    434 
    435 Panel* BasePanelBrowserTest::CreateDockedPanel(const std::string& name,
    436                                                const gfx::Rect& bounds) {
    437   Panel* panel = CreatePanelWithBounds(name, bounds);
    438   EXPECT_EQ(PanelCollection::DOCKED, panel->collection()->type());
    439   return panel;
    440 }
    441 
    442 Panel* BasePanelBrowserTest::CreateDetachedPanel(const std::string& name,
    443                                                  const gfx::Rect& bounds) {
    444   Panel* panel = CreatePanelWithBounds(name, bounds);
    445   PanelManager* panel_manager = panel->manager();
    446   panel_manager->MovePanelToCollection(panel,
    447                                        panel_manager->detached_collection(),
    448                                        PanelCollection::DEFAULT_POSITION);
    449   EXPECT_EQ(PanelCollection::DETACHED, panel->collection()->type());
    450   // The panel is first created as docked panel, which ignores the specified
    451   // origin in |bounds|. We need to reposition the panel after it becomes
    452   // detached.
    453   panel->SetPanelBounds(bounds);
    454   WaitForBoundsAnimationFinished(panel);
    455   return panel;
    456 }
    457 
    458 Panel* BasePanelBrowserTest::CreateStackedPanel(const std::string& name,
    459                                                 const gfx::Rect& bounds,
    460                                                 StackedPanelCollection* stack) {
    461   Panel* panel = CreateDetachedPanel(name, bounds);
    462   panel->manager()->MovePanelToCollection(
    463       panel,
    464       stack,
    465       static_cast<PanelCollection::PositioningMask>(
    466           PanelCollection::DEFAULT_POSITION |
    467           PanelCollection::COLLAPSE_TO_FIT));
    468   EXPECT_EQ(PanelCollection::STACKED, panel->collection()->type());
    469   WaitForBoundsAnimationFinished(panel);
    470   return panel;
    471 }
    472 
    473 Panel* BasePanelBrowserTest::CreateInactivePanel(const std::string& name) {
    474   // Create an active panel first, instead of inactive panel. This is because
    475   // certain window managers on Linux, like icewm, will always activate the
    476   // new window.
    477   Panel* panel = CreatePanel(name);
    478 
    479   DeactivatePanel(panel);
    480   WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
    481 
    482   return panel;
    483 }
    484 
    485 Panel* BasePanelBrowserTest::CreateInactiveDockedPanel(
    486     const std::string& name, const gfx::Rect& bounds) {
    487   // Create an active panel first, instead of inactive panel. This is because
    488   // certain window managers on Linux, like icewm, will always activate the
    489   // new window.
    490   Panel* panel = CreateDockedPanel(name, bounds);
    491 
    492   DeactivatePanel(panel);
    493   WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
    494 
    495   return panel;
    496 }
    497 
    498 Panel* BasePanelBrowserTest::CreateInactiveDetachedPanel(
    499     const std::string& name, const gfx::Rect& bounds) {
    500   // Create an active panel first, instead of inactive panel. This is because
    501   // certain window managers on Linux, like icewm, will always activate the
    502   // new window.
    503   Panel* panel = CreateDetachedPanel(name, bounds);
    504 
    505   DeactivatePanel(panel);
    506   WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
    507 
    508   return panel;
    509 }
    510 
    511 void BasePanelBrowserTest::ActivatePanel(Panel* panel) {
    512   // For certain window managers on Linux, the window activation/deactivation
    513   // signals might not be sent. To work around this, we explicitly deactivate
    514   // all other panels first.
    515 #if defined(OS_LINUX)
    516   std::vector<Panel*> panels = PanelManager::GetInstance()->panels();
    517   for (std::vector<Panel*>::const_iterator iter = panels.begin();
    518        iter != panels.end(); ++iter) {
    519     Panel* current_panel = *iter;
    520     if (panel != current_panel)
    521       current_panel->Deactivate();
    522   }
    523 #endif
    524 
    525   panel->Activate();
    526 }
    527 
    528 void BasePanelBrowserTest::DeactivatePanel(Panel* panel) {
    529 #if defined(OS_LINUX)
    530   // For certain window managers on Linux, like icewm, panel activation and
    531   // deactivation notification might not get tiggered when non-panel window is
    532   // activated or deactivated. So we deactivate the panel directly.
    533   panel->Deactivate();
    534 #else
    535   // Make the panel lose focus by activating the browser window. This is
    536   // because:
    537   // 1) On Windows, deactivating the panel window might cause the application
    538   //    to lose the foreground status. When this occurs, trying to activate
    539   //    the panel window again will not be allowed by the system.
    540   // 2) On MacOS, deactivating a window is not supported by Cocoa.
    541   browser()->window()->Activate();
    542 #endif
    543 }
    544 
    545 // static
    546 NativePanelTesting* BasePanelBrowserTest::CreateNativePanelTesting(
    547     Panel* panel) {
    548   return panel->native_panel()->CreateNativePanelTesting();
    549 }
    550 
    551 scoped_refptr<Extension> BasePanelBrowserTest::CreateExtension(
    552     const base::FilePath::StringType& path,
    553     extensions::Manifest::Location location,
    554     const base::DictionaryValue& extra_value) {
    555   extensions::ExtensionPrefs* extension_prefs =
    556       extensions::ExtensionPrefs::Get(browser()->profile());
    557   base::FilePath full_path = extension_prefs->install_directory().Append(path);
    558 
    559   scoped_ptr<base::DictionaryValue> input_value(extra_value.DeepCopy());
    560   input_value->SetString(extensions::manifest_keys::kVersion, "1.0.0.0");
    561   input_value->SetString(extensions::manifest_keys::kName, "Sample Extension");
    562 
    563   std::string error;
    564   scoped_refptr<Extension> extension = Extension::Create(
    565       full_path,  location, *input_value, Extension::NO_FLAGS, &error);
    566   EXPECT_TRUE(extension.get());
    567   EXPECT_STREQ("", error.c_str());
    568   browser()->profile()->GetExtensionService()->OnExtensionInstalled(
    569       extension.get(),
    570       syncer::StringOrdinal(),
    571       extensions::kInstallFlagInstallImmediately);
    572   return extension;
    573 }
    574 
    575 void BasePanelBrowserTest::CloseWindowAndWait(Panel* panel) {
    576   // Closing a panel may involve several async tasks. Need to use
    577   // message pump and wait for the notification.
    578   PanelManager* manager = PanelManager::GetInstance();
    579   int panel_count = manager->num_panels();
    580   content::WindowedNotificationObserver signal(
    581       chrome::NOTIFICATION_PANEL_CLOSED,
    582       content::Source<Panel>(panel));
    583   panel->Close();
    584   signal.Wait();
    585   // Now we have one less panel.
    586   EXPECT_EQ(panel_count - 1, manager->num_panels());
    587 
    588 #if defined(OS_MACOSX)
    589   // Mac window controllers may be autoreleased, and in the non-test
    590   // environment, may actually depend on the autorelease pool being recycled
    591   // with the run loop in order to perform important work. Replicate this in
    592   // the test environment.
    593   AutoreleasePool()->Recycle();
    594 
    595   // Make sure that everything has a chance to run.
    596   chrome::testing::NSRunLoopRunAllPending();
    597 #endif  // OS_MACOSX
    598 }
    599 
    600 void BasePanelBrowserTest::MoveMouseAndWaitForExpansionStateChange(
    601     Panel* panel,
    602     const gfx::Point& position) {
    603   content::WindowedNotificationObserver signal(
    604       chrome::NOTIFICATION_PANEL_CHANGED_EXPANSION_STATE,
    605       content::Source<Panel>(panel));
    606   MoveMouse(position);
    607   signal.Wait();
    608 }
    609 
    610 void BasePanelBrowserTest::MoveMouse(const gfx::Point& position) {
    611   PanelManager::GetInstance()->mouse_watcher()->NotifyMouseMovement(position);
    612 }
    613 
    614 std::string BasePanelBrowserTest::MakePanelName(int index) {
    615   std::string panel_name("Panel");
    616   return panel_name + base::IntToString(index);
    617 }
    618 
    619 bool BasePanelBrowserTest::WmSupportWindowActivation() {
    620   return true;
    621 }
    622