Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1163)

Unified Diff: chrome/browser/drag_and_drop_browsertest.cc

Issue 2478583005: Browser tests for starting a drag-and-drop out of an OOPIF. (Closed)
Patch Set: Integrate the test with the nested drag-and-drop message loop. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | chrome/test/BUILD.gn » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/drag_and_drop_browsertest.cc
diff --git a/content/browser/web_contents/drag_and_drop_browsertest.cc b/chrome/browser/drag_and_drop_browsertest.cc
similarity index 47%
rename from content/browser/web_contents/drag_and_drop_browsertest.cc
rename to chrome/browser/drag_and_drop_browsertest.cc
index 71dfc4765bd61ba0b812ee8707e666878c31d0e8..b5c44dee86706c24437f5be8842089cd8eba826f 100644
--- a/content/browser/web_contents/drag_and_drop_browsertest.cc
+++ b/chrome/browser/drag_and_drop_browsertest.cc
@@ -5,27 +5,33 @@
#include <memory>
#include <string>
+#include "base/callback.h"
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
#include "base/strings/pattern.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
-#include "content/browser/frame_host/frame_tree.h"
-#include "content/browser/frame_host/frame_tree_node.h"
-#include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/browser/web_contents/web_contents_impl.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/interactive_test_utils.h"
+#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_frame_navigation_observer.h"
#include "content/public/test/test_utils.h"
-#include "content/shell/browser/shell.h"
#include "net/base/escape.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/window.h"
@@ -36,7 +42,7 @@
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
-namespace content {
+namespace chrome {
namespace {
@@ -70,7 +76,7 @@ namespace {
// Test helper for simulating drag and drop happening in WebContents.
class DragAndDropSimulator {
public:
- explicit DragAndDropSimulator(WebContents* web_contents)
+ explicit DragAndDropSimulator(content::WebContents* web_contents)
: web_contents_(web_contents) {}
// Simulates notification that |text| was dragged from outside of the browser,
@@ -157,30 +163,114 @@ class DragAndDropSimulator {
ui::DragDropTypes::DRAG_COPY |
ui::DragDropTypes::DRAG_LINK;
- WebContents* web_contents_;
+ content::WebContents* web_contents_;
std::unique_ptr<ui::DropTargetEvent> active_drag_event_;
DISALLOW_COPY_AND_ASSIGN(DragAndDropSimulator);
};
+// Helper for waiting until a drag-and-drop nested message loop starts
+// (i.e. in response to a mouse-down + mouse-move simulated by the test)
+// and for running a test continuation inside the nested message loop.
+class DragStartWaiter : public aura::client::DragDropClient {
+ public:
+ using TestContinuationCallback =
+ base::Callback<void(const std::string& text,
+ const std::string& html,
+ int operation,
+ bool did_originate_from_renderer)>;
+
+ // Starts monitoring |web_contents| for a start of a drag-and-drop.
+ // Will call |test_continuation| when drag-and-drop starts.
+ DragStartWaiter(content::WebContents* web_contents,
+ const TestContinuationCallback& test_continuation)
+ : web_contents_(web_contents),
+ test_continuation_(test_continuation),
+ message_loop_runner_(new content::MessageLoopRunner) {
+ DCHECK(web_contents_);
+ DCHECK(!test_continuation_.is_null());
+
+ // Intercept calls to the old DragDropClient.
+ gfx::NativeWindow root_window =
+ web_contents_->GetContentNativeView()->GetRootWindow();
+ old_client_ = aura::client::GetDragDropClient(root_window);
+ aura::client::SetDragDropClient(root_window, this);
+ }
+
+ ~DragStartWaiter() override {
+ // Restore the original DragDropClient.
+ gfx::NativeWindow root_window =
+ web_contents_->GetContentNativeView()->GetRootWindow();
+ aura::client::SetDragDropClient(root_window, old_client_);
+ }
+
+ // Waits until drag-and-drop starts, ensures |test_continuation| is run (see
+ // the constructor) and then returns after the drag-and-drop has ended.
+ void WaitUntilFullDragAndDropCompletes() { message_loop_runner_->Run(); }
+
+ int StartDragAndDrop(const ui::OSExchangeData& data,
+ aura::Window* root_window,
+ aura::Window* source_window,
+ const gfx::Point& screen_location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) override {
+ if (!test_continuation_.is_null()) {
+ base::string16 text;
+ if (!data.GetString(&text))
+ text = base::ASCIIToUTF16("<no text>");
+
+ GURL base_url;
+ base::string16 html;
+ if (!data.GetHtml(&html, &base_url))
+ html = base::ASCIIToUTF16("<no html>");
+
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(std::move(test_continuation_), base::UTF16ToUTF8(text),
+ base::UTF16ToUTF8(html), operation,
+ data.DidOriginateFromRenderer()));
+
+ test_continuation_.Reset();
+ message_loop_runner_->Quit();
+ }
+
+ // This will kick-off a nested message loop and won't return until
+ // drag-and-drop ends.
+ return old_client_->StartDragAndDrop(data, root_window, source_window,
+ screen_location, operation, source);
+ }
+
+ void DragCancel() override { old_client_->DragCancel(); }
+
+ bool IsDragDropInProgress() override {
+ return old_client_->IsDragDropInProgress();
+ }
+
+ private:
+ content::WebContents* web_contents_;
+ DragStartWaiter::TestContinuationCallback test_continuation_;
+ scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+ aura::client::DragDropClient* old_client_;
+};
+
// Helper for waiting for notifications from
// content/test/data/drag_and_drop/event_monitoring.js
class DOMDragEventWaiter {
public:
explicit DOMDragEventWaiter(const std::string& event_type_to_wait_for,
- const ToRenderFrameHost& target)
+ const content::ToRenderFrameHost& target)
: target_frame_name_(target.render_frame_host()->GetFrameName()),
event_type_to_wait_for_(event_type_to_wait_for),
- dom_message_queue_(
- WebContents::FromRenderFrameHost(target.render_frame_host())) {}
+ dom_message_queue_(content::WebContents::FromRenderFrameHost(
+ target.render_frame_host())) {}
// Waits until |target| calls reportDragEvent in
- // content/test/data/drag_and_drop/event_monitoring.js with event_type
+ // chrome/test/data/drag_and_drop/event_monitoring.js with event_type
// property set to |event_type_to_wait_for|. (|target| and
// |event_type_to_wait_for| are passed to the constructor).
//
// Returns the event details via |found_event| (in form of a JSON-encoded
- // object). See content/test/data/drag_and_drop/event_monitoring.js for keys
+ // object). See chrome/test/data/drag_and_drop/event_monitoring.js for keys
// and properties that |found_event| is expected to have.
//
// Returns true upon success. It is okay if |response| is null.
@@ -210,51 +300,85 @@ class DOMDragEventWaiter {
private:
std::string target_frame_name_;
std::string event_type_to_wait_for_;
- DOMMessageQueue dom_message_queue_;
+ content::DOMMessageQueue dom_message_queue_;
};
const char kTestPagePath[] = "/drag_and_drop/page.html";
} // namespace
-class DragAndDropBrowserTest : public ContentBrowserTest {
+class DragAndDropBrowserTest : public InProcessBrowserTest {
public:
DragAndDropBrowserTest(){};
+ // Declarations of test continuations.
+ void DragStartInFrame_Step2(const std::string& frame_site,
+ const std::string& text,
+ const std::string& html,
+ int operation,
+ bool did_originate_from_renderer);
+
protected:
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(embedded_test_server()->Start());
content::SetupCrossSiteRedirector(embedded_test_server());
- drag_simulator_.reset(new DragAndDropSimulator(shell()->web_contents()));
+ drag_simulator_.reset(new DragAndDropSimulator(web_contents()));
}
- // Navigates to content/test/data/drag_and_drop/page.html, with page origin
- // and frame contents being controlled by the parameters.
- bool NavigateToTestPage(const std::string& main_origin,
- const std::string& left_frame,
- const std::string& right_frame) {
- GURL base_url = embedded_test_server()->GetURL(main_origin, kTestPagePath);
-
- std::string left_arg;
- if (!left_frame.empty()) {
- left_arg = net::EscapeQueryParamValue(
- std::string("/cross-site/") + left_frame, true);
- }
- std::string right_arg;
- if (!right_frame.empty()) {
- right_arg = net::EscapeQueryParamValue(
- std::string("/cross-site/") + right_frame, true);
- }
- std::string query = base::StringPrintf("left=%s&right=%s", left_arg.c_str(),
- right_arg.c_str());
- GURL::Replacements query_replacement;
- query_replacement.SetQueryStr(query);
- GURL target_url = base_url.ReplaceComponents(query_replacement);
+ content::RenderFrameHost* left_frame() {
+ AssertTestPageIsLoaded();
+ return GetFrameByName("left");
+ }
+
+ content::RenderFrameHost* right_frame() {
+ AssertTestPageIsLoaded();
+ return GetFrameByName("right");
+ }
+
+ // Navigation helpers.
+
+ bool NavigateToTestPage(const std::string& origin_of_main_frame) {
+ GURL url =
+ embedded_test_server()->GetURL(origin_of_main_frame, kTestPagePath);
+ ui_test_utils::NavigateToURL(browser(), url);
+ return web_contents()->GetLastCommittedURL() == url;
+ }
+
+ // Navigates the left frame to |filename| (found under
+ // chrome/test/data/drag_and_drop directory).
+ bool NavigateLeftFrame(const std::string& origin,
+ const std::string& filename) {
+ AssertTestPageIsLoaded();
+ return NavigateNamedFrame("left", origin, filename);
+ }
+
+ // Navigates the right frame to |filename| (found under
+ // chrome/test/data/drag_and_drop directory).
+ bool NavigateRightFrame(const std::string& origin,
+ const std::string& filename) {
+ AssertTestPageIsLoaded();
+ return NavigateNamedFrame("right", origin, filename);
+ }
+
+ // Drag-and-drop simulation using the mouse.
+
+ bool SimulateMouseDownAndDragStartInLeftFrame() {
+ AssertTestPageIsLoaded();
+ if (!SimulateMouseMove(kMiddleOfLeftFrame) || !SimulateMouseDown() ||
+ !SimulateMouseMove(kMiddleOfLeftFrame + gfx::Vector2d(5, 5)))
+ return false;
+
+ return true;
+ }
- return NavigateToURL(shell(), target_url);
+ bool SimulateMouseUp() {
+ return ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
+ ui_controls::UP);
}
+ // Drag-and-drop simulation via DragAndDropSimulator.
+
bool SimulateDragEnterToRightFrame(const std::string& text) {
AssertTestPageIsLoaded();
return drag_simulator_->SimulateDragEnter(kMiddleOfRightFrame, text);
@@ -265,22 +389,82 @@ class DragAndDropBrowserTest : public ContentBrowserTest {
return drag_simulator_->SimulateDrop(kMiddleOfRightFrame);
}
- RenderFrameHost* right_frame() {
- AssertTestPageIsLoaded();
- return GetFrameByName("right");
+ content::WebContents* web_contents() {
+ return browser()->tab_strip_model()->GetActiveWebContents();
}
private:
- RenderFrameHost* GetFrameByName(const std::string& name_to_find) {
- WebContentsImpl* web_contents =
- static_cast<WebContentsImpl*>(shell()->web_contents());
- FrameTree* frame_tree = web_contents->GetFrameTree();
- return frame_tree->FindByName(name_to_find)->current_frame_host();
+ bool SimulateMouseDown() {
+ return ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
+ ui_controls::DOWN);
+ }
+
+ bool SimulateMouseMove(const gfx::Point& location_inside_web_contents) {
+ gfx::Rect bounds = web_contents()->GetContainerBounds();
+ return ui_test_utils::SendMouseMoveSync(
+ gfx::Point(bounds.x() + location_inside_web_contents.x(),
+ bounds.y() + location_inside_web_contents.y()));
+ }
+
+ bool NavigateNamedFrame(const std::string& frame_name,
+ const std::string& origin,
+ const std::string& filename) {
+ content::RenderFrameHost* frame = GetFrameByName(frame_name);
+ if (!frame)
+ return false;
+
+ std::string script;
+ int response = 0;
+
+ // Navigate the frame and wait for the load event.
+ script = base::StringPrintf(
+ "location.href = '/cross-site/%s/drag_and_drop/%s';\n"
+ "setTimeout(function() { domAutomationController.send(42); }, 0);",
+ origin.c_str(), filename.c_str());
+ content::TestFrameNavigationObserver observer(frame);
+ if (!content::ExecuteScriptAndExtractInt(frame, script, &response))
+ return false;
+ if (response != 42)
+ return false;
+ observer.Wait();
+
+ // Wait until frame contents (e.g. images) have painted (which should happen
+ // in the animation frame that *starts* after the onload event - therefore
+ // we need to wait for 2 animation frames).
+ script = std::string(
+ "requestAnimationFrame(function() {\n"
+ " requestAnimationFrame(function() {\n"
+ " domAutomationController.send(43);\n"
+ " });\n"
+ "});\n");
+ if (!content::ExecuteScriptAndExtractInt(frame, script, &response))
+ return false;
+ if (response != 43)
+ return false;
+
+ return true;
+ }
+
+ content::RenderFrameHost* GetFrameByName(const std::string& name_to_find) {
Łukasz Anforowicz 2016/11/10 19:26:24 content::FrameTree::FindByName is not exposed via
+ content::RenderFrameHost* result = nullptr;
+ for (content::RenderFrameHost* rfh : web_contents()->GetAllFrames()) {
+ if (rfh->GetFrameName() == name_to_find) {
+ if (result) {
+ ADD_FAILURE() << "More than one frame named "
+ << "'" << name_to_find << "'";
+ return nullptr;
+ }
+ result = rfh;
+ }
+ }
+
+ EXPECT_TRUE(result) << "Couldn't find a frame named "
+ << "'" << name_to_find << "'";
+ return result;
}
void AssertTestPageIsLoaded() {
- ASSERT_EQ(kTestPagePath,
- shell()->web_contents()->GetLastCommittedURL().path());
+ ASSERT_EQ(kTestPagePath, web_contents()->GetLastCommittedURL().path());
}
std::unique_ptr<DragAndDropSimulator> drag_simulator_;
@@ -293,14 +477,15 @@ class DragAndDropBrowserTest : public ContentBrowserTest {
};
IN_PROC_BROWSER_TEST_F(DragAndDropBrowserTest, DropTextFromOutside) {
- ASSERT_TRUE(NavigateToTestPage("a.com",
- "", // Left frame is unused by this test.
- "c.com/drag_and_drop/drop_target.html"));
+ ASSERT_TRUE(NavigateToTestPage("a.com"));
+ ASSERT_TRUE(NavigateRightFrame("b.com", "drop_target.html"));
+ // Drag text from outside the browser into/over the right frame.
{
- std::string dragover_event;
DOMDragEventWaiter dragover_waiter("dragover", right_frame());
ASSERT_TRUE(SimulateDragEnterToRightFrame("Dragged test text"));
+
+ std::string dragover_event;
ASSERT_TRUE(dragover_waiter.WaitForNextMatchingEvent(&dragover_event));
EXPECT_THAT(dragover_event, testing::HasSubstr("\"drop_effect\":\"none\""));
EXPECT_THAT(dragover_event,
@@ -309,10 +494,12 @@ IN_PROC_BROWSER_TEST_F(DragAndDropBrowserTest, DropTextFromOutside) {
testing::HasSubstr("\"mime_types\":\"text/plain\""));
}
+ // Drop into the right frame.
{
- std::string drop_event;
DOMDragEventWaiter drop_waiter("drop", right_frame());
ASSERT_TRUE(SimulateDropInRightFrame());
+
+ std::string drop_event;
ASSERT_TRUE(drop_waiter.WaitForNextMatchingEvent(&drop_event));
EXPECT_THAT(drop_event, testing::HasSubstr("\"drop_effect\":\"none\""));
EXPECT_THAT(drop_event, testing::HasSubstr("\"effect_allowed\":\"all\""));
@@ -321,4 +508,55 @@ IN_PROC_BROWSER_TEST_F(DragAndDropBrowserTest, DropTextFromOutside) {
}
}
+IN_PROC_BROWSER_TEST_F(DragAndDropBrowserTest, DragStartInFrame) {
+ std::string frame_site = "b.com";
+ ASSERT_TRUE(NavigateToTestPage("a.com"));
+ ASSERT_TRUE(NavigateLeftFrame(frame_site, "image_source.html"));
+
+ // Start the drag in the left frame.
+ DragStartWaiter drag_start_waiter(
+ web_contents(),
+ base::Bind(&DragAndDropBrowserTest::DragStartInFrame_Step2,
+ base::Unretained(this), frame_site));
+ DOMDragEventWaiter dragstart_event_waiter("dragstart", left_frame());
+ ASSERT_TRUE(SimulateMouseDownAndDragStartInLeftFrame());
+
+ // Verify Javascript event data.
+ std::string dragstart_event;
+ ASSERT_TRUE(
+ dragstart_event_waiter.WaitForNextMatchingEvent(&dragstart_event));
+ EXPECT_THAT(dragstart_event, testing::HasSubstr("\"drop_effect\":\"none\""));
+ // |effect_allowed| is intialized *inside* dragstart event handler - no
+ // point in verifying this value here (this would be tautological).
+ EXPECT_THAT(
+ dragstart_event,
+ testing::HasSubstr("\"mime_types\":\"Files,text/html,text/uri-list\""));
+
+ // Run the nested drag-and-drop loop
+ // (test will continue in DragStartInFrame_Step2).
+ drag_start_waiter.WaitUntilFullDragAndDropCompletes();
+}
+
+void DragAndDropBrowserTest::DragStartInFrame_Step2(
+ const std::string& frame_site,
+ const std::string& text,
+ const std::string& html,
+ int operation,
+ bool did_originate_from_renderer) {
+ EXPECT_EQ(
+ embedded_test_server()->GetURL(frame_site, "/image_decoding/droids.jpg"),
+ text);
+ EXPECT_THAT(html,
+ testing::MatchesRegex("<img .*src=\""
+ "http://.*:.*/image_decoding/droids.jpg"
+ "\">"));
+ EXPECT_TRUE(did_originate_from_renderer);
+
+ // dragstart event handler in image_source.html is asking for "copy" only.
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, operation);
+
+ // This will exit the nested drag-and-drag loop.
+ ASSERT_TRUE(SimulateMouseUp());
+}
+
} // namespace chrome
« no previous file with comments | « no previous file | chrome/test/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698