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/extension_system.h"
     34 #include "extensions/browser/install_flag.h"
     35 #include "extensions/common/manifest_constants.h"
     36 #include "sync/api/string_ordinal.h"
     37 
     38 #if defined(OS_LINUX)
     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 void BasePanelBrowserTest::SetUpCommandLine(CommandLine* command_line) {
    249   command_line->AppendSwitch(switches::kEnablePanels);
    250 }
    251 
    252 void BasePanelBrowserTest::SetUpOnMainThread() {
    253   InProcessBrowserTest::SetUpOnMainThread();
    254 
    255   // Setup the work area and desktop bar so that we have consistent testing
    256   // environment for all panel related tests.
    257   if (mock_display_settings_enabled_) {
    258     mock_display_settings_provider_ = new MockDisplaySettingsProviderImpl();
    259     mock_display_settings_provider_->SetPrimaryDisplay(
    260         kTestingPrimaryDisplayArea, kTestingPrimaryWorkArea);
    261     PanelManager::SetDisplaySettingsProviderForTesting(
    262         mock_display_settings_provider_);
    263   }
    264 
    265   PanelManager* panel_manager = PanelManager::GetInstance();
    266   panel_manager->enable_auto_sizing(false);
    267 
    268   PanelManager::shorten_time_intervals_for_testing();
    269 
    270   // Simulate the mouse movement so that tests are not affected by actual mouse
    271   // events.
    272   PanelMouseWatcher* mouse_watcher = new TestPanelMouseWatcher();
    273   panel_manager->SetMouseWatcherForTesting(mouse_watcher);
    274 
    275   // This is needed so the subsequently created panels can be activated.
    276   // On a Mac, it transforms background-only test process into foreground one.
    277   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    278 }
    279 
    280 void BasePanelBrowserTest::WaitForPanelActiveState(
    281     Panel* panel, ActiveState expected_state) {
    282   DCHECK(expected_state == SHOW_AS_ACTIVE ||
    283          expected_state == SHOW_AS_INACTIVE);
    284 
    285 #if defined(OS_MACOSX)
    286   scoped_ptr<NativePanelTesting> panel_testing(
    287       CreateNativePanelTesting(panel));
    288   ASSERT_TRUE(panel_testing->EnsureApplicationRunOnForeground()) <<
    289       "Failed to bring application to foreground. Bail out.";
    290 #endif
    291 
    292   PanelActiveStateObserver signal(panel, expected_state == SHOW_AS_ACTIVE);
    293   signal.Wait();
    294 }
    295 
    296 void BasePanelBrowserTest::WaitForWindowSizeAvailable(Panel* panel) {
    297   scoped_ptr<NativePanelTesting> panel_testing(
    298       CreateNativePanelTesting(panel));
    299   content::WindowedNotificationObserver signal(
    300       chrome::NOTIFICATION_PANEL_WINDOW_SIZE_KNOWN,
    301       content::Source<Panel>(panel));
    302   if (panel_testing->IsWindowSizeKnown())
    303     return;
    304   signal.Wait();
    305   EXPECT_TRUE(panel_testing->IsWindowSizeKnown());
    306 }
    307 
    308 void BasePanelBrowserTest::WaitForBoundsAnimationFinished(Panel* panel) {
    309   scoped_ptr<NativePanelTesting> panel_testing(
    310       CreateNativePanelTesting(panel));
    311   // Sometimes there are several animations in sequence due to content
    312   // auto resizing. Wait for all animations to finish.
    313   while (panel_testing->IsAnimatingBounds()) {
    314     content::WindowedNotificationObserver signal(
    315         chrome::NOTIFICATION_PANEL_BOUNDS_ANIMATIONS_FINISHED,
    316         content::Source<Panel>(panel));
    317     if (!panel_testing->IsAnimatingBounds())
    318       return;
    319     signal.Wait();
    320   }
    321 }
    322 
    323 BasePanelBrowserTest::CreatePanelParams::CreatePanelParams(
    324     const std::string& name,
    325     const gfx::Rect& bounds,
    326     ActiveState show_flag)
    327     : name(name),
    328       bounds(bounds),
    329       show_flag(show_flag),
    330       wait_for_fully_created(true),
    331       expected_active_state(show_flag),
    332       create_mode(PanelManager::CREATE_AS_DOCKED),
    333       profile(NULL) {
    334 }
    335 
    336 Panel* BasePanelBrowserTest::CreatePanelWithParams(
    337     const CreatePanelParams& params) {
    338 #if defined(OS_MACOSX)
    339   // Opening panels on a Mac causes NSWindowController of the Panel window
    340   // to be autoreleased. We need a pool drained after it's done so the test
    341   // can close correctly. The NSWindowController of the Panel window controls
    342   // lifetime of the Panel object so we want to release it as soon as
    343   // possible. In real Chrome, this is done by message pump.
    344   // On non-Mac platform, this is an empty class.
    345   base::mac::ScopedNSAutoreleasePool autorelease_pool;
    346 #endif
    347 
    348   content::WindowedNotificationObserver observer(
    349       content::NOTIFICATION_LOAD_STOP,
    350       content::NotificationService::AllSources());
    351 
    352   PanelManager* manager = PanelManager::GetInstance();
    353   Panel* panel = manager->CreatePanel(
    354       params.name,
    355       params.profile ? params.profile : browser()->profile(),
    356       params.url,
    357       params.bounds,
    358       params.create_mode);
    359 
    360   if (!params.url.is_empty())
    361     observer.Wait();
    362 
    363   if (!manager->auto_sizing_enabled() ||
    364       params.bounds.width() || params.bounds.height()) {
    365     EXPECT_FALSE(panel->auto_resizable());
    366   } else {
    367     EXPECT_TRUE(panel->auto_resizable());
    368   }
    369 
    370   if (params.show_flag == SHOW_AS_ACTIVE) {
    371     panel->Show();
    372   } else {
    373     panel->ShowInactive();
    374   }
    375 
    376   if (params.wait_for_fully_created) {
    377     base::MessageLoopForUI::current()->RunUntilIdle();
    378 
    379 #if defined(OS_LINUX) && defined(USE_X11)
    380     // On bots, we might have a simple window manager which always activates new
    381     // windows, and can't always deactivate them. Re-activate the main tabbed
    382     // browser to "deactivate" the newly created panel.
    383     if (params.expected_active_state == SHOW_AS_INACTIVE &&
    384         ui::GuessWindowManager() == ui::WM_ICE_WM) {
    385       // Wait for new panel to become active before deactivating to ensure
    386       // the activated notification is consumed before we wait for the panel
    387       // to become inactive.
    388       WaitForPanelActiveState(panel, SHOW_AS_ACTIVE);
    389       browser()->window()->Activate();
    390     }
    391 #endif
    392     // More waiting, because gaining or losing focus may require inter-process
    393     // asynchronous communication, and it is not enough to just run the local
    394     // message loop to make sure this activity has completed.
    395     WaitForPanelActiveState(panel, params.expected_active_state);
    396 
    397     // On Linux, window size is not available right away and we should wait
    398     // before moving forward with the test.
    399     WaitForWindowSizeAvailable(panel);
    400 
    401     // Wait for the bounds animations on creation to finish.
    402     WaitForBoundsAnimationFinished(panel);
    403   }
    404 
    405   return panel;
    406 }
    407 
    408 Panel* BasePanelBrowserTest::CreatePanelWithBounds(
    409     const std::string& panel_name, const gfx::Rect& bounds) {
    410   CreatePanelParams params(panel_name, bounds, SHOW_AS_ACTIVE);
    411   return CreatePanelWithParams(params);
    412 }
    413 
    414 Panel* BasePanelBrowserTest::CreatePanel(const std::string& panel_name) {
    415   CreatePanelParams params(panel_name, gfx::Rect(), SHOW_AS_ACTIVE);
    416   return CreatePanelWithParams(params);
    417 }
    418 
    419 Panel* BasePanelBrowserTest::CreateDockedPanel(const std::string& name,
    420                                                const gfx::Rect& bounds) {
    421   Panel* panel = CreatePanelWithBounds(name, bounds);
    422   EXPECT_EQ(PanelCollection::DOCKED, panel->collection()->type());
    423   return panel;
    424 }
    425 
    426 Panel* BasePanelBrowserTest::CreateDetachedPanel(const std::string& name,
    427                                                  const gfx::Rect& bounds) {
    428   Panel* panel = CreatePanelWithBounds(name, bounds);
    429   PanelManager* panel_manager = panel->manager();
    430   panel_manager->MovePanelToCollection(panel,
    431                                        panel_manager->detached_collection(),
    432                                        PanelCollection::DEFAULT_POSITION);
    433   EXPECT_EQ(PanelCollection::DETACHED, panel->collection()->type());
    434   // The panel is first created as docked panel, which ignores the specified
    435   // origin in |bounds|. We need to reposition the panel after it becomes
    436   // detached.
    437   panel->SetPanelBounds(bounds);
    438   WaitForBoundsAnimationFinished(panel);
    439   return panel;
    440 }
    441 
    442 Panel* BasePanelBrowserTest::CreateStackedPanel(const std::string& name,
    443                                                 const gfx::Rect& bounds,
    444                                                 StackedPanelCollection* stack) {
    445   Panel* panel = CreateDetachedPanel(name, bounds);
    446   panel->manager()->MovePanelToCollection(
    447       panel,
    448       stack,
    449       static_cast<PanelCollection::PositioningMask>(
    450           PanelCollection::DEFAULT_POSITION |
    451           PanelCollection::COLLAPSE_TO_FIT));
    452   EXPECT_EQ(PanelCollection::STACKED, panel->collection()->type());
    453   WaitForBoundsAnimationFinished(panel);
    454   return panel;
    455 }
    456 
    457 Panel* BasePanelBrowserTest::CreateInactivePanel(const std::string& name) {
    458   // Create an active panel first, instead of inactive panel. This is because
    459   // certain window managers on Linux, like icewm, will always activate the
    460   // new window.
    461   Panel* panel = CreatePanel(name);
    462 
    463   DeactivatePanel(panel);
    464   WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
    465 
    466   return panel;
    467 }
    468 
    469 Panel* BasePanelBrowserTest::CreateInactiveDockedPanel(
    470     const std::string& name, const gfx::Rect& bounds) {
    471   // Create an active panel first, instead of inactive panel. This is because
    472   // certain window managers on Linux, like icewm, will always activate the
    473   // new window.
    474   Panel* panel = CreateDockedPanel(name, bounds);
    475 
    476   DeactivatePanel(panel);
    477   WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
    478 
    479   return panel;
    480 }
    481 
    482 Panel* BasePanelBrowserTest::CreateInactiveDetachedPanel(
    483     const std::string& name, const gfx::Rect& bounds) {
    484   // Create an active panel first, instead of inactive panel. This is because
    485   // certain window managers on Linux, like icewm, will always activate the
    486   // new window.
    487   Panel* panel = CreateDetachedPanel(name, bounds);
    488 
    489   DeactivatePanel(panel);
    490   WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
    491 
    492   return panel;
    493 }
    494 
    495 void BasePanelBrowserTest::ActivatePanel(Panel* panel) {
    496   // For certain window managers on Linux, the window activation/deactivation
    497   // signals might not be sent. To work around this, we explicitly deactivate
    498   // all other panels first.
    499 #if defined(OS_LINUX)
    500   std::vector<Panel*> panels = PanelManager::GetInstance()->panels();
    501   for (std::vector<Panel*>::const_iterator iter = panels.begin();
    502        iter != panels.end(); ++iter) {
    503     Panel* current_panel = *iter;
    504     if (panel != current_panel)
    505       current_panel->Deactivate();
    506   }
    507 #endif
    508 
    509   panel->Activate();
    510 }
    511 
    512 void BasePanelBrowserTest::DeactivatePanel(Panel* panel) {
    513 #if defined(OS_LINUX)
    514   // For certain window managers on Linux, like icewm, panel activation and
    515   // deactivation notification might not get tiggered when non-panel window is
    516   // activated or deactivated. So we deactivate the panel directly.
    517   panel->Deactivate();
    518 #else
    519   // Make the panel lose focus by activating the browser window. This is
    520   // because:
    521   // 1) On Windows, deactivating the panel window might cause the application
    522   //    to lose the foreground status. When this occurs, trying to activate
    523   //    the panel window again will not be allowed by the system.
    524   // 2) On MacOS, deactivating a window is not supported by Cocoa.
    525   browser()->window()->Activate();
    526 #endif
    527 }
    528 
    529 // static
    530 NativePanelTesting* BasePanelBrowserTest::CreateNativePanelTesting(
    531     Panel* panel) {
    532   return panel->native_panel()->CreateNativePanelTesting();
    533 }
    534 
    535 scoped_refptr<Extension> BasePanelBrowserTest::CreateExtension(
    536     const base::FilePath::StringType& path,
    537     extensions::Manifest::Location location,
    538     const base::DictionaryValue& extra_value) {
    539   extensions::ExtensionPrefs* extension_prefs =
    540       extensions::ExtensionPrefs::Get(browser()->profile());
    541   base::FilePath full_path = extension_prefs->install_directory().Append(path);
    542 
    543   scoped_ptr<base::DictionaryValue> input_value(extra_value.DeepCopy());
    544   input_value->SetString(extensions::manifest_keys::kVersion, "1.0.0.0");
    545   input_value->SetString(extensions::manifest_keys::kName, "Sample Extension");
    546 
    547   std::string error;
    548   scoped_refptr<Extension> extension = Extension::Create(
    549       full_path,  location, *input_value, Extension::NO_FLAGS, &error);
    550   EXPECT_TRUE(extension.get());
    551   EXPECT_STREQ("", error.c_str());
    552   extensions::ExtensionSystem::Get(
    553       browser()->profile())->extension_service()->OnExtensionInstalled(
    554           extension.get(),
    555           syncer::StringOrdinal(),
    556           extensions::kInstallFlagInstallImmediately);
    557   return extension;
    558 }
    559 
    560 void BasePanelBrowserTest::CloseWindowAndWait(Panel* panel) {
    561   // Closing a panel may involve several async tasks. Need to use
    562   // message pump and wait for the notification.
    563   PanelManager* manager = PanelManager::GetInstance();
    564   int panel_count = manager->num_panels();
    565   content::WindowedNotificationObserver signal(
    566       chrome::NOTIFICATION_PANEL_CLOSED,
    567       content::Source<Panel>(panel));
    568   panel->Close();
    569   signal.Wait();
    570   // Now we have one less panel.
    571   EXPECT_EQ(panel_count - 1, manager->num_panels());
    572 
    573 #if defined(OS_MACOSX)
    574   // Mac window controllers may be autoreleased, and in the non-test
    575   // environment, may actually depend on the autorelease pool being recycled
    576   // with the run loop in order to perform important work. Replicate this in
    577   // the test environment.
    578   AutoreleasePool()->Recycle();
    579 
    580   // Make sure that everything has a chance to run.
    581   chrome::testing::NSRunLoopRunAllPending();
    582 #endif  // OS_MACOSX
    583 }
    584 
    585 void BasePanelBrowserTest::MoveMouseAndWaitForExpansionStateChange(
    586     Panel* panel,
    587     const gfx::Point& position) {
    588   content::WindowedNotificationObserver signal(
    589       chrome::NOTIFICATION_PANEL_CHANGED_EXPANSION_STATE,
    590       content::Source<Panel>(panel));
    591   MoveMouse(position);
    592   signal.Wait();
    593 }
    594 
    595 void BasePanelBrowserTest::MoveMouse(const gfx::Point& position) {
    596   PanelManager::GetInstance()->mouse_watcher()->NotifyMouseMovement(position);
    597 }
    598 
    599 std::string BasePanelBrowserTest::MakePanelName(int index) {
    600   std::string panel_name("Panel");
    601   return panel_name + base::IntToString(index);
    602 }
    603 
    604 bool BasePanelBrowserTest::WmSupportWindowActivation() {
    605   return true;
    606 }
    607