1// Copyright 2013 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#import "chrome/browser/ui/cocoa/extensions/extension_action_context_menu_controller.h" 6 7#include "base/files/file_path.h" 8#include "base/json/json_file_value_serializer.h" 9#include "base/path_service.h" 10#include "base/prefs/pref_service.h" 11#include "chrome/browser/extensions/browser_action_test_util.h" 12#include "chrome/browser/extensions/extension_action.h" 13#include "chrome/browser/extensions/extension_action_manager.h" 14#include "chrome/browser/extensions/extension_browsertest.h" 15#include "chrome/browser/extensions/extension_tab_util.h" 16#include "chrome/browser/profiles/profile.h" 17#include "chrome/browser/ui/browser.h" 18#include "chrome/browser/ui/cocoa/browser_window_cocoa.h" 19#include "chrome/browser/ui/cocoa/browser_window_controller.h" 20#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" 21#include "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" 22#include "chrome/browser/ui/tabs/tab_strip_model.h" 23#include "chrome/common/chrome_paths.h" 24#include "chrome/common/pref_names.h" 25#include "content/public/browser/devtools_manager.h" 26#include "content/public/test/test_utils.h" 27#include "extensions/common/extension.h" 28#include "grit/generated_resources.h" 29#include "ui/base/l10n/l10n_util_mac.h" 30 31using extensions::Extension; 32 33namespace { 34 35NSMenuItem* GetInspectItem(NSMenu* menu) { 36 return [menu itemWithTitle: 37 l10n_util::GetNSStringWithFixup(IDS_EXTENSION_ACTION_INSPECT_POPUP)]; 38} 39 40} // namespace 41 42class ExtensionActionContextMenuControllerTest : public ExtensionBrowserTest { 43 public: 44 ExtensionActionContextMenuControllerTest() : extension_(NULL), action_(NULL) { 45 } 46 47 protected: 48 void SetupPageAction() { 49 extension_ = InstallExtension( 50 test_data_dir_.AppendASCII("browsertest") 51 .AppendASCII("page_action_popup"), 52 1); 53 EXPECT_TRUE(extension_); 54 extensions::ExtensionActionManager* action_manager = 55 extensions::ExtensionActionManager::Get(browser()->profile()); 56 action_ = action_manager->GetPageAction(*extension_); 57 EXPECT_TRUE(action_); 58 59 content::WebContents* contents = 60 browser()->tab_strip_model()->GetActiveWebContents(); 61 action_->SetIsVisible(extensions::ExtensionTabUtil::GetTabId(contents), 62 true); 63 64 BrowserWindowCocoa* window = 65 static_cast<BrowserWindowCocoa*>(browser()->window()); 66 ToolbarController* toolbarController = 67 [window->cocoa_controller() toolbarController]; 68 LocationBarViewMac* locationBarView = 69 [toolbarController locationBarBridge]; 70 locationBarView->Update(NULL); 71 } 72 73 const Extension* extension_; 74 ExtensionAction* action_; 75}; 76 77IN_PROC_BROWSER_TEST_F(ExtensionActionContextMenuControllerTest, BasicTest) { 78 SetupPageAction(); 79 base::scoped_nsobject<ExtensionActionContextMenuController> controller( 80 [[ExtensionActionContextMenuController alloc] initWithExtension:extension_ 81 browser:browser() 82 extensionAction:action_]); 83 84 85 PrefService* service = browser()->profile()->GetPrefs(); 86 bool original = service->GetBoolean(prefs::kExtensionsUIDeveloperMode); 87 88 service->SetBoolean(prefs::kExtensionsUIDeveloperMode, true); 89 base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]); 90 [controller populateMenu:menu]; 91 EXPECT_GT([menu numberOfItems], 0); 92 EXPECT_TRUE(GetInspectItem(menu)); 93 94 service->SetBoolean(prefs::kExtensionsUIDeveloperMode, false); 95 [menu removeAllItems]; 96 [controller populateMenu:menu]; 97 EXPECT_GT([menu numberOfItems], 0); 98 EXPECT_FALSE(GetInspectItem(menu)); 99 100 service->SetBoolean(prefs::kExtensionsUIDeveloperMode, original); 101} 102 103// Test that browser action context menus work. Browser actions have their 104// menus created during browser initialization, when there is no tab. This 105// test simulates that and checks the menu is operational. 106IN_PROC_BROWSER_TEST_F(ExtensionActionContextMenuControllerTest, 107 BrowserAction) { 108 extension_ = 109 InstallExtension(test_data_dir_.AppendASCII("browsertest").AppendASCII( 110 "browser_action_popup"), 111 1); 112 EXPECT_TRUE(extension_); 113 extensions::ExtensionActionManager* action_manager = 114 extensions::ExtensionActionManager::Get(browser()->profile()); 115 action_ = action_manager->GetBrowserAction(*extension_); 116 EXPECT_TRUE(action_); 117 118 Browser* empty_browser( 119 new Browser(Browser::CreateParams(browser()->profile(), 120 browser()->host_desktop_type()))); 121 122 base::scoped_nsobject<ExtensionActionContextMenuController> controller( 123 [[ExtensionActionContextMenuController alloc] 124 initWithExtension:extension_ 125 browser:empty_browser 126 extensionAction:action_]); 127 base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]); 128 [controller populateMenu:menu]; 129 EXPECT_GT([menu numberOfItems], 0); 130 131 // Close the empty browser. Can't just free it directly because there are 132 // dangling references in the various native controllers that must be 133 // cleaned up first. 134 NSWindow* window = empty_browser->window()->GetNativeWindow(); 135 BrowserWindowController* wc = 136 [BrowserWindowController browserWindowControllerForWindow:window]; 137 ASSERT_TRUE(wc != NULL); 138 [wc destroyBrowser]; 139} 140 141namespace { 142 143class DevToolsAttachedObserver { 144 public: 145 DevToolsAttachedObserver(const base::Closure& callback) 146 : callback_(callback), 147 devtools_callback_(base::Bind( 148 &DevToolsAttachedObserver::OnDevToolsStateChanged, 149 base::Unretained(this))) { 150 content::DevToolsManager::GetInstance()->AddAgentStateCallback( 151 devtools_callback_); 152 } 153 154 ~DevToolsAttachedObserver() { 155 content::DevToolsManager::GetInstance()->RemoveAgentStateCallback( 156 devtools_callback_); 157 } 158 159 void OnDevToolsStateChanged(content::DevToolsAgentHost*, bool attached) { 160 if (attached) 161 callback_.Run(); 162 } 163 164 private: 165 base::Closure callback_; 166 base::Callback<void(content::DevToolsAgentHost*, bool)> devtools_callback_; 167 168 DISALLOW_COPY_AND_ASSIGN(DevToolsAttachedObserver); 169}; 170 171} // namespace 172 173IN_PROC_BROWSER_TEST_F( 174 ExtensionActionContextMenuControllerTest, DISABLED_RunInspectPopup) { 175 SetupPageAction(); 176 base::scoped_nsobject<ExtensionActionContextMenuController> controller( 177 [[ExtensionActionContextMenuController alloc] initWithExtension:extension_ 178 browser:browser() 179 extensionAction:action_]); 180 181 PrefService* service = browser()->profile()->GetPrefs(); 182 bool original = service->GetBoolean(prefs::kExtensionsUIDeveloperMode); 183 184 service->SetBoolean(prefs::kExtensionsUIDeveloperMode, true); 185 186 base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]); 187 [controller populateMenu:menu]; 188 EXPECT_GT([menu numberOfItems], 0); 189 NSMenuItem* inspectItem = GetInspectItem(menu); 190 EXPECT_TRUE(inspectItem); 191 192 scoped_refptr<content::MessageLoopRunner> loop_runner( 193 new content::MessageLoopRunner); 194 DevToolsAttachedObserver observer(loop_runner->QuitClosure()); 195 [NSApp sendAction:[inspectItem action] 196 to:[inspectItem target] 197 from:inspectItem]; 198 loop_runner->Run(); 199 200 service->SetBoolean(prefs::kExtensionsUIDeveloperMode, original); 201} 202