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/extensions/browser_event_router.h" 6 #include "chrome/browser/extensions/extension_action.h" 7 #include "chrome/browser/extensions/extension_action_icon_factory.h" 8 #include "chrome/browser/extensions/extension_action_manager.h" 9 #include "chrome/browser/extensions/extension_apitest.h" 10 #include "chrome/browser/extensions/extension_service.h" 11 #include "chrome/browser/extensions/extension_system.h" 12 #include "chrome/browser/extensions/extension_tab_util.h" 13 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/sessions/session_tab_helper.h" 15 #include "chrome/browser/ui/browser.h" 16 #include "chrome/browser/ui/browser_commands.h" 17 #include "chrome/browser/ui/browser_window.h" 18 #include "chrome/browser/ui/omnibox/location_bar.h" 19 #include "chrome/browser/ui/tabs/tab_strip_model.h" 20 #include "chrome/common/extensions/extension.h" 21 #include "chrome/test/base/ui_test_utils.h" 22 #include "content/public/browser/web_contents.h" 23 #include "content/public/test/browser_test_utils.h" 24 25 using content::WebContents; 26 27 namespace extensions { 28 namespace { 29 30 class PageActionApiTest : public ExtensionApiTest { 31 protected: 32 ExtensionAction* GetPageAction(const Extension& extension) { 33 return ExtensionActionManager::Get(browser()->profile())-> 34 GetPageAction(extension); 35 } 36 }; 37 38 IN_PROC_BROWSER_TEST_F(PageActionApiTest, Basic) { 39 ASSERT_TRUE(test_server()->Start()); 40 ASSERT_TRUE(RunExtensionTest("page_action/basics")) << message_; 41 const Extension* extension = GetSingleLoadedExtension(); 42 ASSERT_TRUE(extension) << message_; 43 { 44 // Tell the extension to update the page action state. 45 ResultCatcher catcher; 46 ui_test_utils::NavigateToURL(browser(), 47 GURL(extension->GetResourceURL("update.html"))); 48 ASSERT_TRUE(catcher.GetNextResult()); 49 } 50 51 // Test that we received the changes. 52 int tab_id = SessionTabHelper::FromWebContents( 53 browser()->tab_strip_model()->GetActiveWebContents())->session_id().id(); 54 ExtensionAction* action = GetPageAction(*extension); 55 ASSERT_TRUE(action); 56 EXPECT_EQ("Modified", action->GetTitle(tab_id)); 57 58 { 59 // Simulate the page action being clicked. 60 ResultCatcher catcher; 61 int tab_id = ExtensionTabUtil::GetTabId( 62 browser()->tab_strip_model()->GetActiveWebContents()); 63 ExtensionService* service = extensions::ExtensionSystem::Get( 64 browser()->profile())->extension_service(); 65 service->browser_event_router()->PageActionExecuted( 66 browser()->profile(), *action, tab_id, std::string(), 0); 67 EXPECT_TRUE(catcher.GetNextResult()); 68 } 69 70 { 71 // Tell the extension to update the page action state again. 72 ResultCatcher catcher; 73 ui_test_utils::NavigateToURL(browser(), 74 GURL(extension->GetResourceURL("update2.html"))); 75 ASSERT_TRUE(catcher.GetNextResult()); 76 } 77 78 // We should not be creating icons asynchronously, so we don't need an 79 // observer. 80 ExtensionActionIconFactory icon_factory(profile(), extension, action, NULL); 81 82 // Test that we received the changes. 83 tab_id = SessionTabHelper::FromWebContents( 84 browser()->tab_strip_model()->GetActiveWebContents())->session_id().id(); 85 EXPECT_FALSE(icon_factory.GetIcon(tab_id).IsEmpty()); 86 } 87 88 // Test that calling chrome.pageAction.setPopup() can enable a popup. 89 IN_PROC_BROWSER_TEST_F(PageActionApiTest, AddPopup) { 90 // Load the extension, which has no default popup. 91 ASSERT_TRUE(RunExtensionTest("page_action/add_popup")) << message_; 92 const Extension* extension = GetSingleLoadedExtension(); 93 ASSERT_TRUE(extension) << message_; 94 95 int tab_id = ExtensionTabUtil::GetTabId( 96 browser()->tab_strip_model()->GetActiveWebContents()); 97 98 ExtensionAction* page_action = GetPageAction(*extension); 99 ASSERT_TRUE(page_action) 100 << "Page action test extension should have a page action."; 101 102 ASSERT_FALSE(page_action->HasPopup(tab_id)); 103 104 // Simulate the page action being clicked. The resulting event should 105 // install a page action popup. 106 { 107 ResultCatcher catcher; 108 ExtensionService* service = extensions::ExtensionSystem::Get( 109 browser()->profile())->extension_service(); 110 service->browser_event_router()->PageActionExecuted( 111 browser()->profile(), *page_action, tab_id, std::string(), 1); 112 ASSERT_TRUE(catcher.GetNextResult()); 113 } 114 115 ASSERT_TRUE(page_action->HasPopup(tab_id)) 116 << "Clicking on the page action should have caused a popup to be added."; 117 118 ASSERT_STREQ("/a_popup.html", 119 page_action->GetPopupUrl(tab_id).path().c_str()); 120 121 // Now change the popup from a_popup.html to a_second_popup.html . 122 // Load a page which removes the popup using chrome.pageAction.setPopup(). 123 { 124 ResultCatcher catcher; 125 ui_test_utils::NavigateToURL( 126 browser(), 127 GURL(extension->GetResourceURL("change_popup.html"))); 128 ASSERT_TRUE(catcher.GetNextResult()); 129 } 130 131 ASSERT_TRUE(page_action->HasPopup(tab_id)); 132 ASSERT_STREQ("/another_popup.html", 133 page_action->GetPopupUrl(tab_id).path().c_str()); 134 } 135 136 // Test that calling chrome.pageAction.setPopup() can remove a popup. 137 IN_PROC_BROWSER_TEST_F(PageActionApiTest, RemovePopup) { 138 // Load the extension, which has a page action with a default popup. 139 ASSERT_TRUE(RunExtensionTest("page_action/remove_popup")) << message_; 140 const Extension* extension = GetSingleLoadedExtension(); 141 ASSERT_TRUE(extension) << message_; 142 143 int tab_id = ExtensionTabUtil::GetTabId( 144 browser()->tab_strip_model()->GetActiveWebContents()); 145 146 ExtensionAction* page_action = GetPageAction(*extension); 147 ASSERT_TRUE(page_action) 148 << "Page action test extension should have a page action."; 149 150 ASSERT_TRUE(page_action->HasPopup(tab_id)) 151 << "Expect a page action popup before the test removes it."; 152 153 // Load a page which removes the popup using chrome.pageAction.setPopup(). 154 { 155 ResultCatcher catcher; 156 ui_test_utils::NavigateToURL( 157 browser(), 158 GURL(extension->GetResourceURL("remove_popup.html"))); 159 ASSERT_TRUE(catcher.GetNextResult()); 160 } 161 162 ASSERT_FALSE(page_action->HasPopup(tab_id)) 163 << "Page action popup should have been removed."; 164 } 165 166 // Tests old-style pageActions API that is deprecated but we don't want to 167 // break. 168 IN_PROC_BROWSER_TEST_F(PageActionApiTest, OldPageActions) { 169 ASSERT_TRUE(RunExtensionTestAllowOldManifestVersion("page_action/old_api")) << 170 message_; 171 const Extension* extension = GetSingleLoadedExtension(); 172 ASSERT_TRUE(extension) << message_; 173 174 // Have the extension enable the page action. 175 { 176 ResultCatcher catcher; 177 ui_test_utils::NavigateToURL(browser(), 178 GURL(extension->GetResourceURL("page.html"))); 179 ASSERT_TRUE(catcher.GetNextResult()); 180 } 181 182 // Simulate the page action being clicked. 183 { 184 ResultCatcher catcher; 185 int tab_id = ExtensionTabUtil::GetTabId( 186 browser()->tab_strip_model()->GetActiveWebContents()); 187 ExtensionService* service = extensions::ExtensionSystem::Get( 188 browser()->profile())->extension_service(); 189 ExtensionAction* page_action = GetPageAction(*extension); 190 service->browser_event_router()->PageActionExecuted( 191 browser()->profile(), *page_action, tab_id, std::string(), 1); 192 EXPECT_TRUE(catcher.GetNextResult()); 193 } 194 } 195 196 // Tests popups in page actions. 197 // Flaky on the trybots. See http://crbug.com/96725. 198 IN_PROC_BROWSER_TEST_F(PageActionApiTest, DISABLED_ShowPageActionPopup) { 199 ASSERT_TRUE(RunExtensionTest("page_action/popup")) << message_; 200 const Extension* extension = GetSingleLoadedExtension(); 201 ASSERT_TRUE(extension) << message_; 202 203 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1)); 204 205 { 206 ResultCatcher catcher; 207 LocationBarTesting* location_bar = 208 browser()->window()->GetLocationBar()->GetLocationBarForTesting(); 209 location_bar->TestPageActionPressed(0); 210 ASSERT_TRUE(catcher.GetNextResult()); 211 } 212 } 213 214 // Test http://crbug.com/57333: that two page action extensions using the same 215 // icon for the page action icon and the extension icon do not crash. 216 IN_PROC_BROWSER_TEST_F(PageActionApiTest, TestCrash57333) { 217 // Load extension A. 218 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("page_action") 219 .AppendASCII("crash_57333") 220 .AppendASCII("Extension1"))); 221 // Load extension B. 222 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("page_action") 223 .AppendASCII("crash_57333") 224 .AppendASCII("Extension2"))); 225 } 226 227 IN_PROC_BROWSER_TEST_F(PageActionApiTest, Getters) { 228 ASSERT_TRUE(RunExtensionTest("page_action/getters")) << message_; 229 const Extension* extension = GetSingleLoadedExtension(); 230 ASSERT_TRUE(extension) << message_; 231 232 ResultCatcher catcher; 233 ui_test_utils::NavigateToURL(browser(), 234 GURL(extension->GetResourceURL("update.html"))); 235 ASSERT_TRUE(catcher.GetNextResult()); 236 } 237 238 // Verify triggering page action. 239 IN_PROC_BROWSER_TEST_F(PageActionApiTest, TestTriggerPageAction) { 240 ASSERT_TRUE(test_server()->Start()); 241 242 ASSERT_TRUE(RunExtensionTest("trigger_actions/page_action")) << message_; 243 const Extension* extension = GetSingleLoadedExtension(); 244 ASSERT_TRUE(extension) << message_; 245 246 // Page action icon is displayed when a tab is created. 247 ui_test_utils::NavigateToURL(browser(), 248 test_server()->GetURL("files/simple.html")); 249 chrome::NewTab(browser()); 250 browser()->tab_strip_model()->ActivateTabAt(0, true); 251 252 ExtensionAction* page_action = GetPageAction(*extension); 253 ASSERT_TRUE(page_action); 254 255 { 256 // Simulate the page action being clicked. 257 ResultCatcher catcher; 258 int tab_id = ExtensionTabUtil::GetTabId( 259 browser()->tab_strip_model()->GetActiveWebContents()); 260 ExtensionService* service = extensions::ExtensionSystem::Get( 261 browser()->profile())->extension_service(); 262 service->browser_event_router()->PageActionExecuted( 263 browser()->profile(), *page_action, tab_id, std::string(), 0); 264 EXPECT_TRUE(catcher.GetNextResult()); 265 } 266 267 WebContents* tab = 268 browser()->tab_strip_model()->GetActiveWebContents(); 269 EXPECT_TRUE(tab != NULL); 270 271 // Verify that the browser action turned the background color red. 272 const std::string script = 273 "window.domAutomationController.send(document.body.style." 274 "backgroundColor);"; 275 std::string result; 276 const std::string frame_xpath; 277 EXPECT_TRUE(content::ExecuteScriptInFrameAndExtractString( 278 tab, frame_xpath, script, &result)); 279 EXPECT_EQ(result, "red"); 280 } 281 282 } // namespace 283 } // namespace extensions 284