// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/active_tab_permission_granter.h"
#include "chrome/browser/extensions/api/commands/command_service.h"
#include "chrome/browser/extensions/browser_action_test_util.h"
#include "chrome/browser/extensions/extension_action.h"
#include "chrome/browser/extensions/extension_action_manager.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "extensions/common/extension.h"
#include "extensions/common/feature_switch.h"
#include "extensions/common/permissions/permissions_data.h"
using content::WebContents;
namespace extensions {
class CommandsApiTest : public ExtensionApiTest {
public:
CommandsApiTest() {}
virtual ~CommandsApiTest() {}
protected:
BrowserActionTestUtil GetBrowserActionsBar() {
return BrowserActionTestUtil(browser());
}
bool IsGrantedForTab(const Extension* extension,
const content::WebContents* web_contents) {
return PermissionsData::HasAPIPermissionForTab(
extension,
SessionID::IdForTab(web_contents),
APIPermission::kTab);
}
};
class ScriptBadgesCommandsApiTest : public ExtensionApiTest {
public:
ScriptBadgesCommandsApiTest() {
// We cannot add this to CommandsApiTest because then PageActions get
// treated like BrowserActions and the PageAction test starts failing.
FeatureSwitch::script_badges()->SetOverrideValue(
FeatureSwitch::OVERRIDE_ENABLED);
}
virtual ~ScriptBadgesCommandsApiTest() {}
};
// Test the basic functionality of the Keybinding API:
// - That pressing the shortcut keys should perform actions (activate the
// browser action or send an event).
// - Note: Page action keybindings are tested in PageAction test below.
// - The shortcut keys taken by one extension are not overwritten by the last
// installed extension.
IN_PROC_BROWSER_TEST_F(CommandsApiTest, Basic) {
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("keybinding/basics")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
// Load this extension, which uses the same keybindings but sets the page
// to different colors. This is so we can see that it doesn't interfere. We
// don't test this extension in any other way (it should otherwise be
// immaterial to this test).
ASSERT_TRUE(RunExtensionTest("keybinding/conflicting")) << message_;
// Test that there are two browser actions in the toolbar.
ASSERT_EQ(2, GetBrowserActionsBar().NumberOfBrowserActions());
ui_test_utils::NavigateToURL(browser(),
test_server()->GetURL("files/extensions/test_file.txt"));
// activeTab shouldn't have been granted yet.
WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(tab);
EXPECT_FALSE(IsGrantedForTab(extension, tab));
// Activate the shortcut (Ctrl+Shift+F).
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_F, true, true, false, false));
// activeTab should now be granted.
EXPECT_TRUE(IsGrantedForTab(extension, tab));
// Verify the command worked.
bool result = false;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
tab,
"setInterval(function(){"
" if(document.body.bgColor == 'red'){"
" window.domAutomationController.send(true)}}, 100)",
&result));
ASSERT_TRUE(result);
// Activate the shortcut (Ctrl+Shift+Y).
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_Y, true, true, false, false));
result = false;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
tab,
"setInterval(function(){"
" if(document.body.bgColor == 'blue'){"
" window.domAutomationController.send(true)}}, 100)",
&result));
ASSERT_TRUE(result);
}
// Flaky on linux and chromeos, http://crbug.com/165825
#if defined(OS_MACOSX) || defined(OS_WIN)
#define MAYBE_PageAction PageAction
#else
#define MAYBE_PageAction DISABLED_PageAction
#endif
IN_PROC_BROWSER_TEST_F(CommandsApiTest, MAYBE_PageAction) {
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("keybinding/page_action")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
{
// Load a page, the extension will detect the navigation and request to show
// the page action icon.
ResultCatcher catcher;
ui_test_utils::NavigateToURL(browser(),
test_server()->GetURL("files/extensions/test_file.txt"));
ASSERT_TRUE(catcher.GetNextResult());
}
// Make sure it appears and is the right one.
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
int tab_id = SessionTabHelper::FromWebContents(
browser()->tab_strip_model()->GetActiveWebContents())->session_id().id();
ExtensionAction* action =
ExtensionActionManager::Get(browser()->profile())->
GetPageAction(*extension);
ASSERT_TRUE(action);
EXPECT_EQ("Make this page red", action->GetTitle(tab_id));
// Activate the shortcut (Alt+Shift+F).
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_F, false, true, true, false));
// Verify the command worked (the page action turns the page red).
WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
bool result = false;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
tab,
"setInterval(function(){"
" if(document.body.bgColor == 'red'){"
" window.domAutomationController.send(true)}}, 100)",
&result));
ASSERT_TRUE(result);
}
// Checked-in in a disabled state, because the necessary functionality to
// automatically verify that the test works hasn't been implemented for the
// script badges yet (see http://crbug.com/140016). The test results, can be
// verified manually by running the test and verifying that the synthesized
// popup for script badges appear. When bug 140016 has been fixed, the popup
// code can signal to the test that the test passed.
// TODO(finnur): Enable this test once the bug is fixed.
IN_PROC_BROWSER_TEST_F(ScriptBadgesCommandsApiTest, DISABLED_ScriptBadge) {
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("keybinding/script_badge")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
{
ResultCatcher catcher;
// Tell the extension to update the script badge state.
ui_test_utils::NavigateToURL(
browser(), GURL(extension->GetResourceURL("show.html")));
ASSERT_TRUE(catcher.GetNextResult());
}
{
ResultCatcher catcher;
// Activate the shortcut (Ctrl+Shift+F).
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_F, true, true, false, false));
ASSERT_TRUE(catcher.GetNextResult());
}
}
// This test validates that the getAll query API function returns registered
// commands as well as synthesized ones and that inactive commands (like the
// synthesized ones are in nature) have no shortcuts.
IN_PROC_BROWSER_TEST_F(CommandsApiTest, SynthesizedCommand) {
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("keybinding/synthesized")) << message_;
}
// This test validates that an extension cannot request a shortcut that is
// already in use by Chrome.
IN_PROC_BROWSER_TEST_F(CommandsApiTest, DontOverwriteSystemShortcuts) {
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
ASSERT_TRUE(RunExtensionTest("keybinding/dont_overwrite_system")) << message_;
ui_test_utils::NavigateToURL(browser(),
test_server()->GetURL("files/extensions/test_file.txt"));
WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(tab);
// Activate the shortcut (Alt+Shift+F) to make page blue.
{
ResultCatcher catcher;
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_F, false, true, true, false));
ASSERT_TRUE(catcher.GetNextResult());
}
bool result = false;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
tab,
"setInterval(function() {"
" if (document.body.bgColor == 'blue') {"
" window.domAutomationController.send(true)}}, 100)",
&result));
ASSERT_TRUE(result);
// Activate the shortcut (Ctrl+F) to make page red (should not work).
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_F, true, false, false, false));
// The page should still be blue.
result = false;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
tab,
"setInterval(function() {"
" if (document.body.bgColor == 'blue') {"
" window.domAutomationController.send(true)}}, 100)",
&result));
ASSERT_TRUE(result);
}
#if defined(OS_WIN)
// Currently this feature is implemented on Windows only.
#define MAYBE_AllowDuplicatedMediaKeys AllowDuplicatedMediaKeys
#else
#define MAYBE_AllowDuplicatedMediaKeys DISABLED_AllowDuplicatedMediaKeys
#endif
// Test that media keys go to all extensions that register for them.
IN_PROC_BROWSER_TEST_F(CommandsApiTest, MAYBE_AllowDuplicatedMediaKeys) {
ResultCatcher catcher;
ASSERT_TRUE(RunExtensionTest("keybinding/non_global_media_keys_0"))
<< message_;
ASSERT_TRUE(catcher.GetNextResult());
ASSERT_TRUE(RunExtensionTest("keybinding/non_global_media_keys_1"))
<< message_;
ASSERT_TRUE(catcher.GetNextResult());
// Activate the Media Stop key.
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_MEDIA_STOP, false, false, false, false));
// We should get two success result.
ASSERT_TRUE(catcher.GetNextResult());
ASSERT_TRUE(catcher.GetNextResult());
}
// This test validates that update (including removal) of keybinding preferences
// works correctly.
IN_PROC_BROWSER_TEST_F(CommandsApiTest, UpdateKeybindingPrefsTest) {
#if defined(OS_MACOSX)
// Send "Tab" on OS X to move the focus, otherwise the omnibox will intercept
// the key presses we send below.
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_TAB, false, false, false, false));
#endif
ResultCatcher catcher;
ASSERT_TRUE(RunExtensionTest("keybinding/command_update"));
ASSERT_TRUE(catcher.GetNextResult());
const Extension* extension = GetSingleLoadedExtension();
CommandService* command_service = CommandService::Get(browser()->profile());
extensions::CommandMap named_commands;
command_service->GetNamedCommands(extension->id(),
extensions::CommandService::ACTIVE_ONLY,
extensions::CommandService::ANY_SCOPE,
&named_commands);
EXPECT_EQ(3u, named_commands.size());
const char kCommandNameC[] = "command_C";
command_service->RemoveKeybindingPrefs(extension->id(), kCommandNameC);
command_service->GetNamedCommands(extension->id(),
extensions::CommandService::ACTIVE_ONLY,
extensions::CommandService::ANY_SCOPE,
&named_commands);
EXPECT_EQ(2u, named_commands.size());
// Send "Alt+C", it shouldn't work because it has been removed.
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_C, false, false, true, false));
const char kCommandNameB[] = "command_B";
const char kKeyStroke[] = "Alt+A";
command_service->UpdateKeybindingPrefs(extension->id(),
kCommandNameB,
kKeyStroke);
command_service->GetNamedCommands(extension->id(),
extensions::CommandService::ACTIVE_ONLY,
extensions::CommandService::ANY_SCOPE,
&named_commands);
EXPECT_EQ(1u, named_commands.size());
// Activate the shortcut (Alt+A).
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_A, false, false, true, false));
ASSERT_TRUE(catcher.GetNextResult()) << message_;
}
} // namespace extensions