blob: 6f33782e21eb14e19612f3387b7a1b5e2093647f [file] [log] [blame]
// Copyright 2013 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 <stddef.h>
#include <limits>
#include "base/location.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_timeouts.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/apps/app_browsertest_util.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu_browsertest_util.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/test_launcher_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/guest_view/browser/guest_view_base.h"
#include "components/guest_view/browser/guest_view_manager.h"
#include "components/guest_view/browser/guest_view_manager_delegate.h"
#include "components/guest_view/browser/guest_view_manager_factory.h"
#include "components/guest_view/browser/test_guest_view_manager.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_iterator.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/text_input_test_utils.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/test/extension_test_message_listener.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "ui/base/ime/composition_text.h"
#include "ui/base/ime/ime_text_span.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/test/ui_controls.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/range/range.h"
#include "ui/touch_selection/touch_selection_menu_runner.h"
using extensions::AppWindow;
using extensions::ExtensionsAPIClient;
using guest_view::GuestViewBase;
using guest_view::GuestViewManager;
using guest_view::TestGuestViewManager;
using guest_view::TestGuestViewManagerFactory;
#if defined(OS_MACOSX)
// The original TextInputClientMessageFilter is added during the initialization
// phase of RenderProcessHost. The only chance we have to add the test filter
// (so that it can receive the TextInputClientMac incoming IPC messages) is
// during the call to RenderProcessWillLaunch() on ContentBrowserClient. This
// class provides that for testing. The class also replaces the current client
// and will reset the client back to the original one upon destruction.
class BrowserClientForTextInputClientMac : public ChromeContentBrowserClient {
public:
BrowserClientForTextInputClientMac()
: old_client_(content::SetBrowserClientForTesting(this)) {}
~BrowserClientForTextInputClientMac() override {
content::SetBrowserClientForTesting(old_client_);
}
// ContentBrowserClient overrides.
void RenderProcessWillLaunch(
content::RenderProcessHost* process_host,
service_manager::mojom::ServiceRequest* service_request) override {
ChromeContentBrowserClient::RenderProcessWillLaunch(process_host,
service_request);
filters_.push_back(
new content::TestTextInputClientMessageFilter(process_host));
}
// Retrieves the registered filter for the given RenderProcessHost. It will
// return false if the RenderProcessHost was initialized while a different
// instance of ContentBrowserClient was in action.
scoped_refptr<content::TestTextInputClientMessageFilter>
GetTextInputClientMessageFilterForProcess(
content::RenderProcessHost* process_host) const {
for (auto filter : filters_) {
if (filter->process() == process_host)
return filter;
}
return nullptr;
}
private:
content::ContentBrowserClient* old_client_;
std::vector<scoped_refptr<content::TestTextInputClientMessageFilter>>
filters_;
DISALLOW_COPY_AND_ASSIGN(BrowserClientForTextInputClientMac);
};
// This class observes the RenderWidgetHostViewCocoa corresponding to the outer
// most WebContents provided for newly added subviews. The added subview
// corresponds to a NSPopUpButtonCell which will be removed shortly after being
// shown.
class NewSubViewAddedObserver : content::RenderWidgetHostViewCocoaObserver {
public:
explicit NewSubViewAddedObserver(content::WebContents* web_contents)
: content::RenderWidgetHostViewCocoaObserver(web_contents) {}
~NewSubViewAddedObserver() override {}
void WaitForNextSubView() {
if (did_receive_rect_)
return;
run_loop_.reset(new base::RunLoop());
run_loop_->Run();
}
const gfx::Rect& view_bounds_in_screen() const { return bounds_; }
private:
void DidAddSubviewWillBeDismissed(
const gfx::Rect& bounds_in_root_view) override {
did_receive_rect_ = true;
bounds_ = bounds_in_root_view;
if (run_loop_)
run_loop_->Quit();
}
bool did_receive_rect_ = false;
gfx::Rect bounds_;
std::unique_ptr<base::RunLoop> run_loop_;
DISALLOW_COPY_AND_ASSIGN(NewSubViewAddedObserver);
};
#endif // OS_MACOSX
class WebViewInteractiveTest : public extensions::PlatformAppBrowserTest {
public:
WebViewInteractiveTest()
: guest_web_contents_(NULL),
embedder_web_contents_(NULL),
corner_(gfx::Point()),
mouse_click_result_(false),
first_click_(true) {
GuestViewManager::set_factory_for_testing(&factory_);
}
TestGuestViewManager* GetGuestViewManager() {
TestGuestViewManager* manager = static_cast<TestGuestViewManager*>(
TestGuestViewManager::FromBrowserContext(browser()->profile()));
// TestGuestViewManager::WaitForSingleGuestCreated may and will get called
// before a guest is created.
if (!manager) {
manager = static_cast<TestGuestViewManager*>(
GuestViewManager::CreateWithDelegate(
browser()->profile(),
ExtensionsAPIClient::Get()->CreateGuestViewManagerDelegate(
browser()->profile())));
}
return manager;
}
void MoveMouseInsideWindowWithListener(gfx::Point point,
const std::string& message) {
ExtensionTestMessageListener move_listener(message, false);
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
gfx::Point(corner_.x() + point.x(), corner_.y() + point.y())));
ASSERT_TRUE(move_listener.WaitUntilSatisfied());
}
void SendMouseClickWithListener(ui_controls::MouseButton button,
const std::string& message) {
ExtensionTestMessageListener listener(message, false);
SendMouseClick(button);
ASSERT_TRUE(listener.WaitUntilSatisfied());
}
void SendMouseClick(ui_controls::MouseButton button) {
SendMouseEvent(button, ui_controls::DOWN);
SendMouseEvent(button, ui_controls::UP);
}
void MoveMouseInsideWindow(const gfx::Point& point) {
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
gfx::Point(corner_.x() + point.x(), corner_.y() + point.y())));
}
gfx::NativeWindow GetPlatformAppWindow() {
const extensions::AppWindowRegistry::AppWindowList& app_windows =
extensions::AppWindowRegistry::Get(browser()->profile())->app_windows();
return (*app_windows.begin())->GetNativeWindow();
}
void SendKeyPressToPlatformApp(ui::KeyboardCode key) {
ASSERT_EQ(1U, GetAppWindowCount());
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), key, false, false, false, false));
}
void SendCopyKeyPressToPlatformApp() {
ASSERT_EQ(1U, GetAppWindowCount());
#if defined(OS_MACOSX)
// Send Cmd+C on MacOSX.
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_C, false, false, false, true));
#else
// Send Ctrl+C on Windows and Linux/ChromeOS.
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_C, true, false, false, false));
#endif
}
void SendStartOfLineKeyPressToPlatformApp() {
#if defined(OS_MACOSX)
// Send Cmd+Left on MacOSX.
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_LEFT, false, false, false, true));
#else
// Send Ctrl+Left on Windows and Linux/ChromeOS.
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_LEFT, true, false, false, false));
#endif
}
void SendBackShortcutToPlatformApp() {
#if defined(OS_MACOSX)
// Send Cmd+[ on MacOSX.
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_OEM_4, false, false, false, true));
#else
// Send browser back key on Linux/Windows.
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_BROWSER_BACK,
false, false, false, false));
#endif
}
void SendForwardShortcutToPlatformApp() {
#if defined(OS_MACOSX)
// Send Cmd+] on MacOSX.
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_OEM_6, false, false, false, true));
#else
// Send browser back key on Linux/Windows.
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_BROWSER_FORWARD,
false, false, false, false));
#endif
}
void SendMouseEvent(ui_controls::MouseButton button,
ui_controls::MouseButtonState state) {
if (first_click_) {
mouse_click_result_ = ui_test_utils::SendMouseEventsSync(button,
state);
first_click_ = false;
} else {
ASSERT_EQ(mouse_click_result_, ui_test_utils::SendMouseEventsSync(
button, state));
}
}
enum TestServer {
NEEDS_TEST_SERVER,
NO_TEST_SERVER
};
std::unique_ptr<ExtensionTestMessageListener> RunAppHelper(
const std::string& test_name,
const std::string& app_location,
TestServer test_server,
content::WebContents** embedder_web_contents) {
// For serving guest pages.
if ((test_server == NEEDS_TEST_SERVER) && !StartEmbeddedTestServer()) {
LOG(ERROR) << "FAILED TO START TEST SERVER.";
return std::unique_ptr<ExtensionTestMessageListener>();
}
LoadAndLaunchPlatformApp(app_location.c_str(), "Launched");
if (!ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow())) {
LOG(ERROR) << "UNABLE TO FOCUS TEST WINDOW.";
return std::unique_ptr<ExtensionTestMessageListener>();
}
// Flush any pending events to make sure we start with a clean slate.
content::RunAllPendingInMessageLoop();
*embedder_web_contents = GetFirstAppWindowWebContents();
std::unique_ptr<ExtensionTestMessageListener> done_listener(
new ExtensionTestMessageListener("TEST_PASSED", false));
done_listener->set_failure_message("TEST_FAILED");
if (!content::ExecuteScript(
*embedder_web_contents,
base::StringPrintf("runTest('%s')", test_name.c_str()))) {
LOG(ERROR) << "UNABLE TO START TEST";
return std::unique_ptr<ExtensionTestMessageListener>();
}
return done_listener;
}
void TestHelper(const std::string& test_name,
const std::string& app_location,
TestServer test_server) {
content::WebContents* embedder_web_contents = NULL;
std::unique_ptr<ExtensionTestMessageListener> done_listener(RunAppHelper(
test_name, app_location, test_server, &embedder_web_contents));
ASSERT_TRUE(done_listener);
ASSERT_TRUE(done_listener->WaitUntilSatisfied());
embedder_web_contents_ = embedder_web_contents;
guest_web_contents_ = GetGuestViewManager()->WaitForSingleGuestCreated();
}
void SendMessageToEmbedder(const std::string& message) {
ASSERT_TRUE(content::ExecuteScript(
GetFirstAppWindowWebContents(),
base::StringPrintf("onAppMessage('%s');", message.c_str())));
}
void SetupTest(const std::string& app_name,
const std::string& guest_url_spec) {
ASSERT_TRUE(StartEmbeddedTestServer());
GURL::Replacements replace_host;
replace_host.SetHostStr("localhost");
GURL guest_url = embedded_test_server()->GetURL(guest_url_spec);
guest_url = guest_url.ReplaceComponents(replace_host);
ui_test_utils::UrlLoadObserver guest_observer(
guest_url, content::NotificationService::AllSources());
LoadAndLaunchPlatformApp(app_name.c_str(), "connected");
guest_observer.Wait();
content::Source<content::NavigationController> source =
guest_observer.source();
EXPECT_TRUE(source->GetWebContents()
->GetMainFrame()
->GetProcess()
->IsForGuestsOnly());
guest_web_contents_ = source->GetWebContents();
embedder_web_contents_ =
GuestViewBase::FromWebContents(guest_web_contents_)->
embedder_web_contents();
gfx::Rect offset = embedder_web_contents_->GetContainerBounds();
corner_ = offset.origin();
const testing::TestInfo* const test_info =
testing::UnitTest::GetInstance()->current_test_info();
const char* prefix = "DragDropWithinWebView";
if (!strncmp(test_info->name(), prefix, strlen(prefix))) {
// In the drag drop test we add 20px padding to the page body because on
// windows if we get too close to the edge of the window the resize cursor
// appears and we start dragging the window edge.
corner_.Offset(20, 20);
}
}
content::WebContents* guest_web_contents() {
return guest_web_contents_;
}
content::WebContents* embedder_web_contents() {
return embedder_web_contents_;
}
gfx::Point corner() {
return corner_;
}
void SimulateRWHMouseClick(content::RenderWidgetHost* rwh,
blink::WebMouseEvent::Button button,
int x,
int y) {
blink::WebMouseEvent mouse_event(
blink::WebInputEvent::kMouseDown, blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
mouse_event.button = button;
mouse_event.SetPositionInWidget(x, y);
// Needed for the WebViewTest.ContextMenuPositionAfterCSSTransforms
gfx::Rect rect = rwh->GetView()->GetViewBounds();
mouse_event.SetPositionInScreen(x + rect.x(), y + rect.y());
rwh->ForwardMouseEvent(mouse_event);
mouse_event.SetType(blink::WebInputEvent::kMouseUp);
rwh->ForwardMouseEvent(mouse_event);
}
class PopupCreatedObserver {
public:
PopupCreatedObserver()
: initial_widget_count_(0),
last_render_widget_host_(NULL) {}
~PopupCreatedObserver() {}
void Wait() {
if (CountWidgets() == initial_widget_count_ + 1 &&
last_render_widget_host_->GetView()->GetNativeView()) {
gfx::Rect popup_bounds =
last_render_widget_host_->GetView()->GetViewBounds();
if (!popup_bounds.size().IsEmpty()) {
if (message_loop_.get())
message_loop_->Quit();
return;
}
}
// If we haven't seen any new widget or we get 0 size widget, we need to
// schedule waiting.
ScheduleWait();
if (!message_loop_.get()) {
message_loop_ = new content::MessageLoopRunner;
message_loop_->Run();
}
}
void Init() { initial_widget_count_ = CountWidgets(); }
// Returns the last widget created.
content::RenderWidgetHost* last_render_widget_host() {
return last_render_widget_host_;
}
private:
void ScheduleWait() {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&PopupCreatedObserver::Wait, base::Unretained(this)),
base::TimeDelta::FromMilliseconds(200));
}
size_t CountWidgets() {
std::unique_ptr<content::RenderWidgetHostIterator> widgets(
content::RenderWidgetHost::GetRenderWidgetHosts());
size_t num_widgets = 0;
while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
if (content::RenderViewHost::From(widget))
continue;
++num_widgets;
last_render_widget_host_ = widget;
}
return num_widgets;
}
size_t initial_widget_count_;
content::RenderWidgetHost* last_render_widget_host_;
scoped_refptr<content::MessageLoopRunner> message_loop_;
DISALLOW_COPY_AND_ASSIGN(PopupCreatedObserver);
};
void PopupTestHelper(const gfx::Point& padding) {
PopupCreatedObserver popup_observer;
popup_observer.Init();
// Press alt+DOWN to open popup.
bool alt = true;
content::SimulateKeyPress(guest_web_contents(), ui::DomKey::ARROW_DOWN,
ui::DomCode::ARROW_DOWN, ui::VKEY_DOWN, false,
false, alt, false);
popup_observer.Wait();
content::RenderWidgetHost* popup_rwh =
popup_observer.last_render_widget_host();
gfx::Rect popup_bounds = popup_rwh->GetView()->GetViewBounds();
content::RenderViewHost* embedder_rvh =
GetFirstAppWindowWebContents()->GetRenderViewHost();
gfx::Rect embedder_bounds =
embedder_rvh->GetWidget()->GetView()->GetViewBounds();
gfx::Vector2d diff = popup_bounds.origin() - embedder_bounds.origin();
LOG(INFO) << "DIFF: x = " << diff.x() << ", y = " << diff.y();
const int left_spacing = 40 + padding.x(); // div.style.paddingLeft = 40px.
// div.style.paddingTop = 60px + (input box height = 26px).
const int top_spacing = 60 + 26 + padding.y();
// If the popup is placed within |threshold_px| of the expected position,
// then we consider the test as a pass.
const int threshold_px = 10;
EXPECT_LE(std::abs(diff.x() - left_spacing), threshold_px);
EXPECT_LE(std::abs(diff.y() - top_spacing), threshold_px);
// Close the popup.
content::SimulateKeyPress(guest_web_contents(), ui::DomKey::ESCAPE,
ui::DomCode::ESCAPE, ui::VKEY_ESCAPE, false,
false, false, false);
}
void DragTestStep1() {
// Move mouse to start of text.
MoveMouseInsideWindow(gfx::Point(45, 8));
MoveMouseInsideWindow(gfx::Point(45, 9));
SendMouseEvent(ui_controls::LEFT, ui_controls::DOWN);
MoveMouseInsideWindow(gfx::Point(74, 12));
MoveMouseInsideWindow(gfx::Point(78, 12));
// Now wait a bit before moving mouse to initiate drag/drop.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&WebViewInteractiveTest::DragTestStep2,
base::Unretained(this)),
base::TimeDelta::FromMilliseconds(200));
}
void DragTestStep2() {
// Drag source over target.
MoveMouseInsideWindow(gfx::Point(76, 76));
// Create a second mouse over the source to trigger the drag over event.
MoveMouseInsideWindow(gfx::Point(76, 77));
// Release mouse to drop.
SendMouseEvent(ui_controls::LEFT, ui_controls::UP);
SendMouseClick(ui_controls::LEFT);
quit_closure_.Run();
// Note that following ExtensionTestMessageListener and ExecuteScript*
// call must be after we quit |quit_closure_|. Otherwise the class
// here won't be able to receive messages sent by chrome.test.sendMessage.
// This is because of the nature of drag and drop code (esp. the
// MessageLoop) in it.
// Now check if we got a drop and read the drop data.
embedder_web_contents_ = GetFirstAppWindowWebContents();
ExtensionTestMessageListener drop_listener("guest-got-drop", false);
EXPECT_TRUE(content::ExecuteScript(embedder_web_contents_,
"window.checkIfGuestGotDrop()"));
EXPECT_TRUE(drop_listener.WaitUntilSatisfied());
std::string last_drop_data;
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
embedder_web_contents_,
"window.domAutomationController.send(getLastDropData())",
&last_drop_data));
last_drop_data_ = last_drop_data;
}
void FullscreenTestHelper(const std::string& test_name,
const std::string& test_dir) {
TestHelper(test_name, test_dir, NO_TEST_SERVER);
content::WebContents* embedder_web_contents =
GetFirstAppWindowWebContents();
ASSERT_TRUE(embedder_web_contents);
ASSERT_TRUE(guest_web_contents());
// Click the guest to request fullscreen.
ExtensionTestMessageListener passed_listener(
"FULLSCREEN_STEP_PASSED", false);
passed_listener.set_failure_message("TEST_FAILED");
content::SimulateMouseClickAt(guest_web_contents(), 0,
blink::WebMouseEvent::Button::kLeft,
gfx::Point(20, 20));
ASSERT_TRUE(passed_listener.WaitUntilSatisfied());
}
protected:
TestGuestViewManagerFactory factory_;
content::WebContents* guest_web_contents_;
content::WebContents* embedder_web_contents_;
gfx::Point corner_;
bool mouse_click_result_;
bool first_click_;
// Only used in drag/drop test.
base::Closure quit_closure_;
std::string last_drop_data_;
};
class WebViewImeInteractiveTest : public WebViewInteractiveTest {
protected:
// This class observes all the composition range updates associated with the
// TextInputManager of the provided WebContents. The WebContents should be an
// outer most WebContents.
class CompositionRangeUpdateObserver {
public:
explicit CompositionRangeUpdateObserver(content::WebContents* web_contents)
: tester_(web_contents) {
tester_.SetOnImeCompositionRangeChangedCallback(
base::Bind(&CompositionRangeUpdateObserver::OnCompositionRangeUpdated,
base::Unretained(this)));
}
~CompositionRangeUpdateObserver() {}
// Wait until a composition range update with a range length equal to
// |length| is received.
void WaitForCompositionRangeLength(uint32_t length) {
if (last_composition_range_length_.has_value() &&
last_composition_range_length_.value() == length)
return;
expected_length_ = length;
run_loop_.reset(new base::RunLoop());
run_loop_->Run();
}
private:
void OnCompositionRangeUpdated() {
uint32_t length = std::numeric_limits<uint32_t>::max();
if (tester_.GetLastCompositionRangeLength(&length)) {
last_composition_range_length_ = length;
}
if (last_composition_range_length_.value() == expected_length_)
run_loop_->Quit();
}
content::TextInputManagerTester tester_;
std::unique_ptr<base::RunLoop> run_loop_;
base::Optional<uint32_t> last_composition_range_length_;
uint32_t expected_length_ = 0;
DISALLOW_COPY_AND_ASSIGN(CompositionRangeUpdateObserver);
};
};
class WebViewDragDropInteractiveTest : public WebViewInteractiveTest {};
class WebViewNewWindowInteractiveTest : public WebViewInteractiveTest {};
class WebViewFocusInteractiveTest : public WebViewInteractiveTest {};
class WebViewPointerLockInteractiveTest : public WebViewInteractiveTest {};
// The following class of tests do not work for OOPIF <webview>.
// TODO(ekaramad): Make this tests work with OOPIF and replace the test classes
// with WebViewInteractiveTest (see crbug.com/582562).
class DISABLED_WebViewPopupInteractiveTest : public WebViewInteractiveTest {};
// TODO(mcnee): These tests are BrowserPlugin specific. While WebView itself
// is no longer based on BrowserPlugin, MimeHandlerViewGuest is. We'll keep
// these tests (that would otherwise be removed) so that we keep test coverage
// of functionality that could still be relevant to MimeHandlerViewGuest. Once
// MimeHandlerViewGuest is no longer based on BrowserPlugin, remove these
// tests. (See https://crbug.com/533069 and https://crbug.com/659750).
class WebViewBrowserPluginSpecificInteractiveTest
: public WebViewInteractiveTest {
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
WebViewInteractiveTest::SetUpCommandLine(command_line);
scoped_feature_list_.InitAndDisableFeature(
features::kGuestViewCrossProcessFrames);
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
class WebViewContextMenuBrowserPluginSpecificInteractiveTest
: public WebViewBrowserPluginSpecificInteractiveTest {};
// ui_test_utils::SendMouseMoveSync doesn't seem to work on OS_MACOSX, and
// likely won't work on many other platforms as well, so for now this test
// is for Windows and Linux only. As of Sept 17th, 2013 this test is disabled
// on Windows due to flakines, see http://crbug.com/293445.
// Disabled on Linux Aura because pointer lock does not work on Linux Aura.
// crbug.com/341876
#if defined(OS_LINUX)
// flaky http://crbug.com/412086
IN_PROC_BROWSER_TEST_F(WebViewPointerLockInteractiveTest,
DISABLED_PointerLock) {
SetupTest("web_view/pointer_lock",
"/extensions/platform_apps/web_view/pointer_lock/guest.html");
// Move the mouse over the Lock Pointer button.
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
gfx::Point(corner().x() + 75, corner().y() + 25)));
// Click the Lock Pointer button. The first two times the button is clicked
// the permission API will deny the request (intentional).
ExtensionTestMessageListener exception_listener("request exception", false);
SendMouseClickWithListener(ui_controls::LEFT, "lock error");
ASSERT_TRUE(exception_listener.WaitUntilSatisfied());
SendMouseClickWithListener(ui_controls::LEFT, "lock error");
// Click the Lock Pointer button, locking the mouse to lockTarget1.
SendMouseClickWithListener(ui_controls::LEFT, "locked");
// Attempt to move the mouse off of the lock target, and onto lockTarget2,
// (which would trigger a test failure).
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
gfx::Point(corner().x() + 74, corner().y() + 74)));
MoveMouseInsideWindowWithListener(gfx::Point(75, 75), "mouse-move");
#if defined(OS_WIN)
// When the mouse is unlocked on win aura, sending a test mouse click clicks
// where the mouse moved to while locked. I was unable to figure out why, and
// since the issue only occurs with the test mouse events, just fix it with
// a simple workaround - moving the mouse back to where it should be.
// TODO(mthiesse): Fix Win Aura simulated mouse events while mouse locked.
MoveMouseInsideWindowWithListener(gfx::Point(75, 25), "mouse-move");
#endif
ExtensionTestMessageListener unlocked_listener("unlocked", false);
// Send a key press to unlock the mouse.
SendKeyPressToPlatformApp(ui::VKEY_ESCAPE);
// Wait for page to receive (successful) mouse unlock response.
ASSERT_TRUE(unlocked_listener.WaitUntilSatisfied());
// After the second lock, guest.js sends a message to main.js to remove the
// webview object. main.js then removes the div containing the webview, which
// should unlock, and leave the mouse over the mousemove-capture-container
// div. We then move the mouse over that div to ensure the mouse was properly
// unlocked and that the div receieves the message.
ExtensionTestMessageListener move_captured_listener("move-captured", false);
move_captured_listener.set_failure_message("timeout");
// Mouse should already be over lock button (since we just unlocked), so send
// click to re-lock the mouse.
SendMouseClickWithListener(ui_controls::LEFT, "deleted");
// A mousemove event is triggered on the mousemove-capture-container element
// when we delete the webview container (since the mouse moves onto the
// element), but just in case, send an explicit mouse movement to be safe.
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
gfx::Point(corner().x() + 50, corner().y() + 10)));
// Wait for page to receive second (successful) mouselock response.
bool success = move_captured_listener.WaitUntilSatisfied();
if (!success) {
fprintf(stderr, "TIMEOUT - retrying\n");
// About 1 in 40 tests fail to detect mouse moves at this point (why?).
// Sending a right click seems to fix this (why?).
ExtensionTestMessageListener move_listener2("move-captured", false);
SendMouseClick(ui_controls::RIGHT);
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
gfx::Point(corner().x() + 51, corner().y() + 11)));
ASSERT_TRUE(move_listener2.WaitUntilSatisfied());
}
}
// flaky http://crbug.com/412086
IN_PROC_BROWSER_TEST_F(WebViewPointerLockInteractiveTest,
DISABLED_PointerLockFocus) {
SetupTest("web_view/pointer_lock_focus",
"/extensions/platform_apps/web_view/pointer_lock_focus/guest.html");
// Move the mouse over the Lock Pointer button.
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
gfx::Point(corner().x() + 75, corner().y() + 25)));
// Click the Lock Pointer button, locking the mouse to lockTarget.
// This will also change focus to another element
SendMouseClickWithListener(ui_controls::LEFT, "locked");
// Try to unlock the mouse now that the focus is outside of the BrowserPlugin
ExtensionTestMessageListener unlocked_listener("unlocked", false);
// Send a key press to unlock the mouse.
SendKeyPressToPlatformApp(ui::VKEY_ESCAPE);
// Wait for page to receive (successful) mouse unlock response.
ASSERT_TRUE(unlocked_listener.WaitUntilSatisfied());
}
#endif // defined(OS_LINUX)
// Tests that if a <webview> is focused before navigation then the guest starts
// off focused.
IN_PROC_BROWSER_TEST_F(WebViewFocusInteractiveTest,
Focus_FocusBeforeNavigation) {
TestHelper("testFocusBeforeNavigation", "web_view/focus", NO_TEST_SERVER);
}
// Tests that setting focus on the <webview> sets focus on the guest.
IN_PROC_BROWSER_TEST_F(WebViewFocusInteractiveTest, Focus_FocusEvent) {
TestHelper("testFocusEvent", "web_view/focus", NO_TEST_SERVER);
}
IN_PROC_BROWSER_TEST_F(WebViewFocusInteractiveTest, Focus_FocusTakeFocus) {
TestHelper("testFocusTakeFocus", "web_view/focus", NO_TEST_SERVER);
// Compute where to click in the window to focus the guest input box.
int clickX, clickY;
EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
embedder_web_contents(),
"domAutomationController.send(Math.floor(window.clickX));", &clickX));
EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
embedder_web_contents(),
"domAutomationController.send(Math.floor(window.clickY));", &clickY));
ExtensionTestMessageListener next_step_listener("TEST_STEP_PASSED", false);
next_step_listener.set_failure_message("TEST_STEP_FAILED");
content::SimulateMouseClickAt(guest_web_contents(), 0,
blink::WebMouseEvent::Button::kLeft,
gfx::Point(clickX, clickY));
ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
// TAB back out to the embedder's input.
next_step_listener.Reset();
content::SimulateKeyPress(embedder_web_contents(), ui::DomKey::TAB,
ui::DomCode::TAB, ui::VKEY_TAB, false, false, false,
false);
ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
}
// Flaky on Mac and Linux - https://crbug.com/707648
#if defined(OS_MACOSX) || defined(OS_LINUX)
#define MAYBE_Focus_FocusTracksEmbedder DISABLED_Focus_FocusTracksEmbedder
#else
#define MAYBE_Focus_FocusTracksEmbedder Focus_FocusTracksEmbedder
#endif
IN_PROC_BROWSER_TEST_F(WebViewFocusInteractiveTest,
MAYBE_Focus_FocusTracksEmbedder) {
content::WebContents* embedder_web_contents = NULL;
std::unique_ptr<ExtensionTestMessageListener> done_listener(
RunAppHelper("testFocusTracksEmbedder", "web_view/focus", NO_TEST_SERVER,
&embedder_web_contents));
EXPECT_TRUE(done_listener->WaitUntilSatisfied());
ExtensionTestMessageListener next_step_listener("TEST_STEP_PASSED", false);
next_step_listener.set_failure_message("TEST_STEP_FAILED");
EXPECT_TRUE(content::ExecuteScript(
embedder_web_contents,
"window.runCommand('testFocusTracksEmbedderRunNextStep');"));
// Blur the embedder.
embedder_web_contents->GetRenderViewHost()->GetWidget()->Blur();
// Ensure that the guest is also blurred.
ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
}
IN_PROC_BROWSER_TEST_F(WebViewFocusInteractiveTest, Focus_AdvanceFocus) {
content::WebContents* embedder_web_contents = NULL;
{
std::unique_ptr<ExtensionTestMessageListener> done_listener(
RunAppHelper("testAdvanceFocus", "web_view/focus", NO_TEST_SERVER,
&embedder_web_contents));
EXPECT_TRUE(done_listener->WaitUntilSatisfied());
}
{
ExtensionTestMessageListener listener("button1-focused", false);
listener.set_failure_message("TEST_FAILED");
// In oopif-webview, the click it directly routed to the guest.
content::WebContents* guest =
GetGuestViewManager()->WaitForSingleGuestCreated();
SimulateRWHMouseClick(guest->GetRenderViewHost()->GetWidget(),
blink::WebMouseEvent::Button::kLeft, 200, 20);
content::SimulateKeyPress(embedder_web_contents, ui::DomKey::TAB,
ui::DomCode::TAB, ui::VKEY_TAB, false, false,
false, false);
ASSERT_TRUE(listener.WaitUntilSatisfied());
}
{
// Wait for button1 to be focused again, this means we were asked to
// move the focus to the next focusable element.
ExtensionTestMessageListener listener("button1-advance-focus", false);
listener.set_failure_message("TEST_FAILED");
// TODO(fsamuel): A third Tab key press should not be necessary.
// The <webview> will take keyboard focus but it will not focus an initial
// element. The initial element is dependent upon tab direction which blink
// does not propagate to the plugin.
// See http://crbug.com/147644.
content::SimulateKeyPress(embedder_web_contents, ui::DomKey::TAB,
ui::DomCode::TAB, ui::VKEY_TAB, false, false,
false, false);
content::SimulateKeyPress(embedder_web_contents, ui::DomKey::TAB,
ui::DomCode::TAB, ui::VKEY_TAB, false, false,
false, false);
content::SimulateKeyPress(embedder_web_contents, ui::DomKey::TAB,
ui::DomCode::TAB, ui::VKEY_TAB, false, false,
false, false);
ASSERT_TRUE(listener.WaitUntilSatisfied());
}
}
// Tests that blurring <webview> also blurs the guest.
IN_PROC_BROWSER_TEST_F(WebViewFocusInteractiveTest, Focus_BlurEvent) {
TestHelper("testBlurEvent", "web_view/focus", NO_TEST_SERVER);
}
// Tests that a <webview> can't steal focus from the embedder.
IN_PROC_BROWSER_TEST_F(WebViewFocusInteractiveTest,
FrameInGuestWontStealFocus) {
LoadAndLaunchPlatformApp("web_view/simple", "WebViewTest.LAUNCHED");
content::WebContents* embedder_web_contents = GetFirstAppWindowWebContents();
content::WebContents* guest_web_contents =
GetGuestViewManager()->WaitForSingleGuestCreated();
content::MainThreadFrameObserver embedder_observer(
embedder_web_contents->GetMainFrame()->GetView()->GetRenderWidgetHost());
content::MainThreadFrameObserver guest_observer(
guest_web_contents->GetMainFrame()->GetView()->GetRenderWidgetHost());
// Embedder should be focused initially.
EXPECT_EQ(content::GetFocusedWebContents(guest_web_contents),
embedder_web_contents);
// Try to focus an iframe in the guest.
EXPECT_TRUE(content::ExecuteScript(
guest_web_contents,
"document.body.appendChild(document.createElement('iframe')); "
"document.querySelector('iframe').focus()"));
embedder_observer.Wait();
guest_observer.Wait();
// Embedder should still be focused.
EXPECT_EQ(content::GetFocusedWebContents(guest_web_contents),
embedder_web_contents);
// Try to focus the guest from the embedder.
EXPECT_TRUE(content::ExecuteScript(
embedder_web_contents, "document.querySelector('webview').focus()"));
embedder_observer.Wait();
guest_observer.Wait();
// Guest should be focused.
EXPECT_EQ(content::GetFocusedWebContents(guest_web_contents),
guest_web_contents);
// Try to focus an iframe in the embedder.
EXPECT_TRUE(content::ExecuteScript(
embedder_web_contents,
"document.body.appendChild(document.createElement('iframe')); "
"document.querySelector('iframe').focus()"));
embedder_observer.Wait();
guest_observer.Wait();
// Embedder is allowed to steal focus from guest.
EXPECT_EQ(content::GetFocusedWebContents(guest_web_contents),
embedder_web_contents);
}
// Tests that guests receive edit commands and respond appropriately.
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, EditCommands) {
LoadAndLaunchPlatformApp("web_view/edit_commands", "connected");
ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
GetPlatformAppWindow()));
// Flush any pending events to make sure we start with a clean slate.
content::RunAllPendingInMessageLoop();
ExtensionTestMessageListener copy_listener("copy", false);
SendCopyKeyPressToPlatformApp();
// Wait for the guest to receive a 'copy' edit command.
ASSERT_TRUE(copy_listener.WaitUntilSatisfied());
}
// Tests that guests receive edit commands and respond appropriately.
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, EditCommandsNoMenu) {
SetupTest("web_view/edit_commands_no_menu",
"/extensions/platform_apps/web_view/edit_commands_no_menu/"
"guest.html");
ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
GetPlatformAppWindow()));
// Flush any pending events to make sure we start with a clean slate.
content::RunAllPendingInMessageLoop();
ExtensionTestMessageListener start_of_line_listener("StartOfLine", false);
SendStartOfLineKeyPressToPlatformApp();
#if defined(OS_MACOSX)
// On macOS, sending an accelerator [key-down] will also cause the subsequent
// key-up to be swallowed. The implementation of guest.html is waiting for a
// key-up to send the caret-position message. So we send a key-down/key-up of
// a character that otherwise has no effect.
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_UP, false, false, false, false));
#endif
// Wait for the guest to receive a 'copy' edit command.
ASSERT_TRUE(start_of_line_listener.WaitUntilSatisfied());
}
IN_PROC_BROWSER_TEST_F(WebViewNewWindowInteractiveTest,
NewWindow_AttachAfterOpenerDestroyed) {
TestHelper("testNewWindowAttachAfterOpenerDestroyed",
"web_view/newwindow",
NEEDS_TEST_SERVER);
}
IN_PROC_BROWSER_TEST_F(WebViewNewWindowInteractiveTest,
NewWindow_NewWindowNameTakesPrecedence) {
TestHelper("testNewWindowNameTakesPrecedence",
"web_view/newwindow",
NEEDS_TEST_SERVER);
}
IN_PROC_BROWSER_TEST_F(WebViewNewWindowInteractiveTest,
NewWindow_WebViewNameTakesPrecedence) {
TestHelper("testNewWindowWebViewNameTakesPrecedence", "web_view/newwindow",
NEEDS_TEST_SERVER);
}
IN_PROC_BROWSER_TEST_F(WebViewNewWindowInteractiveTest, NewWindow_NoName) {
TestHelper("testNewWindowNoName",
"web_view/newwindow",
NEEDS_TEST_SERVER);
}
IN_PROC_BROWSER_TEST_F(WebViewNewWindowInteractiveTest, NewWindow_Redirect) {
TestHelper("testNewWindowRedirect",
"web_view/newwindow",
NEEDS_TEST_SERVER);
}
IN_PROC_BROWSER_TEST_F(WebViewNewWindowInteractiveTest, NewWindow_Close) {
TestHelper("testNewWindowClose",
"web_view/newwindow",
NEEDS_TEST_SERVER);
}
IN_PROC_BROWSER_TEST_F(WebViewNewWindowInteractiveTest,
NewWindow_DeferredAttachment) {
TestHelper("testNewWindowDeferredAttachment",
"web_view/newwindow",
NEEDS_TEST_SERVER);
}
IN_PROC_BROWSER_TEST_F(WebViewNewWindowInteractiveTest,
NewWindow_ExecuteScript) {
TestHelper("testNewWindowExecuteScript",
"web_view/newwindow",
NEEDS_TEST_SERVER);
}
IN_PROC_BROWSER_TEST_F(WebViewNewWindowInteractiveTest,
NewWindow_DeclarativeWebRequest) {
TestHelper("testNewWindowDeclarativeWebRequest",
"web_view/newwindow",
NEEDS_TEST_SERVER);
}
IN_PROC_BROWSER_TEST_F(WebViewNewWindowInteractiveTest,
NewWindow_DiscardAfterOpenerDestroyed) {
TestHelper("testNewWindowDiscardAfterOpenerDestroyed",
"web_view/newwindow",
NEEDS_TEST_SERVER);
}
IN_PROC_BROWSER_TEST_F(WebViewNewWindowInteractiveTest, NewWindow_WebRequest) {
TestHelper("testNewWindowWebRequest",
"web_view/newwindow",
NEEDS_TEST_SERVER);
}
// A custom elements bug needs to be addressed to enable this test:
// See http://crbug.com/282477 for more information.
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest,
DISABLED_NewWindow_WebRequestCloseWindow) {
TestHelper("testNewWindowWebRequestCloseWindow",
"web_view/newwindow",
NEEDS_TEST_SERVER);
}
IN_PROC_BROWSER_TEST_F(WebViewNewWindowInteractiveTest,
NewWindow_WebRequestRemoveElement) {
TestHelper("testNewWindowWebRequestRemoveElement",
"web_view/newwindow",
NEEDS_TEST_SERVER);
}
// There is a problem of missing keyup events with the command key after
// the NSEvent is sent to NSApplication in ui/base/test/ui_controls_mac.mm .
// This test is disabled on only the Mac until the problem is resolved.
// See http://crbug.com/425859 for more information.
#if !defined(OS_MACOSX)
// Tests that Ctrl+Click/Cmd+Click on a link fires up the newwindow API.
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_OpenInNewTab) {
content::WebContents* embedder_web_contents = NULL;
ExtensionTestMessageListener loaded_listener("Loaded", false);
std::unique_ptr<ExtensionTestMessageListener> done_listener(
RunAppHelper("testNewWindowOpenInNewTab", "web_view/newwindow",
NEEDS_TEST_SERVER, &embedder_web_contents));
EXPECT_TRUE(loaded_listener.WaitUntilSatisfied());
#if defined(OS_MACOSX)
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_RETURN,
false, false, false, true /* cmd */));
#else
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_RETURN,
true /* ctrl */, false, false, false));
#endif
// Wait for the embedder to receive a 'newwindow' event.
ASSERT_TRUE(done_listener->WaitUntilSatisfied());
}
#endif
IN_PROC_BROWSER_TEST_F(WebViewNewWindowInteractiveTest,
NewWindow_OpenerDestroyedWhileUnattached) {
TestHelper("testNewWindowOpenerDestroyedWhileUnattached",
"web_view/newwindow",
NEEDS_TEST_SERVER);
ASSERT_EQ(2u, GetGuestViewManager()->num_guests_created());
// We have two guests in this test, one is the intial one, the other
// is the newwindow one.
// Before the embedder goes away, both the guests should go away.
// This ensures that unattached guests are gone if opener is gone.
GetGuestViewManager()->WaitForAllGuestsDeleted();
}
// Tests whether <webview> context menu sees <webview> local coordinates
// in its RenderViewContextMenu params.
// Local coordinates are required for plugin actions to work properly.
//
// This test is not needed in --use-cross-process-frames-for-guests,
// since it tests that the <webview> sees local coordinates, which is not
// true with the out-of-process iframes architecture. In that case, the
// <webview> sees transformed coordinates, the point is transformed in
// CrossProcessFrameConnector::TransformPointToRootCoordSpace.
IN_PROC_BROWSER_TEST_F(WebViewContextMenuBrowserPluginSpecificInteractiveTest,
DISABLED_ContextMenuParamCoordinates) {
ASSERT_FALSE(
base::FeatureList::IsEnabled(features::kGuestViewCrossProcessFrames));
TestHelper("testCoordinates", "web_view/context_menus/coordinates",
NO_TEST_SERVER);
ASSERT_TRUE(guest_web_contents());
ContextMenuWaiter menu_observer;
SimulateRWHMouseClick(guest_web_contents()->GetRenderViewHost()->GetWidget(),
blink::WebMouseEvent::Button::kRight, 10, 20);
// Wait until the context menu is opened and closed.
menu_observer.WaitForMenuOpenAndClose();
ASSERT_EQ(10, menu_observer.params().x);
ASSERT_EQ(20, menu_observer.params().y);
}
// https://crbug.com/754890: The embedder could become out of sync and think
// that the guest is not focused when the guest actually was.
// TODO(crbug.com/807116): Flaky on the Linux MSAN bot.
#if defined(OS_LINUX)
#define MAYBE_EnsureFocusSynced DISABLED_EnsureFocusSynced
#else
#define MAYBE_EnsureFocusSynced EnsureFocusSynced
#endif
IN_PROC_BROWSER_TEST_F(WebViewBrowserPluginSpecificInteractiveTest,
MAYBE_EnsureFocusSynced) {
LoadAndLaunchPlatformApp("web_view/focus_sync", "WebViewTest.LAUNCHED");
content::WebContents* embedder_web_contents = GetFirstAppWindowWebContents();
content::WebContents* guest_web_contents =
GetGuestViewManager()->WaitForSingleGuestCreated();
content::MainThreadFrameObserver embedder_observer(
embedder_web_contents->GetMainFrame()->GetView()->GetRenderWidgetHost());
content::MainThreadFrameObserver guest_observer(
guest_web_contents->GetMainFrame()->GetView()->GetRenderWidgetHost());
embedder_observer.Wait();
guest_observer.Wait();
ExtensionTestMessageListener listener{"WebViewTest.WEBVIEW_LOADED", false};
EXPECT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow()));
EXPECT_TRUE(content::ExecuteScript(embedder_web_contents,
"chrome.app.window.getAll()[0].focus()"));
// Embedder should be focused.
EXPECT_EQ(guest_web_contents,
content::GetFocusedWebContents(guest_web_contents));
EXPECT_TRUE(listener.WaitUntilSatisfied());
// Check that the inner contents is correctly focused.
bool result;
EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
guest_web_contents,
"window.requestAnimationFrame(function() {"
" window.domAutomationController.send(checkValid());"
"});",
&result));
EXPECT_TRUE(result);
listener.Reset();
EXPECT_TRUE(
content::ExecuteScript(embedder_web_contents, "reloadWebview();"));
EXPECT_TRUE(listener.WaitUntilSatisfied());
// Check that the inner contents is correctly focused after a reload.
EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
guest_web_contents,
"window.requestAnimationFrame(function() {"
" window.domAutomationController.send(checkValid());"
"});",
&result));
EXPECT_TRUE(result);
}
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, ExecuteCode) {
ASSERT_TRUE(RunPlatformAppTestWithArg(
"platform_apps/web_view/common", "execute_code")) << message_;
}
IN_PROC_BROWSER_TEST_F(DISABLED_WebViewPopupInteractiveTest,
PopupPositioningBasic) {
TestHelper("testBasic", "web_view/popup_positioning", NO_TEST_SERVER);
ASSERT_TRUE(guest_web_contents());
PopupTestHelper(gfx::Point());
// TODO(lazyboy): Move the embedder window to a random location and
// make sure we keep rendering popups correct in webview.
}
// Flaky on ChromeOS and Linux: http://crbug.com/526886
// TODO(crbug.com/807446): Flaky on Mac.
// TODO(crbug.com/809383): Flaky on Windows.
// Tests that moving browser plugin (without resize/UpdateRects) correctly
// repositions popup.
IN_PROC_BROWSER_TEST_F(DISABLED_WebViewPopupInteractiveTest,
PopupPositioningMoved) {
TestHelper("testMoved", "web_view/popup_positioning", NO_TEST_SERVER);
ASSERT_TRUE(guest_web_contents());
PopupTestHelper(gfx::Point(20, 0));
}
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Navigation) {
TestHelper("testNavigation", "web_view/navigation", NO_TEST_SERVER);
}
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Navigation_BackForwardKeys) {
LoadAndLaunchPlatformApp("web_view/navigation", "Launched");
ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
GetPlatformAppWindow()));
// Flush any pending events to make sure we start with a clean slate.
content::RunAllPendingInMessageLoop();
content::WebContents* embedder_web_contents = GetFirstAppWindowWebContents();
ASSERT_TRUE(embedder_web_contents);
ExtensionTestMessageListener done_listener(
"TEST_PASSED", false);
done_listener.set_failure_message("TEST_FAILED");
ExtensionTestMessageListener ready_back_key_listener(
"ReadyForBackKey", false);
ExtensionTestMessageListener ready_forward_key_listener(
"ReadyForForwardKey", false);
EXPECT_TRUE(content::ExecuteScript(
embedder_web_contents,
"runTest('testBackForwardKeys')"));
ASSERT_TRUE(ready_back_key_listener.WaitUntilSatisfied());
SendBackShortcutToPlatformApp();
ASSERT_TRUE(ready_forward_key_listener.WaitUntilSatisfied());
SendForwardShortcutToPlatformApp();
ASSERT_TRUE(done_listener.WaitUntilSatisfied());
}
// Trips over a DCHECK in content::MouseLockDispatcher::OnLockMouseACK; see
// https://crbug.com/761783.
#if defined(OS_WIN)
#define MAYBE_PointerLock_PointerLockLostWithFocus \
PointerLock_PointerLockLostWithFocus
#else
#define MAYBE_PointerLock_PointerLockLostWithFocus \
DISABLED_PointerLock_PointerLockLostWithFocus
#endif
IN_PROC_BROWSER_TEST_F(WebViewPointerLockInteractiveTest,
MAYBE_PointerLock_PointerLockLostWithFocus) {
TestHelper("testPointerLockLostWithFocus",
"web_view/pointerlock",
NO_TEST_SERVER);
}
// Disable this on mac, throws an assertion failure on teardown which
// will result in flakiness:
//
// "not is fullscreen state"
// "*** Assertion failure in -[_NSWindowFullScreenTransition
// transitionedWindowFrame],"
// See similar bug: http://crbug.com/169820.
//
// In addition to the above, these tests are flaky on some platforms:
// http://crbug.com/468660
#if defined(OS_WIN)
#define MAYBE_FullscreenAllow_EmbedderHasPermission \
FullscreenAllow_EmbedderHasPermission
#else
#define MAYBE_FullscreenAllow_EmbedderHasPermission \
DISABLED_FullscreenAllow_EmbedderHasPermission
#endif
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest,
MAYBE_FullscreenAllow_EmbedderHasPermission) {
FullscreenTestHelper("testFullscreenAllow",
"web_view/fullscreen/embedder_has_permission");
}
#if defined(OS_WIN)
#define MAYBE_FullscreenDeny_EmbedderHasPermission \
FullscreenDeny_EmbedderHasPermission
#else
#define MAYBE_FullscreenDeny_EmbedderHasPermission \
DISABLED_FullscreenDeny_EmbedderHasPermission
#endif
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest,
MAYBE_FullscreenDeny_EmbedderHasPermission) {
FullscreenTestHelper("testFullscreenDeny",
"web_view/fullscreen/embedder_has_permission");
}
#if defined(OS_WIN)
#define MAYBE_FullscreenAllow_EmbedderHasNoPermission \
FullscreenAllow_EmbedderHasNoPermission
#else
#define MAYBE_FullscreenAllow_EmbedderHasNoPermission \
DISABLED_FullscreenAllow_EmbedderHasNoPermission
#endif
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest,
MAYBE_FullscreenAllow_EmbedderHasNoPermission) {
FullscreenTestHelper("testFullscreenAllow",
"web_view/fullscreen/embedder_has_no_permission");
}
#if defined(OS_WIN)
#define MAYBE_FullscreenDeny_EmbedderHasNoPermission \
FullscreenDeny_EmbedderHasNoPermission
#else
#define MAYBE_FullscreenDeny_EmbedderHasNoPermission \
DISABLED_FullscreenDeny_EmbedderHasNoPermission
#endif
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest,
MAYBE_FullscreenDeny_EmbedderHasNoPermission) {
FullscreenTestHelper("testFullscreenDeny",
"web_view/fullscreen/embedder_has_no_permission");
}
// This test exercies the following scenario:
// 1. An <input> in guest has focus.
// 2. User takes focus to embedder by clicking e.g. an <input> in embedder.
// 3. User brings back the focus directly to the <input> in #1.
//
// Now we need to make sure TextInputTypeChanged fires properly for the guest's
// view upon step #3. We simply read the input type's state after #3 to
// make sure it's not TEXT_INPUT_TYPE_NONE.
IN_PROC_BROWSER_TEST_F(WebViewFocusInteractiveTest, Focus_FocusRestored) {
TestHelper("testFocusRestored", "web_view/focus", NO_TEST_SERVER);
content::WebContents* embedder_web_contents = GetFirstAppWindowWebContents();
ASSERT_TRUE(embedder_web_contents);
ASSERT_TRUE(guest_web_contents());
// 1) We click on the guest so that we get a focus event.
ExtensionTestMessageListener next_step_listener("TEST_STEP_PASSED", false);
next_step_listener.set_failure_message("TEST_STEP_FAILED");
{
content::SimulateMouseClickAt(guest_web_contents(), 0,
blink::WebMouseEvent::Button::kLeft,
gfx::Point(10, 10));
EXPECT_TRUE(content::ExecuteScript(
embedder_web_contents,
"window.runCommand('testFocusRestoredRunNextStep', 1);"));
}
// Wait for the next step to complete.
ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
// 2) We click on the embedder so the guest's focus goes away and it observes
// a blur event.
next_step_listener.Reset();
{
content::SimulateMouseClickAt(embedder_web_contents, 0,
blink::WebMouseEvent::Button::kLeft,
gfx::Point(200, 20));
EXPECT_TRUE(content::ExecuteScript(
embedder_web_contents,
"window.runCommand('testFocusRestoredRunNextStep', 2);"));
}
// Wait for the next step to complete.
ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
// 3) We click on the guest again to bring back focus directly to the previous
// input element, then we ensure text_input_type is properly set.
next_step_listener.Reset();
{
content::SimulateMouseClickAt(guest_web_contents(), 0,
blink::WebMouseEvent::Button::kLeft,
gfx::Point(10, 10));
EXPECT_TRUE(content::ExecuteScript(
embedder_web_contents,
"window.runCommand('testFocusRestoredRunNextStep', 3)"));
}
// Wait for the next step to complete.
ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
// |text_input_client| is not available for mac and android.
#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
ui::TextInputClient* text_input_client =
embedder_web_contents->GetRenderViewHost()
->GetWidget()
->GetView()
->GetTextInputClient();
ASSERT_TRUE(text_input_client);
ASSERT_TRUE(text_input_client->GetTextInputType() !=
ui::TEXT_INPUT_TYPE_NONE);
#endif
}
// ui::TextInputClient is NULL for mac and android.
#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, DISABLED_Focus_InputMethod) {
content::WebContents* embedder_web_contents = NULL;
std::unique_ptr<ExtensionTestMessageListener> done_listener(
RunAppHelper("testInputMethod", "web_view/focus", NO_TEST_SERVER,
&embedder_web_contents));
ASSERT_TRUE(done_listener->WaitUntilSatisfied());
ui::TextInputClient* text_input_client =
embedder_web_contents->GetRenderViewHost()
->GetWidget()
->GetView()
->GetTextInputClient();
ASSERT_TRUE(text_input_client);
ExtensionTestMessageListener next_step_listener("TEST_STEP_PASSED", false);
next_step_listener.set_failure_message("TEST_STEP_FAILED");
// An input element inside the <webview> gets focus and is given some
// user input via IME.
{
ui::CompositionText composition;
composition.text = base::UTF8ToUTF16("InputTest123");
text_input_client->SetCompositionText(composition);
EXPECT_TRUE(content::ExecuteScript(
embedder_web_contents,
"window.runCommand('testInputMethodRunNextStep', 1);"));
// Wait for the next step to complete.
ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
}
// A composition is committed via IME.
{
next_step_listener.Reset();
ui::CompositionText composition;
composition.text = base::UTF8ToUTF16("InputTest456");
text_input_client->SetCompositionText(composition);
text_input_client->ConfirmCompositionText();
EXPECT_TRUE(content::ExecuteScript(
embedder_web_contents,
"window.runCommand('testInputMethodRunNextStep', 2);"));
// Wait for the next step to complete.
ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
}
// TODO(lazyboy): http://crbug.com/457007, Add a step or a separate test to
// check the following, currently it turns this test to be flaky:
// If we move the focus from the first <input> to the second one after we
// have some composition text set but *not* committed (by calling
// text_input_client->SetCompositionText()), then it would cause IME cancel
// and the onging composition is committed in the first <input> in the
// <webview>, not the second one.
// Tests ExtendSelectionAndDelete message works in <webview>.
{
next_step_listener.Reset();
// At this point we have set focus on first <input> in the <webview>,
// and the value it contains is 'InputTest456' with caret set after 'T'.
// Now we delete 'Test' in 'InputTest456', as the caret is after 'T':
// delete before 1 character ('T') and after 3 characters ('est').
text_input_client->ExtendSelectionAndDelete(1, 3);
EXPECT_TRUE(content::ExecuteScript(
embedder_web_contents,
"window.runCommand('testInputMethodRunNextStep', 3);"));
// Wait for the next step to complete.
ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
}
}
#endif
#if defined(OS_LINUX) // TODO(https://crbug.com/801552): Flaky.
#define MAYBE_LongPressSelection DISABLED_LongPressSelection
#else
#define MAYBE_LongPressSelection LongPressSelection
#endif
#if !defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, MAYBE_LongPressSelection) {
SetupTest("web_view/text_selection",
"/extensions/platform_apps/web_view/text_selection/guest.html");
ASSERT_TRUE(guest_web_contents());
ASSERT_TRUE(embedder_web_contents());
ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow()));
blink::WebInputEvent::Type context_menu_gesture_event_type =
blink::WebInputEvent::kGestureLongPress;
#if defined(OS_WIN)
context_menu_gesture_event_type = blink::WebInputEvent::kGestureLongTap;
#endif
auto filter = std::make_unique<content::InputMsgWatcher>(
guest_web_contents()->GetRenderWidgetHostView()->GetRenderWidgetHost(),
context_menu_gesture_event_type);
// Wait for guest to load (without this the events never reach the guest).
scoped_refptr<content::MessageLoopRunner> message_loop_runner =
new content::MessageLoopRunner;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, message_loop_runner->QuitClosure(),
base::TimeDelta::FromMilliseconds(200));
message_loop_runner->Run();
gfx::Rect guest_rect = guest_web_contents()->GetContainerBounds();
gfx::Point embedder_origin =
embedder_web_contents()->GetContainerBounds().origin();
guest_rect.Offset(-embedder_origin.x(), -embedder_origin.y());
// Mouse click is necessary for focus.
content::SimulateMouseClickAt(embedder_web_contents(), 0,
blink::WebMouseEvent::Button::kLeft,
guest_rect.CenterPoint());
content::SimulateLongTapAt(embedder_web_contents(), guest_rect.CenterPoint());
EXPECT_EQ(content::INPUT_EVENT_ACK_STATE_CONSUMED,
filter->GetAckStateWaitIfNecessary());
// Give enough time for the quick menu to fire.
message_loop_runner = new content::MessageLoopRunner;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, message_loop_runner->QuitClosure(),
base::TimeDelta::FromMilliseconds(200));
message_loop_runner->Run();
// TODO: Fix quick menu opening on Windows.
#if !defined(OS_WIN)
EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
#endif
EXPECT_FALSE(guest_web_contents()->IsShowingContextMenu());
}
#endif
#if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, TextSelection) {
SetupTest("web_view/text_selection",
"/extensions/platform_apps/web_view/text_selection/guest.html");
ASSERT_TRUE(guest_web_contents());
ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
GetPlatformAppWindow()));
// Wait until guest sees a context menu.
ExtensionTestMessageListener ctx_listener("MSG_CONTEXTMENU", false);
ContextMenuWaiter menu_observer;
SimulateRWHMouseClick(guest_web_contents()->GetRenderViewHost()->GetWidget(),
blink::WebMouseEvent::Button::kRight, 20, 20);
menu_observer.WaitForMenuOpenAndClose();
ASSERT_TRUE(ctx_listener.WaitUntilSatisfied());
// Now verify that the selection text propagates properly to RWHV.
content::RenderWidgetHostView* guest_rwhv =
guest_web_contents()->GetRenderWidgetHostView();
ASSERT_TRUE(guest_rwhv);
std::string selected_text = base::UTF16ToUTF8(guest_rwhv->GetSelectedText());
ASSERT_GE(selected_text.size(), 10u);
ASSERT_EQ("AAAAAAAAAA", selected_text.substr(0, 10));
}
// Verifies that asking for a word lookup from a guest will lead to a returned
// IPC from the renderer containing the right selected word.
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, WordLookup) {
// BrowserClientForTextInputClientMac needs to replace the
// ChromeContentBrowserClient after most things are initialized but before the
// WebContents is created.
BrowserClientForTextInputClientMac browser_client;
SetupTest("web_view/text_selection",
"/extensions/platform_apps/web_view/text_selection/guest.html");
ASSERT_TRUE(guest_web_contents());
ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow()));
auto guest_message_filter =
browser_client.GetTextInputClientMessageFilterForProcess(
guest_web_contents()->GetMainFrame()->GetProcess());
ASSERT_TRUE(guest_message_filter);
// Lookup some string through context menu.
ContextMenuNotificationObserver menu_observer(IDC_CONTENT_CONTEXT_LOOK_UP);
// Simulating a mouse click at a position to highlight text in guest and
// showing the context menu.
SimulateRWHMouseClick(guest_web_contents()->GetRenderViewHost()->GetWidget(),
blink::WebMouseEvent::Button::kRight, 20, 20);
// Wait for the response form the guest renderer.
guest_message_filter->WaitForStringFromRange();
// Sanity check.
ASSERT_EQ("AAAA", guest_message_filter->string_from_range().substr(0, 4));
}
#endif
// Flaky on Mac: http://crbug.com/811893
// Flaky on Linux/ChromeOS/Windows: http://crbug.com/845638
#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
defined(OS_WIN)
#define MAYBE_FocusAndVisibility DISABLED_FocusAndVisibility
#else
#define MAYBE_FocusAndVisibility FocusAndVisibility
#endif
IN_PROC_BROWSER_TEST_F(WebViewFocusInteractiveTest, MAYBE_FocusAndVisibility) {
ASSERT_TRUE(StartEmbeddedTestServer());
LoadAndLaunchPlatformApp("web_view/focus_visibility",
"WebViewInteractiveTest.LOADED");
ExtensionTestMessageListener test_init_listener(
"WebViewInteractiveTest.WebViewInitialized", false);
SendMessageToEmbedder("init-oopif");
EXPECT_TRUE(test_init_listener.WaitUntilSatisfied());
// Send several tab-keys. The button inside webview should receive focus at
// least once.
ExtensionTestMessageListener key_processed_listener(
"WebViewInteractiveTest.KeyUp", false);
#if defined(OS_MACOSX)
// On mac, the event listener seems one key event behind and deadlocks. Send
// an extra tab to get things unblocked. See http://crbug.com/685281 when
// fixed, this can be removed.
SendKeyPressToPlatformApp(ui::VKEY_TAB);
#endif
for (size_t i = 0; i < 4; ++i) {
key_processed_listener.Reset();
SendKeyPressToPlatformApp(ui::VKEY_TAB);
EXPECT_TRUE(key_processed_listener.WaitUntilSatisfied());
}
// Verify that the button in the guest receives focus.
ExtensionTestMessageListener webview_button_focused_listener(
"WebViewInteractiveTest.WebViewButtonWasFocused", false);
webview_button_focused_listener.set_failure_message(
"WebViewInteractiveTest.WebViewButtonWasNotFocused");
SendMessageToEmbedder("verify");
EXPECT_TRUE(webview_button_focused_listener.WaitUntilSatisfied());
// Reset the test and now make the <webview> invisible.
ExtensionTestMessageListener reset_listener("WebViewInteractiveTest.DidReset",
false);
SendMessageToEmbedder("reset");
EXPECT_TRUE(reset_listener.WaitUntilSatisfied());
ExtensionTestMessageListener did_hide_webview_listener(
"WebViewInteractiveTest.DidHideWebView", false);
SendMessageToEmbedder("hide-webview");
EXPECT_TRUE(did_hide_webview_listener.WaitUntilSatisfied());
// Send the same number of keys and verify that the webview button was not
// this time.
for (size_t i = 0; i < 4; ++i) {
key_processed_listener.Reset();
SendKeyPressToPlatformApp(ui::VKEY_TAB);
EXPECT_TRUE(key_processed_listener.WaitUntilSatisfied());
}
ExtensionTestMessageListener webview_button_not_focused_listener(
"WebViewInteractiveTest.WebViewButtonWasNotFocused", false);
webview_button_not_focused_listener.set_failure_message(
"WebViewInteractiveTest.WebViewButtonWasFocused");
SendMessageToEmbedder("verify");
EXPECT_TRUE(webview_button_not_focused_listener.WaitUntilSatisfied());
}
// Flaky on MacOSX, crbug.com/817066.
// Flaky timeouts on Linux. https://crbug.com/709202
// Flaky timeouts on Win. https://crbug.com/846695
#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
#define MAYBE_KeyboardFocusSimple DISABLED_KeyboardFocusSimple
#else
#define MAYBE_KeyboardFocusSimple KeyboardFocusSimple
#endif
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, MAYBE_KeyboardFocusSimple) {
TestHelper("testKeyboardFocusSimple", "web_view/focus", NO_TEST_SERVER);
EXPECT_EQ(embedder_web_contents()->GetFocusedFrame(),
embedder_web_contents()->GetMainFrame());
ExtensionTestMessageListener next_step_listener("TEST_STEP_PASSED", false);
next_step_listener.set_failure_message("TEST_STEP_FAILED");
{
gfx::Rect offset = embedder_web_contents()->GetContainerBounds();
// Click the <input> element inside the <webview>.
// If we wanted, we could ask the embedder to compute an appropriate point.
MoveMouseInsideWindow(gfx::Point(offset.x() + 40, offset.y() + 40));
SendMouseClick(ui_controls::LEFT);
}
// Waits for the renderer to know the input has focus.
ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_A, false, false, false, false));
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_B, false, true, false, false));
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_C, false, false, false, false));
next_step_listener.Reset();
EXPECT_TRUE(content::ExecuteScript(
embedder_web_contents(),
"window.runCommand('testKeyboardFocusRunNextStep', 'aBc');"));
ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
}
// Ensures that input is routed to the webview after the containing window loses
// and regains focus. Additionally, the webview does not process keypresses sent
// while another window is focused.
// http://crbug.com/660044.
// Flaky on MacOSX, crbug.com/817067.
// Flaky on linux, crbug.com/706830.
// Flaky on Windows, crbug.com/847201.
#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
#define MAYBE_KeyboardFocusWindowCycle DISABLED_KeyboardFocusWindowCycle
#else
#define MAYBE_KeyboardFocusWindowCycle KeyboardFocusWindowCycle
#endif
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, MAYBE_KeyboardFocusWindowCycle) {
TestHelper("testKeyboardFocusWindowFocusCycle", "web_view/focus",
NO_TEST_SERVER);
EXPECT_EQ(embedder_web_contents()->GetFocusedFrame(),
embedder_web_contents()->GetMainFrame());
ExtensionTestMessageListener next_step_listener("TEST_STEP_PASSED", false);
next_step_listener.set_failure_message("TEST_STEP_FAILED");
{
gfx::Rect offset = embedder_web_contents()->GetContainerBounds();
// Click the <input> element inside the <webview>.
// If we wanted, we could ask the embedder to compute an appropriate point.
MoveMouseInsideWindow(gfx::Point(offset.x() + 40, offset.y() + 40));
SendMouseClick(ui_controls::LEFT);
}
// Waits for the renderer to know the input has focus.
ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_A, false, false, false, false));
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_B, false, true, false, false));
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_C, false, false, false, false));
const extensions::Extension* extension =
LoadAndLaunchPlatformApp("minimal", "Launched");
extensions::AppWindow* window = GetFirstAppWindowForApp(extension->id());
EXPECT_TRUE(content::ExecuteScript(
embedder_web_contents(),
"window.runCommand('monitorGuestEvent', 'focus');"));
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_F, false, false, false, false));
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_O, false, true, false, false));
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_O, false, true, false, false));
// Close the other window and wait for the webview to regain focus.
CloseAppWindow(window);
ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow()));
next_step_listener.Reset();
EXPECT_TRUE(
content::ExecuteScript(embedder_web_contents(),
"window.runCommand('waitGuestEvent', 'focus');"));
ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_X, false, false, false, false));
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_Y, false, true, false, false));
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
GetPlatformAppWindow(), ui::VKEY_Z, false, false, false, false));
next_step_listener.Reset();
EXPECT_TRUE(content::ExecuteScript(
embedder_web_contents(),
"window.runCommand('testKeyboardFocusRunNextStep', 'aBcxYz');"));
ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
}
#if defined(OS_MACOSX)
// This test verifies that replacement range for IME works with <webview>s. To
// verify this, a <webview> with an <input> inside is loaded. Then the <input>
// is focused and populated with some text. The test then sends an IPC to
// commit some text which will replace part of the previous text some new text.
IN_PROC_BROWSER_TEST_F(WebViewImeInteractiveTest,
CommitTextWithReplacementRange) {
ASSERT_TRUE(StartEmbeddedTestServer()); // For serving guest pages.
LoadAndLaunchPlatformApp("web_view/ime", "WebViewImeTest.Launched");
ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow()));
// Flush any pending events to make sure we start with a clean slate.
content::RunAllPendingInMessageLoop();
content::WebContents* guest_web_contents =
GetGuestViewManager()->GetLastGuestCreated();
// Click the <input> element inside the <webview>. In its focus handle, the
// <input> inside the <webview> initializes its value to "A B X D".
ExtensionTestMessageListener focus_listener("WebViewImeTest.InputFocused",
false);
content::WebContents* target_web_contents = guest_web_contents;
// The guest page has a large input box and (50, 50) lies inside the box.
content::SimulateMouseClickAt(target_web_contents, 0,
blink::WebMouseEvent::Button::kLeft,
gfx::Point(50, 50));
EXPECT_TRUE(focus_listener.WaitUntilSatisfied());
// Verify the text inside the <input> is "A B X D".
std::string value;
ASSERT_TRUE(ExecuteScriptAndExtractString(guest_web_contents,
"window.domAutomationController."
"send(document.querySelector('"
"input').value)",
&value));
EXPECT_EQ("A B X D", value);
// Now commit "C" to to replace the range (4, 5).
// For OOPIF guests, the target for IME is the RWH for the guest's main frame.
// For BrowserPlugin-based guests, input always goes to the embedder.
ExtensionTestMessageListener input_listener("WebViewImetest.InputReceived",
false);
content::RenderWidgetHost* target_rwh_for_input =
target_web_contents->GetRenderWidgetHostView()->GetRenderWidgetHost();
content::SendImeCommitTextToWidget(
target_rwh_for_input, base::UTF8ToUTF16("C"),
std::vector<ui::ImeTextSpan>(), gfx::Range(4, 5), 0);
EXPECT_TRUE(input_listener.WaitUntilSatisfied());
// Get the input value from the guest.
value.clear();
ASSERT_TRUE(ExecuteScriptAndExtractString(guest_web_contents,
"window.domAutomationController."
"send(document.querySelector('"
"input').value)",
&value));
EXPECT_EQ("A B C D", value);
}
#endif // OS_MACOSX
// This test verifies that focusing an input inside a <webview> will put the
// guest process's render widget into a monitoring mode for composition range
// changes.
IN_PROC_BROWSER_TEST_F(WebViewImeInteractiveTest, CompositionRangeUpdates) {
ASSERT_TRUE(StartEmbeddedTestServer()); // For serving guest pages.
LoadAndLaunchPlatformApp("web_view/ime", "WebViewImeTest.Launched");
ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow()));
// Flush any pending events to make sure we start with a clean slate.
content::RunAllPendingInMessageLoop();
content::WebContents* guest_web_contents =
GetGuestViewManager()->GetLastGuestCreated();
// Click the <input> element inside the <webview>. In its focus handle, the
// <input> inside the <webview> initializes its value to "A B X D".
ExtensionTestMessageListener focus_listener("WebViewImeTest.InputFocused",
false);
content::WebContents* embedder_web_contents =
guest_view::GuestViewBase::FromWebContents(guest_web_contents)
->embedder_web_contents();
// Event routing in OOPIF and non-OOPIF <webview> is different. With OOPIF,
// input is directly routed to the guest process as opposed to the non OOPIF
// mode where input is always sent to the embedder process first (then hops
// back to the browser and then to the guest).
content::WebContents* target_web_contents = guest_web_contents;
// The guest page has a large input box and (50, 50) lies inside the box.
content::SimulateMouseClickAt(target_web_contents, 0,
blink::WebMouseEvent::Button::kLeft,
gfx::Point(50, 50));
EXPECT_TRUE(focus_listener.WaitUntilSatisfied());
// Clear the string as it already contains some text. Then verify the text in
// the <input> is empty.
std::string value;
ASSERT_TRUE(ExecuteScriptAndExtractString(
guest_web_contents,
"var input = document.querySelector('input');"
"input.value = '';"
"window.domAutomationController.send("
" document.querySelector('input').value)",
&value));
EXPECT_EQ("", value);
// Now set some composition text which should lead to an update in composition
// range information.
CompositionRangeUpdateObserver observer(embedder_web_contents);
content::SendImeSetCompositionTextToWidget(
target_web_contents->GetRenderWidgetHostView()->GetRenderWidgetHost(),
base::UTF8ToUTF16("ABC"), std::vector<ui::ImeTextSpan>(),
gfx::Range::InvalidRange(), 0, 3);
observer.WaitForCompositionRangeLength(3U);
}
#if defined(OS_MACOSX)
// This test verifies that drop-down lists appear correctly inside OOPIF-based
// webviews which have offset inside embedder. This is a test for all guest
// views as the logic for showing such popups is inside content/ layer. For more
// context see https://crbug.com/772840.
IN_PROC_BROWSER_TEST_F(WebViewFocusInteractiveTest,
DropDownPopupInCorrectPosition) {
TestHelper("testSelectPopupPositionInMac", "web_view/shim", NO_TEST_SERVER);
ASSERT_TRUE(guest_web_contents_);
// This is set in javascript.
const float distance_from_root_view_origin = 250.0;
// Verify that the view is offset inside root view as expected.
content::RenderWidgetHostView* guest_rwhv =
guest_web_contents_->GetRenderWidgetHostView();
while (guest_rwhv->TransformPointToRootCoordSpace(gfx::Point())
.OffsetFromOrigin()
.Length() < distance_from_root_view_origin) {
base::RunLoop run_loop;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
run_loop.Run();
}
// Now trigger the popup and wait until it is displayed. The popup will get
// dismissed after being shown.
NewSubViewAddedObserver popup_observer(embedder_web_contents_);
// Now send a mouse click and wait until the <select> tag is focused.
SimulateRWHMouseClick(guest_rwhv->GetRenderWidgetHost(),
blink::WebMouseEvent::Button::kLeft, 5, 5);
popup_observer.WaitForNextSubView();
// Verify the popup bounds intersect with those of the guest. Since the popup
// is relatively small (the width is determined by the <select> element's
// width and the hight is a factor of font-size and number of items), the
// intersection alone is a good indication the popup is shown properly inside
// the screen.
gfx::Rect guest_bounds_in_embedder(
guest_rwhv->TransformPointToRootCoordSpace(gfx::Point()),
guest_rwhv->GetViewBounds().size());
EXPECT_TRUE(guest_bounds_in_embedder.Intersects(
popup_observer.view_bounds_in_screen()))
<< "Guest bounds:" << guest_bounds_in_embedder.ToString()
<< " do not intersect with popup bounds:"
<< popup_observer.view_bounds_in_screen().ToString();
}
#endif