Home | History | Annotate | Download | only in extensions
      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/active_tab_permission_granter.h"
      6 #include "chrome/browser/extensions/api/commands/command_service.h"
      7 #include "chrome/browser/extensions/browser_action_test_util.h"
      8 #include "chrome/browser/extensions/extension_action.h"
      9 #include "chrome/browser/extensions/extension_action_manager.h"
     10 #include "chrome/browser/extensions/extension_apitest.h"
     11 #include "chrome/browser/extensions/tab_helper.h"
     12 #include "chrome/browser/sessions/session_tab_helper.h"
     13 #include "chrome/browser/ui/browser.h"
     14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     15 #include "chrome/test/base/interactive_test_utils.h"
     16 #include "chrome/test/base/ui_test_utils.h"
     17 #include "content/public/browser/notification_service.h"
     18 #include "content/public/browser/web_contents.h"
     19 #include "content/public/test/browser_test_utils.h"
     20 #include "extensions/common/extension.h"
     21 #include "extensions/common/feature_switch.h"
     22 #include "extensions/common/permissions/permissions_data.h"
     23 
     24 using content::WebContents;
     25 
     26 namespace extensions {
     27 
     28 class CommandsApiTest : public ExtensionApiTest {
     29  public:
     30   CommandsApiTest() {}
     31   virtual ~CommandsApiTest() {}
     32 
     33  protected:
     34   BrowserActionTestUtil GetBrowserActionsBar() {
     35     return BrowserActionTestUtil(browser());
     36   }
     37 
     38   bool IsGrantedForTab(const Extension* extension,
     39                        const content::WebContents* web_contents) {
     40     return PermissionsData::HasAPIPermissionForTab(
     41         extension,
     42         SessionID::IdForTab(web_contents),
     43         APIPermission::kTab);
     44   }
     45 };
     46 
     47 class ScriptBadgesCommandsApiTest : public ExtensionApiTest {
     48  public:
     49   ScriptBadgesCommandsApiTest() {
     50     // We cannot add this to CommandsApiTest because then PageActions get
     51     // treated like BrowserActions and the PageAction test starts failing.
     52     FeatureSwitch::script_badges()->SetOverrideValue(
     53         FeatureSwitch::OVERRIDE_ENABLED);
     54   }
     55   virtual ~ScriptBadgesCommandsApiTest() {}
     56 };
     57 
     58 // Test the basic functionality of the Keybinding API:
     59 // - That pressing the shortcut keys should perform actions (activate the
     60 //   browser action or send an event).
     61 // - Note: Page action keybindings are tested in PageAction test below.
     62 // - The shortcut keys taken by one extension are not overwritten by the last
     63 //   installed extension.
     64 IN_PROC_BROWSER_TEST_F(CommandsApiTest, Basic) {
     65   ASSERT_TRUE(test_server()->Start());
     66   ASSERT_TRUE(RunExtensionTest("keybinding/basics")) << message_;
     67   const Extension* extension = GetSingleLoadedExtension();
     68   ASSERT_TRUE(extension) << message_;
     69 
     70   // Load this extension, which uses the same keybindings but sets the page
     71   // to different colors. This is so we can see that it doesn't interfere. We
     72   // don't test this extension in any other way (it should otherwise be
     73   // immaterial to this test).
     74   ASSERT_TRUE(RunExtensionTest("keybinding/conflicting")) << message_;
     75 
     76   // Test that there are two browser actions in the toolbar.
     77   ASSERT_EQ(2, GetBrowserActionsBar().NumberOfBrowserActions());
     78 
     79   ui_test_utils::NavigateToURL(browser(),
     80       test_server()->GetURL("files/extensions/test_file.txt"));
     81 
     82   // activeTab shouldn't have been granted yet.
     83   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
     84   ASSERT_TRUE(tab);
     85 
     86   EXPECT_FALSE(IsGrantedForTab(extension, tab));
     87 
     88   // Activate the shortcut (Ctrl+Shift+F).
     89   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
     90       browser(), ui::VKEY_F, true, true, false, false));
     91 
     92   // activeTab should now be granted.
     93   EXPECT_TRUE(IsGrantedForTab(extension, tab));
     94 
     95   // Verify the command worked.
     96   bool result = false;
     97   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
     98       tab,
     99       "setInterval(function(){"
    100       "  if(document.body.bgColor == 'red'){"
    101       "    window.domAutomationController.send(true)}}, 100)",
    102       &result));
    103   ASSERT_TRUE(result);
    104 
    105   // Activate the shortcut (Ctrl+Shift+Y).
    106   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    107       browser(), ui::VKEY_Y, true, true, false, false));
    108 
    109   result = false;
    110   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
    111       tab,
    112       "setInterval(function(){"
    113       "  if(document.body.bgColor == 'blue'){"
    114       "    window.domAutomationController.send(true)}}, 100)",
    115       &result));
    116   ASSERT_TRUE(result);
    117 }
    118 
    119 // Flaky on linux and chromeos, http://crbug.com/165825
    120 #if defined(OS_MACOSX) || defined(OS_WIN)
    121 #define MAYBE_PageAction PageAction
    122 #else
    123 #define MAYBE_PageAction DISABLED_PageAction
    124 #endif
    125 IN_PROC_BROWSER_TEST_F(CommandsApiTest, MAYBE_PageAction) {
    126   ASSERT_TRUE(test_server()->Start());
    127   ASSERT_TRUE(RunExtensionTest("keybinding/page_action")) << message_;
    128   const Extension* extension = GetSingleLoadedExtension();
    129   ASSERT_TRUE(extension) << message_;
    130 
    131   {
    132     // Load a page, the extension will detect the navigation and request to show
    133     // the page action icon.
    134     ResultCatcher catcher;
    135     ui_test_utils::NavigateToURL(browser(),
    136         test_server()->GetURL("files/extensions/test_file.txt"));
    137     ASSERT_TRUE(catcher.GetNextResult());
    138   }
    139 
    140   // Make sure it appears and is the right one.
    141   ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
    142   int tab_id = SessionTabHelper::FromWebContents(
    143       browser()->tab_strip_model()->GetActiveWebContents())->session_id().id();
    144   ExtensionAction* action =
    145       ExtensionActionManager::Get(browser()->profile())->
    146       GetPageAction(*extension);
    147   ASSERT_TRUE(action);
    148   EXPECT_EQ("Make this page red", action->GetTitle(tab_id));
    149 
    150   // Activate the shortcut (Alt+Shift+F).
    151   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    152       browser(), ui::VKEY_F, false, true, true, false));
    153 
    154   // Verify the command worked (the page action turns the page red).
    155   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
    156   bool result = false;
    157   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
    158       tab,
    159       "setInterval(function(){"
    160       "  if(document.body.bgColor == 'red'){"
    161       "    window.domAutomationController.send(true)}}, 100)",
    162       &result));
    163   ASSERT_TRUE(result);
    164 }
    165 
    166 // Checked-in in a disabled state, because the necessary functionality to
    167 // automatically verify that the test works hasn't been implemented for the
    168 // script badges yet (see http://crbug.com/140016). The test results, can be
    169 // verified manually by running the test and verifying that the synthesized
    170 // popup for script badges appear. When bug 140016 has been fixed, the popup
    171 // code can signal to the test that the test passed.
    172 // TODO(finnur): Enable this test once the bug is fixed.
    173 IN_PROC_BROWSER_TEST_F(ScriptBadgesCommandsApiTest, DISABLED_ScriptBadge) {
    174   ASSERT_TRUE(test_server()->Start());
    175   ASSERT_TRUE(RunExtensionTest("keybinding/script_badge")) << message_;
    176   const Extension* extension = GetSingleLoadedExtension();
    177   ASSERT_TRUE(extension) << message_;
    178 
    179   {
    180     ResultCatcher catcher;
    181     // Tell the extension to update the script badge state.
    182     ui_test_utils::NavigateToURL(
    183         browser(), GURL(extension->GetResourceURL("show.html")));
    184     ASSERT_TRUE(catcher.GetNextResult());
    185   }
    186 
    187   {
    188     ResultCatcher catcher;
    189     // Activate the shortcut (Ctrl+Shift+F).
    190     ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    191         browser(), ui::VKEY_F, true, true, false, false));
    192     ASSERT_TRUE(catcher.GetNextResult());
    193   }
    194 }
    195 
    196 // This test validates that the getAll query API function returns registered
    197 // commands as well as synthesized ones and that inactive commands (like the
    198 // synthesized ones are in nature) have no shortcuts.
    199 IN_PROC_BROWSER_TEST_F(CommandsApiTest, SynthesizedCommand) {
    200   ASSERT_TRUE(test_server()->Start());
    201   ASSERT_TRUE(RunExtensionTest("keybinding/synthesized")) << message_;
    202 }
    203 
    204 // This test validates that an extension cannot request a shortcut that is
    205 // already in use by Chrome.
    206 IN_PROC_BROWSER_TEST_F(CommandsApiTest, DontOverwriteSystemShortcuts) {
    207   ASSERT_TRUE(test_server()->Start());
    208 
    209   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    210 
    211   ASSERT_TRUE(RunExtensionTest("keybinding/dont_overwrite_system")) << message_;
    212 
    213   ui_test_utils::NavigateToURL(browser(),
    214       test_server()->GetURL("files/extensions/test_file.txt"));
    215 
    216   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
    217   ASSERT_TRUE(tab);
    218 
    219   // Activate the shortcut (Alt+Shift+F) to make page blue.
    220   {
    221     ResultCatcher catcher;
    222     ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    223         browser(), ui::VKEY_F, false, true, true, false));
    224     ASSERT_TRUE(catcher.GetNextResult());
    225   }
    226 
    227   bool result = false;
    228   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
    229       tab,
    230       "setInterval(function() {"
    231       "  if (document.body.bgColor == 'blue') {"
    232       "    window.domAutomationController.send(true)}}, 100)",
    233       &result));
    234   ASSERT_TRUE(result);
    235 
    236   // Activate the shortcut (Ctrl+F) to make page red (should not work).
    237   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    238       browser(), ui::VKEY_F, true, false, false, false));
    239 
    240   // The page should still be blue.
    241   result = false;
    242   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
    243       tab,
    244       "setInterval(function() {"
    245       "  if (document.body.bgColor == 'blue') {"
    246       "    window.domAutomationController.send(true)}}, 100)",
    247       &result));
    248   ASSERT_TRUE(result);
    249 }
    250 
    251 #if defined(OS_WIN)
    252 // Currently this feature is implemented on Windows only.
    253 #define MAYBE_AllowDuplicatedMediaKeys AllowDuplicatedMediaKeys
    254 #else
    255 #define MAYBE_AllowDuplicatedMediaKeys DISABLED_AllowDuplicatedMediaKeys
    256 #endif
    257 
    258 // Test that media keys go to all extensions that register for them.
    259 IN_PROC_BROWSER_TEST_F(CommandsApiTest, MAYBE_AllowDuplicatedMediaKeys) {
    260   ResultCatcher catcher;
    261   ASSERT_TRUE(RunExtensionTest("keybinding/non_global_media_keys_0"))
    262       << message_;
    263   ASSERT_TRUE(catcher.GetNextResult());
    264   ASSERT_TRUE(RunExtensionTest("keybinding/non_global_media_keys_1"))
    265       << message_;
    266   ASSERT_TRUE(catcher.GetNextResult());
    267 
    268   // Activate the Media Stop key.
    269   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    270       browser(), ui::VKEY_MEDIA_STOP, false, false, false, false));
    271 
    272   // We should get two success result.
    273   ASSERT_TRUE(catcher.GetNextResult());
    274   ASSERT_TRUE(catcher.GetNextResult());
    275 }
    276 
    277 // This test validates that update (including removal) of keybinding preferences
    278 // works correctly.
    279 IN_PROC_BROWSER_TEST_F(CommandsApiTest, UpdateKeybindingPrefsTest) {
    280 #if defined(OS_MACOSX)
    281   // Send "Tab" on OS X to move the focus, otherwise the omnibox will intercept
    282   // the key presses we send below.
    283   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    284       browser(), ui::VKEY_TAB, false, false, false, false));
    285 #endif
    286   ResultCatcher catcher;
    287   ASSERT_TRUE(RunExtensionTest("keybinding/command_update"));
    288   ASSERT_TRUE(catcher.GetNextResult());
    289   const Extension* extension = GetSingleLoadedExtension();
    290 
    291   CommandService* command_service = CommandService::Get(browser()->profile());
    292   extensions::CommandMap named_commands;
    293   command_service->GetNamedCommands(extension->id(),
    294                                     extensions::CommandService::ACTIVE_ONLY,
    295                                     extensions::CommandService::ANY_SCOPE,
    296                                     &named_commands);
    297   EXPECT_EQ(3u, named_commands.size());
    298 
    299   const char kCommandNameC[] = "command_C";
    300   command_service->RemoveKeybindingPrefs(extension->id(), kCommandNameC);
    301   command_service->GetNamedCommands(extension->id(),
    302                                     extensions::CommandService::ACTIVE_ONLY,
    303                                     extensions::CommandService::ANY_SCOPE,
    304                                     &named_commands);
    305   EXPECT_EQ(2u, named_commands.size());
    306 
    307   // Send "Alt+C", it shouldn't work because it has been removed.
    308   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    309       browser(), ui::VKEY_C, false, false, true, false));
    310 
    311   const char kCommandNameB[] = "command_B";
    312   const char kKeyStroke[] = "Alt+A";
    313   command_service->UpdateKeybindingPrefs(extension->id(),
    314                                          kCommandNameB,
    315                                          kKeyStroke);
    316   command_service->GetNamedCommands(extension->id(),
    317                                     extensions::CommandService::ACTIVE_ONLY,
    318                                     extensions::CommandService::ANY_SCOPE,
    319                                     &named_commands);
    320   EXPECT_EQ(1u, named_commands.size());
    321 
    322   // Activate the shortcut (Alt+A).
    323   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    324       browser(), ui::VKEY_A, false, false, true, false));
    325   ASSERT_TRUE(catcher.GetNextResult()) << message_;
    326 }
    327 
    328 }  // namespace extensions
    329