blob: e56b1bea9053185436c7c1de60b6778b02ab3440 [file] [log] [blame]
// 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 "base/command_line.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/panels/native_panel.h"
#include "chrome/browser/ui/panels/panel.h"
#include "chrome/browser/ui/panels/panel_constants.h"
#include "chrome/browser/ui/panels/panel_manager.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/test_utils.h"
#include "extensions/common/extension.h"
#include "extensions/test/extension_test_message_listener.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_MACOSX)
#include "base/mac/scoped_nsautorelease_pool.h"
#endif
using extensions::Extension;
class PanelExtensionBrowserTest : public ExtensionBrowserTest {
protected:
void SetUpCommandLine(CommandLine* command_line) override {
ExtensionBrowserTest::SetUpCommandLine(command_line);
command_line->AppendSwitch(switches::kEnablePanels);
PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
test_data_dir_ = test_data_dir_.AppendASCII("panels");
}
Panel* CreatePanelFromExtension(const Extension* extension) const {
#if defined(OS_MACOSX)
// Opening panels on a Mac causes NSWindowController of the Panel window
// to be autoreleased. We need a pool drained after it's done so the test
// can close correctly. The NSWindowController of the Panel window controls
// lifetime of the Panel object so we want to release it as soon as
// possible. In real Chrome, this is done by message pump.
// On non-Mac platform, this is an empty class.
base::mac::ScopedNSAutoreleasePool autorelease_pool;
#endif
Panel* panel = PanelManager::GetInstance()->CreatePanel(
web_app::GenerateApplicationNameFromExtensionId(extension->id()),
browser()->profile(),
GURL(),
gfx::Rect(),
PanelManager::CREATE_AS_DETACHED);
panel->ShowInactive();
return panel;
}
void WaitForAppIconAvailable(Panel* panel) const {
content::WindowedNotificationObserver signal(
chrome::NOTIFICATION_PANEL_APP_ICON_LOADED,
content::Source<Panel>(panel));
if (!panel->app_icon().IsEmpty())
return;
signal.Wait();
EXPECT_FALSE(panel->app_icon().IsEmpty());
}
static NativePanelTesting* CreateNativePanelTesting(Panel* panel) {
return panel->native_panel()->CreateNativePanelTesting();
}
};
// TODO(jschuh): Hanging plugin tests. crbug.com/244653
#if !defined(OS_WIN) && !defined(ARCH_CPU_X86_64)
IN_PROC_BROWSER_TEST_F(PanelExtensionBrowserTest, PanelAppIcon) {
const Extension* extension =
LoadExtension(test_data_dir_.AppendASCII("test_extension"));
Panel* panel = CreatePanelFromExtension(extension);
// Wait for the app icon gets fully loaded.
WaitForAppIconAvailable(panel);
// First verify on the panel level.
gfx::ImageSkia app_icon = panel->app_icon().AsImageSkia();
EXPECT_EQ(panel::kPanelAppIconSize, app_icon.width());
EXPECT_EQ(panel::kPanelAppIconSize, app_icon.height());
// Then verify on the native panel level.
#if !defined(OS_WIN) || !defined(USE_AURA)
scoped_ptr<NativePanelTesting> native_panel_testing(
CreateNativePanelTesting(panel));
EXPECT_TRUE(native_panel_testing->VerifyAppIcon());
#endif
panel->Close();
}
#endif
IN_PROC_BROWSER_TEST_F(PanelExtensionBrowserTest,
ClosePanelBeforeIconLoadingCompleted) {
const Extension* extension =
LoadExtension(test_data_dir_.AppendASCII("test_extension"));
Panel* panel = CreatePanelFromExtension(extension);
// Close tha panel without waiting for the app icon loaded.
panel->Close();
}
// Non-abstract RenderViewContextMenu class for testing context menus in Panels.
class PanelContextMenu : public RenderViewContextMenu {
public:
PanelContextMenu(content::RenderFrameHost* render_frame_host,
const content::ContextMenuParams& params)
: RenderViewContextMenu(render_frame_host, params) {}
bool HasCommandWithId(int command_id) {
return menu_model_.GetIndexOfCommandId(command_id) != -1;
}
protected:
// RenderViewContextMenu implementation.
bool GetAcceleratorForCommandId(int command_id,
ui::Accelerator* accelerator) override {
return false;
}
};
IN_PROC_BROWSER_TEST_F(PanelExtensionBrowserTest, BasicContextMenu) {
ExtensionTestMessageListener listener("panel loaded", false);
LoadExtension(test_data_dir_.AppendASCII("basic"));
ASSERT_TRUE(listener.WaitUntilSatisfied());
// There should only be one panel.
PanelManager* panel_manager = PanelManager::GetInstance();
EXPECT_EQ(1, panel_manager->num_panels());
Panel* panel = panel_manager->panels().front();
content::WebContents* web_contents = panel->GetWebContents();
ASSERT_TRUE(web_contents);
// Verify basic menu contents. The basic extension does not add any
// context menu items so the panel's menu should include only the
// developer tools.
{
content::ContextMenuParams params;
params.page_url = web_contents->GetURL();
// Ensure context menu isn't swallowed by WebContentsDelegate (the panel).
EXPECT_FALSE(web_contents->GetDelegate()->HandleContextMenu(params));
scoped_ptr<PanelContextMenu> menu(
new PanelContextMenu(web_contents->GetMainFrame(), params));
menu->Init();
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_PASTE));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
EXPECT_FALSE(menu->HasCommandWithId(IDC_BACK));
EXPECT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPYLINKLOCATION));
}
// Verify expected menu contents for editable item.
{
content::ContextMenuParams params;
params.is_editable = true;
params.page_url = web_contents->GetURL();
// Ensure context menu isn't swallowed by WebContentsDelegate (the panel).
EXPECT_FALSE(web_contents->GetDelegate()->HandleContextMenu(params));
scoped_ptr<PanelContextMenu> menu(
new PanelContextMenu(web_contents->GetMainFrame(), params));
menu->Init();
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
EXPECT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
EXPECT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_PASTE));
EXPECT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
EXPECT_FALSE(menu->HasCommandWithId(IDC_BACK));
EXPECT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPYLINKLOCATION));
}
// Verify expected menu contents for text selection.
{
content::ContextMenuParams params;
params.page_url = web_contents->GetURL();
params.selection_text = base::ASCIIToUTF16("Select me");
// Ensure context menu isn't swallowed by WebContentsDelegate (the panel).
EXPECT_FALSE(web_contents->GetDelegate()->HandleContextMenu(params));
scoped_ptr<PanelContextMenu> menu(
new PanelContextMenu(web_contents->GetMainFrame(), params));
menu->Init();
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_PASTE));
EXPECT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
EXPECT_FALSE(menu->HasCommandWithId(IDC_BACK));
EXPECT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPYLINKLOCATION));
}
// Verify expected menu contexts for a link.
{
content::ContextMenuParams params;
params.page_url = web_contents->GetURL();
params.unfiltered_link_url = GURL("http://google.com/");
// Ensure context menu isn't swallowed by WebContentsDelegate (the panel).
EXPECT_FALSE(web_contents->GetDelegate()->HandleContextMenu(params));
scoped_ptr<PanelContextMenu> menu(
new PanelContextMenu(web_contents->GetMainFrame(), params));
menu->Init();
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_PASTE));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
EXPECT_FALSE(menu->HasCommandWithId(IDC_BACK));
EXPECT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
EXPECT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPYLINKLOCATION));
}
}
IN_PROC_BROWSER_TEST_F(PanelExtensionBrowserTest, CustomContextMenu) {
ExtensionTestMessageListener listener("created item", false);
LoadExtension(test_data_dir_.AppendASCII("context_menu"));
ASSERT_TRUE(listener.WaitUntilSatisfied());
// Load a second extension that also creates a custom context menu item.
ExtensionTestMessageListener bogey_listener("created bogey item", false);
LoadExtension(test_data_dir_.AppendASCII("context_menu2"));
ASSERT_TRUE(bogey_listener.WaitUntilSatisfied());
// There should only be one panel.
PanelManager* panel_manager = PanelManager::GetInstance();
EXPECT_EQ(1, panel_manager->num_panels());
Panel* panel = panel_manager->panels().front();
content::WebContents* web_contents = panel->GetWebContents();
ASSERT_TRUE(web_contents);
content::ContextMenuParams params;
params.page_url = web_contents->GetURL();
// Ensure context menu isn't swallowed by WebContentsDelegate (the panel).
EXPECT_FALSE(web_contents->GetDelegate()->HandleContextMenu(params));
// Verify menu contents contains the custom item added by their own extension.
scoped_ptr<PanelContextMenu> menu;
menu.reset(new PanelContextMenu(web_contents->GetMainFrame(), params));
menu->Init();
EXPECT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
EXPECT_FALSE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + 1));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_PASTE));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
EXPECT_FALSE(menu->HasCommandWithId(IDC_BACK));
EXPECT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
EXPECT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPYLINKLOCATION));
// Execute the extension's custom menu item and wait for the extension's
// script to tell us its onclick fired.
ExtensionTestMessageListener onclick_listener("clicked", false);
int command_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
ASSERT_TRUE(menu->IsCommandIdEnabled(command_id));
menu->ExecuteCommand(command_id, 0);
EXPECT_TRUE(onclick_listener.WaitUntilSatisfied());
}