1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <algorithm>
6 #include <initializer_list>
7 #include <memory>
8 #include <string>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/files/file_path.h"
14 #include "base/macros.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/sequenced_task_runner.h"
17 #include "base/strings/pattern.h"
18 #include "base/strings/string_piece.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/test/test_timeouts.h"
22 #include "base/threading/sequenced_task_runner_handle.h"
23 #include "build/build_config.h"
24 #include "chrome/browser/ui/browser.h"
25 #include "chrome/browser/ui/browser_commands.h"
26 #include "chrome/browser/ui/browser_window.h"
27 #include "chrome/browser/ui/tabs/tab_strip_model.h"
28 #include "chrome/browser/ui/view_ids.h"
29 #include "chrome/test/base/in_process_browser_test.h"
30 #include "chrome/test/base/interactive_test_utils.h"
31 #include "chrome/test/base/ui_test_utils.h"
32 #include "content/public/browser/navigation_controller.h"
33 #include "content/public/browser/render_frame_host.h"
34 #include "content/public/browser/render_process_host.h"
35 #include "content/public/browser/web_contents.h"
36 #include "content/public/test/browser_test.h"
37 #include "content/public/test/browser_test_utils.h"
38 #include "content/public/test/content_browser_test.h"
39 #include "content/public/test/content_browser_test_utils.h"
40 #include "content/public/test/hit_test_region_observer.h"
41 #include "content/public/test/test_frame_navigation_observer.h"
42 #include "content/public/test/test_navigation_observer.h"
43 #include "content/public/test/test_utils.h"
44 #include "net/base/escape.h"
45 #include "net/base/filename_util.h"
46 #include "net/dns/mock_host_resolver.h"
47 #include "net/test/embedded_test_server/embedded_test_server.h"
48 #include "testing/gmock/include/gmock/gmock.h"
49 #include "testing/gtest/include/gtest/gtest.h"
50 #include "ui/aura/client/drag_drop_client.h"
51 #include "ui/aura/client/drag_drop_delegate.h"
52 #include "ui/aura/client/screen_position_client.h"
53 #include "ui/aura/window.h"
54 #include "ui/base/dragdrop/drag_drop_types.h"
55 #include "ui/base/dragdrop/drop_target_event.h"
56 #include "ui/base/dragdrop/os_exchange_data.h"
57 #include "ui/gfx/geometry/point.h"
58 #include "ui/gfx/geometry/rect.h"
59 #include "url/gurl.h"
60
61 namespace chrome {
62
63 namespace {
64
65 // TODO(lukasza): Support testing on non-Aura platforms (i.e. Android + Mac?).
66 //
67 // Notes for the TODO above:
68 //
69 // - Why inject/simulate drag-and-drop events at the aura::Window* level.
70 //
71 // - It seems better to inject into UI libraries to cover code *inside* these
72 // libraries. This might complicate simulation a little bit (i.e. picking
73 // the right aura::Window and/or aura::client::DragDropDelegate to target),
74 // but otherwise important bits of code wouldn't get test coverage (i.e.
75 // directly injecting into RenderViewHost->DragTargetDragEnter seems wrong).
76 //
77 // - In theory, we could introduce WebContentsImpl::DragTargetDragEnter (to be
78 // used by all UI platforms - so reused by web_contents_view_android.cc,
79 // web_contents_view_aura.cc, web_drag_dest_mac.mm), but it feels wrong - UI
80 // libraries should already know which widget is the target of the event and
81 // so should be able to talk directly to the right widget (i.e. WebContents
82 // should not be responsible for mapping coordinates to a widget - this is
83 // the job of the UI library).
84 //
85 // - Unknowns:
86 //
87 // - Will this work for WebView and Plugin testing.
88
89 // Test helper for simulating drag and drop happening in WebContents.
90 class DragAndDropSimulator {
91 public:
DragAndDropSimulator(content::WebContents * web_contents)92 explicit DragAndDropSimulator(content::WebContents* web_contents)
93 : web_contents_(web_contents) {}
94
95 // Simulates notification that |text| was dragged from outside of the browser,
96 // into the specified |location| inside |web_contents|.
97 // |location| is relative to |web_contents|.
98 // Returns true upon success.
SimulateDragEnter(const gfx::Point & location,const std::string & text)99 bool SimulateDragEnter(const gfx::Point& location, const std::string& text) {
100 os_exchange_data_ = std::make_unique<ui::OSExchangeData>();
101 os_exchange_data_->SetString(base::UTF8ToUTF16(text));
102 return SimulateDragEnter(location, *os_exchange_data_);
103 }
104
105 // Simulates notification that |url| was dragged from outside of the browser,
106 // into the specified |location| inside |web_contents|.
107 // |location| is relative to |web_contents|.
108 // Returns true upon success.
SimulateDragEnter(const gfx::Point & location,const GURL & url)109 bool SimulateDragEnter(const gfx::Point& location, const GURL& url) {
110 os_exchange_data_ = std::make_unique<ui::OSExchangeData>();
111 os_exchange_data_->SetURL(url, base::UTF8ToUTF16(url.spec()));
112 return SimulateDragEnter(location, *os_exchange_data_);
113 }
114
115 // Simulates notification that |file| was dragged from outside of the browser,
116 // into the specified |location| inside |web_contents|.
117 // |location| is relative to |web_contents|.
118 // Returns true upon success.
SimulateDragEnter(const gfx::Point & location,const base::FilePath & file)119 bool SimulateDragEnter(const gfx::Point& location,
120 const base::FilePath& file) {
121 os_exchange_data_ = std::make_unique<ui::OSExchangeData>();
122 os_exchange_data_->SetFilename(file);
123 return SimulateDragEnter(location, *os_exchange_data_);
124 }
125
126 // Simulates dropping of the drag-and-dropped item.
127 // SimulateDragEnter needs to be called first.
128 // Returns true upon success.
SimulateDrop(const gfx::Point & location)129 bool SimulateDrop(const gfx::Point& location) {
130 if (!active_drag_event_) {
131 ADD_FAILURE() << "Cannot drop a drag that hasn't started yet.";
132 return false;
133 }
134
135 aura::client::DragDropDelegate* delegate = GetDragDropDelegate();
136 if (!delegate)
137 return false;
138
139 gfx::PointF event_location;
140 gfx::PointF event_root_location;
141 CalculateEventLocations(location, &event_location, &event_root_location);
142 active_drag_event_->set_location_f(event_location);
143 active_drag_event_->set_root_location_f(event_root_location);
144
145 delegate->OnDragUpdated(*active_drag_event_);
146 delegate->OnPerformDrop(*active_drag_event_, std::move(os_exchange_data_));
147 return true;
148 }
149
150 private:
SimulateDragEnter(const gfx::Point & location,const ui::OSExchangeData & data)151 bool SimulateDragEnter(const gfx::Point& location,
152 const ui::OSExchangeData& data) {
153 if (active_drag_event_) {
154 ADD_FAILURE() << "Cannot start a new drag when old one hasn't ended yet.";
155 return false;
156 }
157
158 aura::client::DragDropDelegate* delegate = GetDragDropDelegate();
159 if (!delegate)
160 return false;
161
162 gfx::PointF event_location;
163 gfx::PointF event_root_location;
164 CalculateEventLocations(location, &event_location, &event_root_location);
165 active_drag_event_.reset(new ui::DropTargetEvent(
166 data, event_location, event_root_location, kDefaultSourceOperations));
167
168 delegate->OnDragEntered(*active_drag_event_);
169 delegate->OnDragUpdated(*active_drag_event_);
170 return true;
171 }
172
GetDragDropDelegate()173 aura::client::DragDropDelegate* GetDragDropDelegate() {
174 gfx::NativeView view = web_contents_->GetContentNativeView();
175 aura::client::DragDropDelegate* delegate =
176 aura::client::GetDragDropDelegate(view);
177 EXPECT_TRUE(delegate) << "Expecting WebContents to have DragDropDelegate";
178 return delegate;
179 }
180
CalculateEventLocations(const gfx::Point & web_contents_relative_location,gfx::PointF * out_event_location,gfx::PointF * out_event_root_location)181 void CalculateEventLocations(const gfx::Point& web_contents_relative_location,
182 gfx::PointF* out_event_location,
183 gfx::PointF* out_event_root_location) {
184 gfx::NativeView view = web_contents_->GetNativeView();
185
186 *out_event_location = gfx::PointF(web_contents_relative_location);
187
188 gfx::Point root_location = web_contents_relative_location;
189 aura::Window::ConvertPointToTarget(view, view->GetRootWindow(),
190 &root_location);
191 *out_event_root_location = gfx::PointF(root_location);
192 }
193
194 // These are ui::DropTargetEvent::source_operations_ being sent when manually
195 // trying out drag&drop of an image file from Nemo (Ubuntu's file explorer)
196 // into a content_shell.
197 static constexpr int kDefaultSourceOperations = ui::DragDropTypes::DRAG_MOVE |
198 ui::DragDropTypes::DRAG_COPY |
199 ui::DragDropTypes::DRAG_LINK;
200
201 content::WebContents* web_contents_;
202 std::unique_ptr<ui::DropTargetEvent> active_drag_event_;
203 std::unique_ptr<ui::OSExchangeData> os_exchange_data_;
204
205 DISALLOW_COPY_AND_ASSIGN(DragAndDropSimulator);
206 };
207
208 // Helper for waiting until a drag-and-drop starts (e.g. in response to a
209 // mouse-down + mouse-move simulated by the test).
210 class DragStartWaiter : public aura::client::DragDropClient {
211 public:
212 // Starts monitoring |web_contents| for a start of a drag-and-drop.
DragStartWaiter(content::WebContents * web_contents)213 explicit DragStartWaiter(content::WebContents* web_contents)
214 : web_contents_(web_contents),
215 message_loop_runner_(new content::MessageLoopRunner),
216 suppress_passing_of_start_drag_further_(false),
217 drag_started_(false) {
218 DCHECK(web_contents_);
219
220 // Intercept calls to the old DragDropClient.
221 gfx::NativeWindow root_window =
222 web_contents_->GetContentNativeView()->GetRootWindow();
223 old_client_ = aura::client::GetDragDropClient(root_window);
224 aura::client::SetDragDropClient(root_window, this);
225 }
226
~DragStartWaiter()227 ~DragStartWaiter() override {
228 // Restore the original DragDropClient.
229 gfx::NativeWindow root_window =
230 web_contents_->GetContentNativeView()->GetRootWindow();
231 aura::client::SetDragDropClient(root_window, old_client_);
232 }
233
234 // Waits until we almost report a drag-and-drop start to the OS.
235 // At that point
236 // 1) the callback from PostTaskWhenDragStarts will be posted.
237 // 2) the drag-start request will be forwarded to the OS
238 // (unless SuppressPassingStartDragFurther method was called).
239 //
240 // Note that if SuppressPassingStartDragFurther was not called then
241 // WaitUntilDragStart can take a long time to return (it returns only after
242 // the OS decides that the drag-and-drop has ended).
243 //
244 // Before returning populates |text|, |html| and other parameters with data
245 // that would have been passed to the OS). If the caller is not interested in
246 // this data, then the corresponding argument can be null.
WaitUntilDragStart(std::string * text,std::string * html,int * operation,gfx::Point * location_inside_web_contents)247 void WaitUntilDragStart(std::string* text,
248 std::string* html,
249 int* operation,
250 gfx::Point* location_inside_web_contents) {
251 message_loop_runner_->Run();
252
253 // message_loop_runner_->Quit is only called from StartDragAndDrop.
254 DCHECK(drag_started_);
255
256 if (text)
257 *text = text_;
258 if (html)
259 *html = html_;
260 if (operation)
261 *operation = operation_;
262 if (location_inside_web_contents)
263 *location_inside_web_contents = location_inside_web_contents_;
264 }
265
SuppressPassingStartDragFurther()266 void SuppressPassingStartDragFurther() {
267 suppress_passing_of_start_drag_further_ = true;
268 }
269
PostTaskWhenDragStarts(const base::Closure & callback)270 void PostTaskWhenDragStarts(const base::Closure& callback) {
271 callback_to_run_inside_drag_and_drop_message_loop_ = callback;
272 }
273
274 // aura::client::DragDropClient overrides:
StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,aura::Window * root_window,aura::Window * source_window,const gfx::Point & screen_location,int operation,ui::mojom::DragEventSource source)275 int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
276 aura::Window* root_window,
277 aura::Window* source_window,
278 const gfx::Point& screen_location,
279 int operation,
280 ui::mojom::DragEventSource source) override {
281 DCHECK(!drag_started_);
282 if (!drag_started_) {
283 drag_started_ = true;
284 message_loop_runner_->Quit();
285
286 base::string16 text;
287 if (data->GetString(&text))
288 text_ = base::UTF16ToUTF8(text);
289 else
290 text_ = "<no text>";
291
292 GURL base_url;
293 base::string16 html;
294 if (data->GetHtml(&html, &base_url))
295 html_ = base::UTF16ToUTF8(html);
296 else
297 html_ = "<no html>";
298
299 gfx::Rect bounds =
300 web_contents_->GetContentNativeView()->GetBoundsInScreen();
301 location_inside_web_contents_ =
302 screen_location - gfx::Vector2d(bounds.x(), bounds.y());
303
304 operation_ = operation;
305 }
306
307 if (!callback_to_run_inside_drag_and_drop_message_loop_.is_null()) {
308 base::SequencedTaskRunnerHandle::Get()->PostTask(
309 FROM_HERE,
310 std::move(callback_to_run_inside_drag_and_drop_message_loop_));
311 callback_to_run_inside_drag_and_drop_message_loop_.Reset();
312 }
313
314 if (suppress_passing_of_start_drag_further_)
315 return 0;
316
317 // Start a nested drag-and-drop loop (might not return for a long time).
318 return old_client_->StartDragAndDrop(std::move(data), root_window,
319 source_window, screen_location,
320 operation, source);
321 }
322
DragCancel()323 void DragCancel() override {
324 ADD_FAILURE() << "Unexpected call to DragCancel";
325 }
326
IsDragDropInProgress()327 bool IsDragDropInProgress() override { return drag_started_; }
328
AddObserver(aura::client::DragDropClientObserver * observer)329 void AddObserver(aura::client::DragDropClientObserver* observer) override {}
RemoveObserver(aura::client::DragDropClientObserver * observer)330 void RemoveObserver(aura::client::DragDropClientObserver* observer) override {
331 }
332
333 private:
334 content::WebContents* web_contents_;
335 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
336 aura::client::DragDropClient* old_client_;
337 base::Closure callback_to_run_inside_drag_and_drop_message_loop_;
338 bool suppress_passing_of_start_drag_further_;
339
340 // Data captured during the first intercepted StartDragAndDrop call.
341 bool drag_started_;
342 std::string text_;
343 std::string html_;
344 int operation_;
345 gfx::Point location_inside_web_contents_;
346
347 DISALLOW_COPY_AND_ASSIGN(DragStartWaiter);
348 };
349
350 // Helper for waiting for notifications from
351 // content/test/data/drag_and_drop/event_monitoring.js
352 class DOMDragEventWaiter {
353 public:
DOMDragEventWaiter(const std::string & event_type_to_wait_for,const content::ToRenderFrameHost & target)354 DOMDragEventWaiter(const std::string& event_type_to_wait_for,
355 const content::ToRenderFrameHost& target)
356 : target_frame_name_(target.render_frame_host()->GetFrameName()),
357 event_type_to_wait_for_(event_type_to_wait_for),
358 dom_message_queue_(content::WebContents::FromRenderFrameHost(
359 target.render_frame_host())) {}
360
361 // Waits until |target| calls reportDragEvent in
362 // chrome/test/data/drag_and_drop/event_monitoring.js with event_type
363 // property set to |event_type_to_wait_for|. (|target| and
364 // |event_type_to_wait_for| are passed to the constructor).
365 //
366 // Returns the event details via |found_event| (in form of a JSON-encoded
367 // object). See chrome/test/data/drag_and_drop/event_monitoring.js for keys
368 // and properties that |found_event| is expected to have.
369 //
370 // Returns true upon success. It is okay if |response| is null.
WaitForNextMatchingEvent(std::string * found_event)371 bool WaitForNextMatchingEvent(std::string* found_event) WARN_UNUSED_RESULT {
372 std::string candidate_event;
373 bool got_right_event_type = false;
374 bool got_right_window_name = false;
375 do {
376 if (!dom_message_queue_.WaitForMessage(&candidate_event))
377 return false;
378
379 got_right_event_type =
380 IsExpectedEventType(candidate_event, event_type_to_wait_for_);
381 got_right_window_name =
382 IsExpectedWindowName(candidate_event, target_frame_name_);
383 } while (!got_right_event_type || !got_right_window_name);
384
385 if (found_event)
386 *found_event = candidate_event;
387
388 return true;
389 }
390
IsExpectedEventType(const std::string & actual_event_body,const std::string & expected_event_type)391 static bool IsExpectedEventType(const std::string& actual_event_body,
392 const std::string& expected_event_type) {
393 return IsExpectedPropertyValue(actual_event_body, "event_type",
394 expected_event_type);
395 }
396
IsExpectedWindowName(const std::string & actual_event_body,const std::string & expected_window_name)397 static bool IsExpectedWindowName(const std::string& actual_event_body,
398 const std::string& expected_window_name) {
399 return IsExpectedPropertyValue(actual_event_body, "window_name",
400 expected_window_name);
401 }
402
403 private:
IsExpectedPropertyValue(const std::string & actual_event_body,const std::string & property_name,const std::string & expected_property_value)404 static bool IsExpectedPropertyValue(
405 const std::string& actual_event_body,
406 const std::string& property_name,
407 const std::string& expected_property_value) {
408 return base::MatchPattern(
409 actual_event_body,
410 base::StringPrintf("*\"%s\":\"%s\"*", property_name.c_str(),
411 expected_property_value.c_str()));
412 }
413
414 std::string target_frame_name_;
415 std::string event_type_to_wait_for_;
416 content::DOMMessageQueue dom_message_queue_;
417
418 DISALLOW_COPY_AND_ASSIGN(DOMDragEventWaiter);
419 };
420
421 // Helper for verifying contents of DOM events associated with drag-and-drop.
422 class DOMDragEventVerifier {
423 public:
DOMDragEventVerifier()424 DOMDragEventVerifier() {}
425
set_expected_client_position(const std::string & value)426 void set_expected_client_position(const std::string& value) {
427 expected_client_position_ = value;
428 }
429
set_expected_drop_effect(const std::string & value)430 void set_expected_drop_effect(const std::string& value) {
431 expected_drop_effect_ = value;
432 }
433
set_expected_effect_allowed(const std::string & value)434 void set_expected_effect_allowed(const std::string& value) {
435 expected_effect_allowed_ = value;
436 }
437
set_expected_mime_types(const std::string & value)438 void set_expected_mime_types(const std::string& value) {
439 expected_mime_types_ = value;
440 }
441
set_expected_page_position(const std::string & value)442 void set_expected_page_position(const std::string& value) {
443 expected_page_position_ = value;
444 }
445
set_expected_screen_position(const std::string & value)446 void set_expected_screen_position(const std::string& value) {
447 expected_screen_position_ = value;
448 }
449
450 // Returns a matcher that will match a std::string (drag event data - e.g.
451 // one returned by DOMDragEventWaiter::WaitForNextMatchingEvent) if it matches
452 // the expectations of this DOMDragEventVerifier.
Matches() const453 testing::Matcher<std::string> Matches() const {
454 return testing::AllOf(
455 FieldMatches("client_position", expected_client_position_),
456 FieldMatches("drop_effect", expected_drop_effect_),
457 FieldMatches("effect_allowed", expected_effect_allowed_),
458 FieldMatches("mime_types", expected_mime_types_),
459 FieldMatches("page_position", expected_page_position_),
460 FieldMatches("screen_position", expected_screen_position_));
461 }
462
463 private:
FieldMatches(const std::string & field_name,const std::string & expected_value)464 static testing::Matcher<std::string> FieldMatches(
465 const std::string& field_name,
466 const std::string& expected_value) {
467 if (expected_value == "<no expectation>")
468 return testing::A<std::string>();
469
470 return testing::HasSubstr(base::StringPrintf(
471 "\"%s\":\"%s\"", field_name.c_str(), expected_value.c_str()));
472 }
473
474 std::string expected_drop_effect_ = "<no expectation>";
475 std::string expected_effect_allowed_ = "<no expectation>";
476 std::string expected_mime_types_ = "<no expectation>";
477 std::string expected_client_position_ = "<no expectation>";
478 std::string expected_page_position_ = "<no expectation>";
479 std::string expected_screen_position_ = "<no expectation>";
480
481 DISALLOW_COPY_AND_ASSIGN(DOMDragEventVerifier);
482 };
483
484 // Helper for monitoring event notifications from
485 // content/test/data/drag_and_drop/event_monitoring.js
486 // and counting how many events of a given type were received.
487 class DOMDragEventCounter {
488 public:
DOMDragEventCounter(const content::ToRenderFrameHost & target)489 explicit DOMDragEventCounter(const content::ToRenderFrameHost& target)
490 : target_frame_name_(target.render_frame_host()->GetFrameName()),
491 dom_message_queue_(content::WebContents::FromRenderFrameHost(
492 target.render_frame_host())) {}
493
494 // Resets all the accumulated event counts to zeros.
Reset()495 void Reset() {
496 StoreAccumulatedEvents();
497 received_events_.clear();
498 }
499
500 // Returns the number of events of the specified |event_type| received since
501 // construction, or since the last time Reset was called. |event_type| should
502 // be one of possible |type| property values for a DOM drag-and-drop event -
503 // e.g. "dragenter" or "dragover".
GetNumberOfReceivedEvents(const std::string & event_type)504 int GetNumberOfReceivedEvents(const std::string& event_type) {
505 std::vector<std::string> v({event_type});
506 return GetNumberOfReceivedEvents(v.begin(), v.end());
507 }
508
509 // Returns the number of events of the specified |event_types| received since
510 // construction, or since the last time Reset was called. Elements of
511 // |event_types| should be one of possible |type| property values for a DOM
512 // drag-and-drop event - e.g. "dragenter" or "dragover".
GetNumberOfReceivedEvents(std::initializer_list<const char * > event_types)513 int GetNumberOfReceivedEvents(
514 std::initializer_list<const char*> event_types) {
515 return GetNumberOfReceivedEvents(event_types.begin(), event_types.end());
516 }
517
518 private:
519 template <typename T>
GetNumberOfReceivedEvents(T event_types_begin,T event_types_end)520 int GetNumberOfReceivedEvents(T event_types_begin, T event_types_end) {
521 StoreAccumulatedEvents();
522
523 auto received_event_has_matching_event_type =
524 [&event_types_begin,
525 &event_types_end](const std::string& received_event) {
526 return std::any_of(event_types_begin, event_types_end,
527 [&received_event](const std::string& event_type) {
528 return DOMDragEventWaiter::IsExpectedEventType(
529 received_event, event_type);
530 });
531 };
532
533 return std::count_if(received_events_.begin(), received_events_.end(),
534 received_event_has_matching_event_type);
535 }
536
StoreAccumulatedEvents()537 void StoreAccumulatedEvents() {
538 std::string candidate_event;
539 while (dom_message_queue_.PopMessage(&candidate_event)) {
540 if (DOMDragEventWaiter::IsExpectedWindowName(candidate_event,
541 target_frame_name_)) {
542 received_events_.push_back(candidate_event);
543 }
544 }
545 }
546
547 std::string target_frame_name_;
548 content::DOMMessageQueue dom_message_queue_;
549 std::vector<std::string> received_events_;
550
551 DISALLOW_COPY_AND_ASSIGN(DOMDragEventCounter);
552 };
553
554 const char kTestPagePath[] = "/drag_and_drop/page.html";
555
556 } // namespace
557
558 class DragAndDropBrowserTest : public InProcessBrowserTest,
559 public testing::WithParamInterface<bool> {
560 public:
DragAndDropBrowserTest()561 DragAndDropBrowserTest() {}
562
563 struct DragImageBetweenFrames_TestState;
564 void DragImageBetweenFrames_Step2(DragImageBetweenFrames_TestState*);
565 void DragImageBetweenFrames_Step3(DragImageBetweenFrames_TestState*);
566
567 struct DragImageFromDisappearingFrame_TestState;
568 void DragImageFromDisappearingFrame_Step2(
569 DragImageFromDisappearingFrame_TestState*);
570 void DragImageFromDisappearingFrame_Step3(
571 DragImageFromDisappearingFrame_TestState*);
572
573 struct CrossSiteDrag_TestState;
574 void CrossSiteDrag_Step2(CrossSiteDrag_TestState*);
575 void CrossSiteDrag_Step3(CrossSiteDrag_TestState*);
576
577 protected:
SetUpOnMainThread()578 void SetUpOnMainThread() override {
579 host_resolver()->AddRule("*", "127.0.0.1");
580 content::SetupCrossSiteRedirector(embedded_test_server());
581 ASSERT_TRUE(embedded_test_server()->Start());
582 drag_simulator_.reset(new DragAndDropSimulator(web_contents()));
583 }
584
TearDownOnMainThread()585 void TearDownOnMainThread() override {
586 // For X11 need to tear down before UI goes away.
587 drag_simulator_.reset();
588 }
589
use_cross_site_subframe()590 bool use_cross_site_subframe() {
591 // This is controlled by gtest's test param from INSTANTIATE_TEST_SUITE_P.
592 return GetParam();
593 }
594
left_frame()595 content::RenderFrameHost* left_frame() {
596 AssertTestPageIsLoaded();
597 return GetFrameByName("left");
598 }
599
right_frame()600 content::RenderFrameHost* right_frame() {
601 AssertTestPageIsLoaded();
602 return GetFrameByName("right");
603 }
604
web_contents()605 content::WebContents* web_contents() {
606 return browser()->tab_strip_model()->GetActiveWebContents();
607 }
608
609 //////////////////////
610 // Navigation helpers.
611
NavigateToTestPage(const std::string & origin_of_main_frame)612 bool NavigateToTestPage(const std::string& origin_of_main_frame) {
613 GURL url =
614 embedded_test_server()->GetURL(origin_of_main_frame, kTestPagePath);
615 ui_test_utils::NavigateToURL(browser(), url);
616 return web_contents()->GetLastCommittedURL() == url;
617 }
618
619 // Navigates the left frame to |filename| (found under
620 // chrome/test/data/drag_and_drop directory).
NavigateLeftFrame(const std::string & origin,const std::string & filename)621 bool NavigateLeftFrame(const std::string& origin,
622 const std::string& filename) {
623 AssertTestPageIsLoaded();
624 return NavigateNamedFrame("left", origin, filename);
625 }
626
627 // Navigates the right frame to |filename| (found under
628 // chrome/test/data/drag_and_drop directory).
NavigateRightFrame(const std::string & origin,const std::string & filename)629 bool NavigateRightFrame(const std::string& origin,
630 const std::string& filename) {
631 AssertTestPageIsLoaded();
632 return NavigateNamedFrame("right", origin, filename);
633 }
634
635 ////////////////////////////////////////////////////////////
636 // Simulation of starting a drag-and-drop (using the mouse).
637
SimulateMouseDownAndDragStartInLeftFrame()638 bool SimulateMouseDownAndDragStartInLeftFrame() {
639 AssertTestPageIsLoaded();
640
641 // Waiting until the mousemove and mousedown events reach the right renderer
642 // is needed to avoid flakiness reported in https://crbug.com/671445 (which
643 // has its root cause in https://crbug.com/647378). Once the latter bug
644 // is fixed, we should no longer need to wait for these events (because
645 // fixing https://crbug.com/647378 should guarantee that events arrive
646 // to the renderer in the right order).
647 DOMDragEventWaiter mouse_move_event_waiter("mousemove", left_frame());
648 DOMDragEventWaiter mouse_down_event_waiter("mousedown", left_frame());
649
650 if (!SimulateMouseMove(kMiddleOfLeftFrame))
651 return false;
652 if (!mouse_move_event_waiter.WaitForNextMatchingEvent(nullptr))
653 return false;
654
655 if (!SimulateMouseDown())
656 return false;
657 if (!mouse_down_event_waiter.WaitForNextMatchingEvent(nullptr))
658 return false;
659
660 if (!SimulateMouseMove(expected_location_of_drag_start_in_left_frame()))
661 return false;
662
663 return true;
664 }
665
expected_location_of_drag_start_in_left_frame()666 gfx::Point expected_location_of_drag_start_in_left_frame() {
667 // TODO(crbug.com/653490): The delta below should exceed kDragThresholdX and
668 // kDragThresholdY from MouseEventManager.cpp in blink. Ideally, it would
669 // come from the OS instead.
670 return kMiddleOfLeftFrame + gfx::Vector2d(10, 10);
671 }
672
SimulateMouseMoveToLeftFrame()673 bool SimulateMouseMoveToLeftFrame() {
674 AssertTestPageIsLoaded();
675 return SimulateMouseMove(kMiddleOfLeftFrame);
676 }
677
SimulateMouseMoveToRightFrame()678 bool SimulateMouseMoveToRightFrame() {
679 AssertTestPageIsLoaded();
680 return SimulateMouseMove(kMiddleOfRightFrame);
681 }
682
SimulateMouseUp()683 bool SimulateMouseUp() {
684 return ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
685 ui_controls::UP);
686 }
687
688 ////////////////////////////////////////////////////////////////////
689 // Simulation of dragging from outside the browser into web contents
690 // (using DragAndDropSimulator, not simulating mouse events).
691
SimulateDragEnterToRightFrame(const std::string & text)692 bool SimulateDragEnterToRightFrame(const std::string& text) {
693 AssertTestPageIsLoaded();
694 return drag_simulator_->SimulateDragEnter(kMiddleOfRightFrame, text);
695 }
696
SimulateDragEnterToRightFrame(const GURL & url)697 bool SimulateDragEnterToRightFrame(const GURL& url) {
698 AssertTestPageIsLoaded();
699 return drag_simulator_->SimulateDragEnter(kMiddleOfRightFrame, url);
700 }
701
SimulateDragEnterToRightFrame(const base::FilePath & file)702 bool SimulateDragEnterToRightFrame(const base::FilePath& file) {
703 AssertTestPageIsLoaded();
704 return drag_simulator_->SimulateDragEnter(kMiddleOfRightFrame, file);
705 }
706
SimulateDropInRightFrame()707 bool SimulateDropInRightFrame() {
708 AssertTestPageIsLoaded();
709 return drag_simulator_->SimulateDrop(kMiddleOfRightFrame);
710 }
711
GetMiddleOfRightFrameInScreenCoords()712 gfx::Point GetMiddleOfRightFrameInScreenCoords() {
713 aura::Window* window = web_contents()->GetNativeView();
714 aura::client::ScreenPositionClient* screen_position_client =
715 aura::client::GetScreenPositionClient(window->GetRootWindow());
716 gfx::Point screen_position(kMiddleOfRightFrame);
717 if (screen_position_client)
718 screen_position_client->ConvertPointToScreen(window, &screen_position);
719 return screen_position;
720 }
721
722 private:
723 // Constants with coordinates within content/test/data/drag_and_drop/page.html
724 // The precise frame center is at 200,200 and 400,200 coordinates, but slight
725 // differences between left and right frame hopefully make it easier to detect
726 // incorrect dom_drag_and_drop_event.clientX/Y values in test asserts.
727 const gfx::Point kMiddleOfLeftFrame = gfx::Point(155, 150);
728 const gfx::Point kMiddleOfRightFrame = gfx::Point(455, 250);
729
SimulateMouseDown()730 bool SimulateMouseDown() {
731 return ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
732 ui_controls::DOWN);
733 }
734
SimulateMouseMove(const gfx::Point & location_inside_web_contents)735 bool SimulateMouseMove(const gfx::Point& location_inside_web_contents) {
736 gfx::Rect bounds = web_contents()->GetContainerBounds();
737 return ui_test_utils::SendMouseMoveSync(
738 gfx::Point(bounds.x() + location_inside_web_contents.x(),
739 bounds.y() + location_inside_web_contents.y()));
740 }
741
NavigateNamedFrame(const std::string & frame_name,const std::string & origin,const std::string & filename)742 bool NavigateNamedFrame(const std::string& frame_name,
743 const std::string& origin,
744 const std::string& filename) {
745 content::RenderFrameHost* frame = GetFrameByName(frame_name);
746 if (!frame)
747 return false;
748
749 std::string script;
750 int response = 0;
751
752 // Navigate the frame and wait for the load event.
753 script = base::StringPrintf(
754 "location.href = '/cross-site/%s/drag_and_drop/%s';\n"
755 "setTimeout(function() { domAutomationController.send(42); }, 0);",
756 origin.c_str(), filename.c_str());
757 content::TestFrameNavigationObserver observer(frame);
758 if (!content::ExecuteScriptAndExtractInt(frame, script, &response))
759 return false;
760 if (response != 42)
761 return false;
762 observer.Wait();
763
764 // |frame| might have been swapped-out during a cross-site navigation,
765 // therefore we need to get the current RenderFrameHost to work against
766 // going forward.
767 frame = GetFrameByName(frame_name);
768 DCHECK(frame);
769
770 // Wait until hit testing data is ready.
771 WaitForHitTestData(frame);
772
773 return true;
774 }
775
GetFrameByName(const std::string & name_to_find)776 content::RenderFrameHost* GetFrameByName(const std::string& name_to_find) {
777 return content::FrameMatchingPredicate(
778 web_contents(),
779 base::BindRepeating(&content::FrameMatchesName, name_to_find));
780 }
781
AssertTestPageIsLoaded()782 void AssertTestPageIsLoaded() {
783 ASSERT_EQ(kTestPagePath, web_contents()->GetLastCommittedURL().path());
784 }
785
786 std::unique_ptr<DragAndDropSimulator> drag_simulator_;
787
788 DISALLOW_COPY_AND_ASSIGN(DragAndDropBrowserTest);
789 };
790
791 // Scenario: drag text from outside the browser and drop to the right frame.
792 // Test coverage: dragover, drop DOM events.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,DropTextFromOutside)793 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, DropTextFromOutside) {
794 std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
795 ASSERT_TRUE(NavigateToTestPage("a.com"));
796 ASSERT_TRUE(NavigateRightFrame(frame_site, "drop_target.html"));
797
798 // Setup test expectations.
799 DOMDragEventVerifier expected_dom_event_data;
800 expected_dom_event_data.set_expected_client_position("(155, 150)");
801 expected_dom_event_data.set_expected_drop_effect("none");
802 expected_dom_event_data.set_expected_effect_allowed("all");
803 expected_dom_event_data.set_expected_mime_types("text/plain");
804 expected_dom_event_data.set_expected_page_position("(155, 150)");
805
806 // Drag text from outside the browser into/over the right frame.
807 {
808 DOMDragEventWaiter dragover_waiter("dragover", right_frame());
809 ASSERT_TRUE(SimulateDragEnterToRightFrame("Dragged test text"));
810
811 std::string dragover_event;
812 ASSERT_TRUE(dragover_waiter.WaitForNextMatchingEvent(&dragover_event));
813 EXPECT_THAT(dragover_event, expected_dom_event_data.Matches());
814 }
815
816 // Drop into the right frame.
817 {
818 DOMDragEventWaiter drop_waiter("drop", right_frame());
819 ASSERT_TRUE(SimulateDropInRightFrame());
820
821 std::string drop_event;
822 ASSERT_TRUE(drop_waiter.WaitForNextMatchingEvent(&drop_event));
823 EXPECT_THAT(drop_event, expected_dom_event_data.Matches());
824 }
825 }
826
827 // Scenario: drag URL from outside the browser and drop to the right frame
828 // (e.g. this is similar to a drag that starts from the bookmarks bar, except
829 // that here there is no drag start event - as-if the drag was started in
830 // another application).
831 //
832 // This test mostly focuses on covering 1) the navigation path, 2) focus
833 // behavior. This test explicitly does not cover the dragover and/or drop DOM
834 // events - they are already covered via the DropTextFromOutside test above.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,DropValidUrlFromOutside)835 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, DropValidUrlFromOutside) {
836 std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
837 ASSERT_TRUE(NavigateToTestPage("a.com"));
838 ASSERT_TRUE(NavigateRightFrame(frame_site, "title1.html"));
839 content::WebContents* web_contents =
840 browser()->tab_strip_model()->GetActiveWebContents();
841 content::NavigationController& controller = web_contents->GetController();
842 int initial_history_count = controller.GetEntryCount();
843 GURL initial_url = web_contents->GetMainFrame()->GetLastCommittedURL();
844 ASSERT_EQ(1, browser()->tab_strip_model()->count());
845
846 // Focus the omnibox.
847 chrome::FocusLocationBar(browser());
848 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
849 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
850
851 // Drag a normal URL from outside the browser into/over the right frame.
852 GURL dragged_url = embedded_test_server()->GetURL("d.com", "/title2.html");
853 ASSERT_TRUE(SimulateDragEnterToRightFrame(dragged_url));
854
855 ui_test_utils::TabAddedWaiter wait_for_new_tab(browser());
856
857 // Drop into the right frame.
858 ASSERT_TRUE(SimulateDropInRightFrame());
859
860 // Verify that dropping |dragged_url| creates a new tab and navigates it to
861 // that URL.
862 wait_for_new_tab.Wait();
863 EXPECT_EQ(2, browser()->tab_strip_model()->count());
864 content::WebContents* new_web_contents =
865 browser()->tab_strip_model()->GetActiveWebContents();
866 content::TestNavigationObserver(new_web_contents, 1).Wait();
867 EXPECT_EQ(dragged_url,
868 new_web_contents->GetMainFrame()->GetLastCommittedURL());
869
870 // Verify that the initial tab didn't navigate.
871 EXPECT_EQ(initial_url, web_contents->GetMainFrame()->GetLastCommittedURL());
872 EXPECT_EQ(initial_history_count, controller.GetEntryCount());
873
874 // Verify that the focus moved from the omnibox to the tab contents.
875 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
876 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
877 }
878
879 // Scenario: drag a file from outside the browser and drop to the right frame
880 // (e.g. starting a drag in a separate file explorer application, like Nemo on
881 // gLinux).
882 //
883 // This test mostly focuses on covering 1) the navigation path, 2) focus
884 // behavior. This test explicitly does not cover the dragover and/or drop DOM
885 // events - they are already covered via the DropTextFromOutside test above.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,DropFileFromOutside)886 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, DropFileFromOutside) {
887 std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
888 ASSERT_TRUE(NavigateToTestPage("a.com"));
889 ASSERT_TRUE(NavigateRightFrame(frame_site, "title1.html"));
890 content::WebContents* web_contents =
891 browser()->tab_strip_model()->GetActiveWebContents();
892 content::NavigationController& controller = web_contents->GetController();
893 int initial_history_count = controller.GetEntryCount();
894 GURL initial_url = web_contents->GetMainFrame()->GetLastCommittedURL();
895 ASSERT_EQ(1, browser()->tab_strip_model()->count());
896
897 // Focus the omnibox.
898 chrome::FocusLocationBar(browser());
899 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
900 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
901
902 // Drag a file from outside the browser into/over the right frame.
903 base::FilePath dragged_file = ui_test_utils::GetTestFilePath(
904 base::FilePath(), base::FilePath().AppendASCII("title3.html"));
905 ASSERT_TRUE(SimulateDragEnterToRightFrame(dragged_file));
906
907 ui_test_utils::TabAddedWaiter wait_for_new_tab(browser());
908
909 // Drop into the right frame.
910 ASSERT_TRUE(SimulateDropInRightFrame());
911
912 // Verify that dropping |dragged_file| creates a new tab and navigates it to
913 // the corresponding file: URL.
914 wait_for_new_tab.Wait();
915 EXPECT_EQ(2, browser()->tab_strip_model()->count());
916 content::WebContents* new_web_contents =
917 browser()->tab_strip_model()->GetActiveWebContents();
918 content::TestNavigationObserver(new_web_contents, 1).Wait();
919 EXPECT_EQ(net::FilePathToFileURL(dragged_file),
920 new_web_contents->GetMainFrame()->GetLastCommittedURL());
921
922 // Verify that the initial tab didn't navigate.
923 EXPECT_EQ(initial_url, web_contents->GetMainFrame()->GetLastCommittedURL());
924 EXPECT_EQ(initial_history_count, controller.GetEntryCount());
925
926 // Verify that the focus moved from the omnibox to the tab contents.
927 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
928 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
929 }
930
931 #if defined(THREAD_SANITIZER)
932 // TSAN Race condition: crbug.com/1005095
933 #define MAYBE_DropForbiddenUrlFromOutside DISABLED_DropForbiddenUrlFromOutside
934 #else
935 #define MAYBE_DropForbiddenUrlFromOutside DropForbiddenUrlFromOutside
936 #endif
937 // Scenario: drag URL from outside the browser and drop to the right frame.
938 // Mostly focuses on covering the navigation path (the dragover and/or drop DOM
939 // events are already covered via the DropTextFromOutside test above).
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,MAYBE_DropForbiddenUrlFromOutside)940 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,
941 MAYBE_DropForbiddenUrlFromOutside) {
942 std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
943 ASSERT_TRUE(NavigateToTestPage("a.com"));
944 ASSERT_TRUE(NavigateRightFrame(frame_site, "title1.html"));
945 content::WebContents* web_contents =
946 browser()->tab_strip_model()->GetActiveWebContents();
947 content::NavigationController& controller = web_contents->GetController();
948 int initial_history_count = controller.GetEntryCount();
949
950 // Drag URL from outside the browser into/over the right frame. The test uses
951 // a URL that:
952 // 1. Passes RenderWidgetHostImpl::FilterDropData checks.
953 // 2. Fails CanDisplay checks in Blink (e.g. in RemoteFrame::Navigate).
954 // - This condition trigger the crash from https://crbug.com/1003169
955 // 3. Passes BeginNavigation checks
956 // - This rules out "chrome-error://blah".
957 GURL dragged_url("blob:null/some-guid");
958 ASSERT_TRUE(SimulateDragEnterToRightFrame(dragged_url));
959
960 // Drop into the right frame - this should *not* initiate navigating the main
961 // frame to |dragged_url| (because this would be a forbidden, web->file
962 // navigation).
963 ASSERT_TRUE(SimulateDropInRightFrame());
964
965 // Verify that the right frame is still responsive (this is a regression test
966 // for https://crbug.com/1003169.
967 ASSERT_TRUE(right_frame()->GetProcess()->IsInitializedAndNotDead());
968 EXPECT_EQ(123, content::EvalJs(right_frame(), "123"));
969
970 // Verify that the history remains unchanged.
971 EXPECT_NE(dragged_url, web_contents->GetMainFrame()->GetLastCommittedURL());
972 EXPECT_EQ(initial_history_count, controller.GetEntryCount());
973 }
974
975 // Scenario: starting a drag in left frame
976 // Test coverage: dragstart DOM event, dragstart data passed to the OS.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,DragStartInFrame)977 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, DragStartInFrame) {
978 std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
979 ASSERT_TRUE(NavigateToTestPage("a.com"));
980 ASSERT_TRUE(NavigateLeftFrame(frame_site, "image_source.html"));
981
982 // Setup test expectations.
983 DOMDragEventVerifier expected_dom_event_data;
984 expected_dom_event_data.set_expected_client_position("(55, 50)");
985 expected_dom_event_data.set_expected_drop_effect("none");
986 // (dragstart event handler in image_source.html is asking for "copy" only).
987 expected_dom_event_data.set_expected_effect_allowed("copy");
988 expected_dom_event_data.set_expected_page_position("(55, 50)");
989
990 // TODO(lukasza): Figure out why the dragstart event
991 // - lists "Files" on the mime types list,
992 // - doesn't list "text/plain" on the mime types list.
993 // (i.e. why expectations below differ from expectations for dragenter,
994 // dragover, dragend and/or drop events in DragImageBetweenFrames test).
995 expected_dom_event_data.set_expected_mime_types(
996 "Files,text/html,text/uri-list");
997
998 // Start the drag in the left frame.
999 DragStartWaiter drag_start_waiter(web_contents());
1000 drag_start_waiter.SuppressPassingStartDragFurther();
1001 DOMDragEventWaiter dragstart_event_waiter("dragstart", left_frame());
1002 EXPECT_TRUE(SimulateMouseDownAndDragStartInLeftFrame());
1003
1004 // Verify Javascript event data.
1005 {
1006 std::string dragstart_event;
1007 EXPECT_TRUE(
1008 dragstart_event_waiter.WaitForNextMatchingEvent(&dragstart_event));
1009 EXPECT_THAT(dragstart_event, expected_dom_event_data.Matches());
1010 }
1011
1012 // Verify data being passed to the OS.
1013 {
1014 std::string text;
1015 std::string html;
1016 int operation = 0;
1017 gfx::Point location_inside_web_contents;
1018 drag_start_waiter.WaitUntilDragStart(&text, &html, &operation,
1019 &location_inside_web_contents);
1020 EXPECT_EQ(embedded_test_server()->GetURL(frame_site,
1021 "/image_decoding/droids.jpg"),
1022 text);
1023 EXPECT_THAT(html,
1024 testing::MatchesRegex("<img .*src=\""
1025 "http://.*/image_decoding/droids.jpg"
1026 "\">"));
1027 EXPECT_EQ(expected_location_of_drag_start_in_left_frame(),
1028 location_inside_web_contents);
1029 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, operation);
1030 }
1031
1032 // Try to leave everything in a clean state.
1033 SimulateMouseUp();
1034 }
1035
1036 #if defined(OS_WIN)
1037 // There is no known way to execute test-controlled tasks during
1038 // a drag-and-drop loop run by Windows OS.
1039 #define MAYBE_DragImageBetweenFrames DISABLED_DragImageBetweenFrames
1040 #elif defined(OS_LINUX) || defined(OS_CHROMEOS)
1041 #define MAYBE_DragImageBetweenFrames DISABLED_DragImageBetweenFrames
1042 #else
1043 #define MAYBE_DragImageBetweenFrames DragImageBetweenFrames
1044 #endif
1045
1046 // Data that needs to be shared across multiple test steps below
1047 // (i.e. across DragImageBetweenFrames_Step2 and DragImageBetweenFrames_Step3).
1048 struct DragAndDropBrowserTest::DragImageBetweenFrames_TestState {
1049 DOMDragEventVerifier expected_dom_event_data;
1050 std::unique_ptr<DOMDragEventWaiter> dragstart_event_waiter;
1051 std::unique_ptr<DOMDragEventWaiter> drop_event_waiter;
1052 std::unique_ptr<DOMDragEventWaiter> dragend_event_waiter;
1053 std::unique_ptr<DOMDragEventCounter> left_frame_events_counter;
1054 std::unique_ptr<DOMDragEventCounter> right_frame_events_counter;
1055 };
1056
1057 // Scenario: drag an image from the left into the right frame.
1058 // Test coverage: dragleave, dragenter, dragover, dragend, drop DOM events.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,MAYBE_DragImageBetweenFrames)1059 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, MAYBE_DragImageBetweenFrames) {
1060 // Note that drag and drop will not expose data across cross-site frames on
1061 // the same page - this is why the same |frame_site| is used below both for
1062 // the left and the right frame. See also https://crbug.com/59081.
1063 std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
1064 ASSERT_TRUE(NavigateToTestPage("a.com"));
1065 ASSERT_TRUE(NavigateLeftFrame(frame_site, "image_source.html"));
1066 ASSERT_TRUE(NavigateRightFrame(frame_site, "drop_target.html"));
1067
1068 // Setup test expectations.
1069 DragAndDropBrowserTest::DragImageBetweenFrames_TestState state;
1070 state.left_frame_events_counter.reset(new DOMDragEventCounter(left_frame()));
1071 state.right_frame_events_counter.reset(
1072 new DOMDragEventCounter(right_frame()));
1073 state.expected_dom_event_data.set_expected_client_position("(55, 50)");
1074 state.expected_dom_event_data.set_expected_drop_effect("none");
1075 // (dragstart event handler in image_source.html is asking for "copy" only).
1076 state.expected_dom_event_data.set_expected_effect_allowed("copy");
1077 state.expected_dom_event_data.set_expected_mime_types(
1078 "text/html,text/plain,text/uri-list");
1079 state.expected_dom_event_data.set_expected_page_position("(55, 50)");
1080
1081 // Start the drag in the left frame.
1082 DragStartWaiter drag_start_waiter(web_contents());
1083 drag_start_waiter.PostTaskWhenDragStarts(
1084 base::Bind(&DragAndDropBrowserTest::DragImageBetweenFrames_Step2,
1085 base::Unretained(this), base::Unretained(&state)));
1086 state.dragstart_event_waiter.reset(
1087 new DOMDragEventWaiter("dragstart", left_frame()));
1088 EXPECT_TRUE(SimulateMouseDownAndDragStartInLeftFrame());
1089
1090 // The next step of the test (DragImageBetweenFrames_Step2) runs inside the
1091 // nested drag-and-drop message loop - the call below won't return until the
1092 // drag-and-drop has already ended.
1093 drag_start_waiter.WaitUntilDragStart(nullptr, nullptr, nullptr, nullptr);
1094
1095 DragImageBetweenFrames_Step3(&state);
1096 }
1097
DragImageBetweenFrames_Step2(DragAndDropBrowserTest::DragImageBetweenFrames_TestState * state)1098 void DragAndDropBrowserTest::DragImageBetweenFrames_Step2(
1099 DragAndDropBrowserTest::DragImageBetweenFrames_TestState* state) {
1100 // Verify dragstart DOM event.
1101 {
1102 std::string dragstart_event;
1103 EXPECT_TRUE(state->dragstart_event_waiter->WaitForNextMatchingEvent(
1104 &dragstart_event));
1105 state->dragstart_event_waiter.reset();
1106
1107 // Only a single "dragstart" should have fired in the left frame since the
1108 // start of the test. We also allow any number of "dragover" events.
1109 EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
1110 "dragstart"));
1111 EXPECT_EQ(0, state->left_frame_events_counter->GetNumberOfReceivedEvents(
1112 {"dragleave", "dragenter", "drop", "dragend"}));
1113
1114 // No events should have fired in the right frame yet.
1115 EXPECT_EQ(0, state->right_frame_events_counter->GetNumberOfReceivedEvents(
1116 {"dragstart", "dragleave", "dragenter", "dragover", "drop",
1117 "dragend"}));
1118 }
1119
1120 // While dragging, move mouse within the left frame.
1121 // Without this extra mouse move we wouldn't get a dragleave event later on.
1122 ASSERT_TRUE(SimulateMouseMoveToLeftFrame());
1123
1124 // While dragging, move mouse from the left into the right frame.
1125 // This should trigger dragleave and dragenter events.
1126 {
1127 DOMDragEventWaiter dragleave_event_waiter("dragleave", left_frame());
1128 DOMDragEventWaiter dragenter_event_waiter("dragenter", right_frame());
1129 state->left_frame_events_counter->Reset();
1130 state->right_frame_events_counter->Reset();
1131 ASSERT_TRUE(SimulateMouseMoveToRightFrame());
1132
1133 { // Verify dragleave DOM event.
1134 std::string dragleave_event;
1135
1136 state->expected_dom_event_data.set_expected_client_position("(355, 150)");
1137 state->expected_dom_event_data.set_expected_page_position("(355, 150)");
1138
1139 EXPECT_TRUE(
1140 dragleave_event_waiter.WaitForNextMatchingEvent(&dragleave_event));
1141 EXPECT_THAT(dragleave_event, state->expected_dom_event_data.Matches());
1142 }
1143
1144 { // Verify dragenter DOM event.
1145 std::string dragenter_event;
1146
1147 // Update expected event coordinates after SimulateMouseMoveToRightFrame
1148 // (these coordinates are relative to the right frame).
1149 state->expected_dom_event_data.set_expected_client_position("(155, 150)");
1150 state->expected_dom_event_data.set_expected_page_position("(155, 150)");
1151
1152 EXPECT_TRUE(
1153 dragenter_event_waiter.WaitForNextMatchingEvent(&dragenter_event));
1154 EXPECT_THAT(dragenter_event, state->expected_dom_event_data.Matches());
1155 }
1156
1157 // Note that ash (unlike aura/x11) will not fire dragover event in response
1158 // to the same mouse event that trigerred a dragenter. Because of that, we
1159 // postpone dragover testing until the next test step below. See
1160 // implementation of ash::DragDropController::DragUpdate for details.
1161 }
1162
1163 // Move the mouse twice in the right frame. The 1st move will ensure that
1164 // allowed operations communicated by the renderer will be stored in
1165 // WebContentsViewAura::current_drag_op_. The 2nd move will ensure that this
1166 // gets be copied into DesktopDragDropClientAuraX11::negotiated_operation_.
1167 for (int i = 0; i < 2; i++) {
1168 DOMDragEventWaiter dragover_event_waiter("dragover", right_frame());
1169 ASSERT_TRUE(SimulateMouseMoveToRightFrame());
1170
1171 { // Verify dragover DOM event.
1172 std::string dragover_event;
1173 EXPECT_TRUE(
1174 dragover_event_waiter.WaitForNextMatchingEvent(&dragover_event));
1175 EXPECT_THAT(dragover_event, state->expected_dom_event_data.Matches());
1176 }
1177 }
1178
1179 // Only a single "dragleave" should have fired in the left frame since the
1180 // last checkpoint. We also allow any number of "dragover" events.
1181 EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
1182 "dragleave"));
1183 EXPECT_EQ(0, state->left_frame_events_counter->GetNumberOfReceivedEvents(
1184 {"dragstart", "dragenter", "drop", "dragend"}));
1185
1186 // A single "dragenter" + at least one "dragover" event should have fired in
1187 // the right frame since the last checkpoint.
1188 EXPECT_EQ(1, state->right_frame_events_counter->GetNumberOfReceivedEvents(
1189 "dragenter"));
1190 EXPECT_LE(1, state->right_frame_events_counter->GetNumberOfReceivedEvents(
1191 "dragover"));
1192 EXPECT_EQ(0, state->right_frame_events_counter->GetNumberOfReceivedEvents(
1193 {"dragstart", "dragleave", "drop", "dragend"}));
1194
1195 // Release the mouse button to end the drag.
1196 state->drop_event_waiter.reset(new DOMDragEventWaiter("drop", right_frame()));
1197 state->dragend_event_waiter.reset(
1198 new DOMDragEventWaiter("dragend", left_frame()));
1199 state->left_frame_events_counter->Reset();
1200 state->right_frame_events_counter->Reset();
1201 SimulateMouseUp();
1202 // The test will continue in DragImageBetweenFrames_Step3.
1203 }
1204
DragImageBetweenFrames_Step3(DragAndDropBrowserTest::DragImageBetweenFrames_TestState * state)1205 void DragAndDropBrowserTest::DragImageBetweenFrames_Step3(
1206 DragAndDropBrowserTest::DragImageBetweenFrames_TestState* state) {
1207 // Verify drop DOM event.
1208 {
1209 std::string drop_event;
1210 EXPECT_TRUE(
1211 state->drop_event_waiter->WaitForNextMatchingEvent(&drop_event));
1212 state->drop_event_waiter.reset();
1213 EXPECT_THAT(drop_event, state->expected_dom_event_data.Matches());
1214 }
1215
1216 // Verify dragend DOM event.
1217 {
1218 // TODO(lukasza): Figure out why the drop event sees different values of
1219 // DataTransfer.dropEffect and DataTransfer.types properties.
1220 state->expected_dom_event_data.set_expected_drop_effect("copy");
1221 state->expected_dom_event_data.set_expected_mime_types("");
1222
1223 // TODO: https://crbug.com/686136: dragEnd coordinates for non-OOPIF
1224 // scenarios are currently broken.
1225 state->expected_dom_event_data.set_expected_client_position(
1226 "<no expectation>");
1227 state->expected_dom_event_data.set_expected_page_position(
1228 "<no expectation>");
1229
1230 std::string dragend_event;
1231 EXPECT_TRUE(
1232 state->dragend_event_waiter->WaitForNextMatchingEvent(&dragend_event));
1233 state->dragend_event_waiter.reset();
1234 EXPECT_THAT(dragend_event, state->expected_dom_event_data.Matches());
1235 }
1236
1237 // Only a single "dragend" should have fired in the left frame since the last
1238 // checkpoint.
1239 EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
1240 "dragend"));
1241 EXPECT_EQ(0,
1242 state->left_frame_events_counter->GetNumberOfReceivedEvents(
1243 {"dragstart", "dragleave", "dragenter", "dragover", "drop"}));
1244
1245 // A single "drop" + possibly some "dragover" events should have fired in the
1246 // right frame since the last checkpoint.
1247 EXPECT_EQ(
1248 1, state->right_frame_events_counter->GetNumberOfReceivedEvents("drop"));
1249 EXPECT_EQ(0, state->right_frame_events_counter->GetNumberOfReceivedEvents(
1250 {"dragstart", "dragleave", "dragenter", "dragend"}));
1251 }
1252
1253 #if defined(OS_WIN)
1254 // There is no known way to execute test-controlled tasks during
1255 // a drag-and-drop loop run by Windows OS.
1256 #define MAYBE_DragImageFromDisappearingFrame \
1257 DISABLED_DragImageFromDisappearingFrame
1258 #else
1259 #define MAYBE_DragImageFromDisappearingFrame DragImageFromDisappearingFrame
1260 #endif
1261
1262 // Data that needs to be shared across multiple test steps below
1263 // (i.e. across DragImageFromDisappearingFrame_Step2 and
1264 // DragImageFromDisappearingFrame_Step3).
1265 struct DragAndDropBrowserTest::DragImageFromDisappearingFrame_TestState {
1266 DOMDragEventVerifier expected_dom_event_data;
1267 std::unique_ptr<DOMDragEventWaiter> drop_event_waiter;
1268 };
1269
1270 // Scenario: drag an image from the left into the right frame and delete the
1271 // left frame during the drag. This is a regression test for
1272 // https://crbug.com/670123.
1273 // Test coverage: dragenter, dragover, drop DOM events.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,MAYBE_DragImageFromDisappearingFrame)1274 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,
1275 MAYBE_DragImageFromDisappearingFrame) {
1276 // Load the test page.
1277 std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
1278 ASSERT_TRUE(NavigateToTestPage("a.com"));
1279 ASSERT_TRUE(NavigateLeftFrame(frame_site, "image_source.html"));
1280 ASSERT_TRUE(NavigateRightFrame(frame_site, "drop_target.html"));
1281
1282 // Setup test expectations.
1283 DragAndDropBrowserTest::DragImageFromDisappearingFrame_TestState state;
1284 state.expected_dom_event_data.set_expected_drop_effect("none");
1285 // (dragstart event handler in image_source.html is asking for "copy" only).
1286 state.expected_dom_event_data.set_expected_effect_allowed("copy");
1287 state.expected_dom_event_data.set_expected_mime_types(
1288 "text/html,text/plain,text/uri-list");
1289 state.expected_dom_event_data.set_expected_client_position("(155, 150)");
1290 state.expected_dom_event_data.set_expected_page_position("(155, 150)");
1291
1292 // Start the drag in the left frame.
1293 DragStartWaiter drag_start_waiter(web_contents());
1294 drag_start_waiter.PostTaskWhenDragStarts(
1295 base::Bind(&DragAndDropBrowserTest::DragImageFromDisappearingFrame_Step2,
1296 base::Unretained(this), base::Unretained(&state)));
1297 EXPECT_TRUE(SimulateMouseDownAndDragStartInLeftFrame());
1298
1299 // The next step of the test (DragImageFromDisappearingFrame_Step2) runs
1300 // inside the nested drag-and-drop message loop - the call below won't return
1301 // until the drag-and-drop has already ended.
1302 drag_start_waiter.WaitUntilDragStart(nullptr, nullptr, nullptr, nullptr);
1303
1304 DragImageFromDisappearingFrame_Step3(&state);
1305 }
1306
DragImageFromDisappearingFrame_Step2(DragAndDropBrowserTest::DragImageFromDisappearingFrame_TestState * state)1307 void DragAndDropBrowserTest::DragImageFromDisappearingFrame_Step2(
1308 DragAndDropBrowserTest::DragImageFromDisappearingFrame_TestState* state) {
1309 // Delete the left frame in an attempt to repro https://crbug.com/670123.
1310 content::RenderFrameDeletedObserver frame_deleted_observer(left_frame());
1311 ASSERT_TRUE(ExecuteScript(web_contents()->GetMainFrame(),
1312 "frame = document.getElementById('left');\n"
1313 "frame.parentNode.removeChild(frame);\n"));
1314 frame_deleted_observer.WaitUntilDeleted();
1315
1316 // While dragging, move mouse from the left into the right frame.
1317 // This should trigger dragleave and dragenter events.
1318 {
1319 DOMDragEventWaiter dragenter_event_waiter("dragenter", right_frame());
1320 ASSERT_TRUE(SimulateMouseMoveToRightFrame());
1321
1322 { // Verify dragenter DOM event.
1323 std::string dragenter_event;
1324 EXPECT_TRUE(
1325 dragenter_event_waiter.WaitForNextMatchingEvent(&dragenter_event));
1326 EXPECT_THAT(dragenter_event, state->expected_dom_event_data.Matches());
1327 }
1328
1329 // Note that ash (unlike aura/x11) will not fire dragover event in response
1330 // to the same mouse event that trigerred a dragenter. Because of that, we
1331 // postpone dragover testing until the next test step below. See
1332 // implementation of ash::DragDropController::DragUpdate for details.
1333 }
1334
1335 // Move the mouse twice in the right frame. The 1st move will ensure that
1336 // allowed operations communicated by the renderer will be stored in
1337 // WebContentsViewAura::current_drag_op_. The 2nd move will ensure that this
1338 // gets be copied into DesktopDragDropClientAuraX11::negotiated_operation_.
1339 for (int i = 0; i < 2; i++) {
1340 DOMDragEventWaiter dragover_event_waiter("dragover", right_frame());
1341 ASSERT_TRUE(SimulateMouseMoveToRightFrame());
1342
1343 { // Verify dragover DOM event.
1344 std::string dragover_event;
1345 EXPECT_TRUE(
1346 dragover_event_waiter.WaitForNextMatchingEvent(&dragover_event));
1347 EXPECT_THAT(dragover_event, state->expected_dom_event_data.Matches());
1348 }
1349 }
1350
1351 // Release the mouse button to end the drag.
1352 state->drop_event_waiter.reset(new DOMDragEventWaiter("drop", right_frame()));
1353 SimulateMouseUp();
1354 // The test will continue in DragImageFromDisappearingFrame_Step3.
1355 }
1356
DragImageFromDisappearingFrame_Step3(DragAndDropBrowserTest::DragImageFromDisappearingFrame_TestState * state)1357 void DragAndDropBrowserTest::DragImageFromDisappearingFrame_Step3(
1358 DragAndDropBrowserTest::DragImageFromDisappearingFrame_TestState* state) {
1359 // Verify drop DOM event.
1360 {
1361 std::string drop_event;
1362 EXPECT_TRUE(
1363 state->drop_event_waiter->WaitForNextMatchingEvent(&drop_event));
1364 state->drop_event_waiter.reset();
1365 EXPECT_THAT(drop_event, state->expected_dom_event_data.Matches());
1366 }
1367 }
1368
1369 // There is no known way to execute test-controlled tasks during
1370 // a drag-and-drop loop run by Windows OS.
1371 #if defined(OS_WIN)
1372 #define MAYBE_CrossSiteDrag DISABLED_CrossSiteDrag
1373 #else
1374 #define MAYBE_CrossSiteDrag CrossSiteDrag
1375 #endif
1376
1377 // Data that needs to be shared across multiple test steps below
1378 // (i.e. across CrossSiteDrag_Step2 and CrossSiteDrag_Step3).
1379 struct DragAndDropBrowserTest::CrossSiteDrag_TestState {
1380 std::unique_ptr<DOMDragEventWaiter> dragend_event_waiter;
1381 std::unique_ptr<DOMDragEventCounter> left_frame_events_counter;
1382 std::unique_ptr<DOMDragEventCounter> right_frame_events_counter;
1383 };
1384
1385 // Scenario: drag an image from the left into the right frame when the
1386 // left-vs-right frames are cross-site. This is a regression test for
1387 // https://crbug.com/59081.
1388 //
1389 // Test coverage: absence of dragenter, dragover, drop DOM events
1390 // + presence of dragstart, dragleave and dragend.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,MAYBE_CrossSiteDrag)1391 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, MAYBE_CrossSiteDrag) {
1392 std::string left_frame_site = "c.com"; // Always cross-site VS main frame.
1393 std::string right_frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
1394 ASSERT_TRUE(NavigateToTestPage("a.com"));
1395 ASSERT_TRUE(NavigateLeftFrame(left_frame_site, "image_source.html"));
1396 ASSERT_TRUE(NavigateRightFrame(right_frame_site, "drop_target.html"));
1397
1398 // Setup test expectations.
1399 DragAndDropBrowserTest::CrossSiteDrag_TestState state;
1400 state.left_frame_events_counter.reset(new DOMDragEventCounter(left_frame()));
1401 state.right_frame_events_counter.reset(
1402 new DOMDragEventCounter(right_frame()));
1403
1404 // Start the drag in the left frame.
1405 DragStartWaiter drag_start_waiter(web_contents());
1406 drag_start_waiter.PostTaskWhenDragStarts(
1407 base::Bind(&DragAndDropBrowserTest::CrossSiteDrag_Step2,
1408 base::Unretained(this), base::Unretained(&state)));
1409 EXPECT_TRUE(SimulateMouseDownAndDragStartInLeftFrame());
1410
1411 // The next step of the test (CrossSiteDrag_Step2) runs inside the
1412 // nested drag-and-drop message loop - the call below won't return until the
1413 // drag-and-drop has already ended.
1414 drag_start_waiter.WaitUntilDragStart(nullptr, nullptr, nullptr, nullptr);
1415
1416 CrossSiteDrag_Step3(&state);
1417 }
1418
CrossSiteDrag_Step2(DragAndDropBrowserTest::CrossSiteDrag_TestState * state)1419 void DragAndDropBrowserTest::CrossSiteDrag_Step2(
1420 DragAndDropBrowserTest::CrossSiteDrag_TestState* state) {
1421 // While "dragleave" and "drop" events are not expected in this test, we
1422 // simulate extra mouse operations for consistency with
1423 // DragImageBetweenFrames_Step2.
1424 ASSERT_TRUE(SimulateMouseMoveToLeftFrame());
1425 for (int i = 0; i < 3; i++) {
1426 content::DOMMessageQueue dom_message_queue(web_contents());
1427 ASSERT_TRUE(SimulateMouseMoveToRightFrame());
1428
1429 // No events are expected from the right frame, so we can't wait for a
1430 // dragover event here. Still - we do want to wait until the right frame
1431 // has had a chance to process any previous browser IPCs, so that in case
1432 // there *is* a bug and a dragover event *does* happen, we won't terminate
1433 // the test before the event has had a chance to be reported back to the
1434 // browser.
1435 std::string expected_response = base::StringPrintf("\"i%d\"", i);
1436 right_frame()->ExecuteJavaScriptWithUserGestureForTests(
1437 base::UTF8ToUTF16(base::StringPrintf(
1438 "domAutomationController.send(%s);", expected_response.c_str())));
1439
1440 // Wait until our response comes back (it might be mixed with responses
1441 // carrying events that are sent by event_monitoring.js).
1442 std::string actual_response;
1443 do {
1444 ASSERT_TRUE(dom_message_queue.WaitForMessage(&actual_response));
1445 } while (actual_response != expected_response);
1446 }
1447
1448 // Release the mouse button to end the drag.
1449 state->dragend_event_waiter.reset(
1450 new DOMDragEventWaiter("dragend", left_frame()));
1451 SimulateMouseUp();
1452 // The test will continue in DragImageBetweenFrames_Step3.
1453 }
1454
CrossSiteDrag_Step3(DragAndDropBrowserTest::CrossSiteDrag_TestState * state)1455 void DragAndDropBrowserTest::CrossSiteDrag_Step3(
1456 DragAndDropBrowserTest::CrossSiteDrag_TestState* state) {
1457 EXPECT_TRUE(state->dragend_event_waiter->WaitForNextMatchingEvent(nullptr));
1458
1459 // Since the start of the test the left frame should have seen a single
1460 // "dragstart",
1461 // and a "dragend" event (and possibly a "dragleave" and some "dragover"
1462 // events).
1463 EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
1464 "dragstart"));
1465 EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
1466 "dragend"));
1467 EXPECT_EQ(
1468 0, state->left_frame_events_counter->GetNumberOfReceivedEvents("drop"));
1469
1470 // No events should have fired in the right frame, because it is cross-site
1471 // from the source of the drag. This is the essence of this test.
1472 EXPECT_EQ(0, state->right_frame_events_counter->GetNumberOfReceivedEvents(
1473 {"dragstart", "dragleave", "dragenter", "dragover", "drop",
1474 "dragend"}));
1475 }
1476
1477 // Test that screenX/screenY for drag updates are in screen coordinates.
1478 // See https://crbug.com/600402 where we mistook the root window coordinate
1479 // space for the screen coordinate space.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,DragUpdateScreenCoordinates)1480 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, DragUpdateScreenCoordinates) {
1481 // Reposition the window so that the root window coordinate space and the
1482 // screen coordinate space are clearly distinct. Otherwise this test would
1483 // be inconclusive.
1484 // In addition to offsetting the window, use a small window size to avoid
1485 // rejection of the new bounds by the system.
1486 browser()->window()->SetBounds(gfx::Rect(200, 100, 700, 500));
1487 do {
1488 base::RunLoop run_loop;
1489 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1490 FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
1491 run_loop.Run();
1492 } while (browser()->window()->GetBounds().origin() != gfx::Point(200, 100));
1493
1494 std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
1495 ASSERT_TRUE(NavigateToTestPage("a.com"));
1496 ASSERT_TRUE(NavigateRightFrame(frame_site, "drop_target.html"));
1497
1498 const gfx::Point screen_position = GetMiddleOfRightFrameInScreenCoords();
1499
1500 DOMDragEventVerifier expected_dom_event_data;
1501 expected_dom_event_data.set_expected_client_position("(155, 150)");
1502 expected_dom_event_data.set_expected_screen_position(
1503 base::StringPrintf("(%d, %d)", screen_position.x(), screen_position.y()));
1504
1505 DOMDragEventWaiter dragover_waiter("dragover", right_frame());
1506 ASSERT_TRUE(SimulateDragEnterToRightFrame("Dragged test text"));
1507
1508 std::string dragover_event;
1509 ASSERT_TRUE(dragover_waiter.WaitForNextMatchingEvent(&dragover_event));
1510 EXPECT_THAT(dragover_event, expected_dom_event_data.Matches());
1511 }
1512
1513 // TODO(paulmeyer): Should test the case of navigation happening in the middle
1514 // of a drag operation, and cross-site drags should be allowed across a
1515 // navigation.
1516
1517 INSTANTIATE_TEST_SUITE_P(SameSiteSubframe,
1518 DragAndDropBrowserTest,
1519 ::testing::Values(false));
1520
1521 INSTANTIATE_TEST_SUITE_P(CrossSiteSubframe,
1522 DragAndDropBrowserTest,
1523 ::testing::Values(true));
1524
1525 } // namespace chrome
1526