Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
|
sky
2016/11/15 00:37:55
This test is ui specific, and it looks like it's a
Łukasz Anforowicz
2016/11/15 18:28:21
Thanks for the suggestion. I agree that it makes
| |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <memory> | 5 #include <memory> |
| 6 #include <string> | 6 #include <string> |
| 7 | 7 |
| 8 #include "base/callback.h" | |
| 8 #include "base/macros.h" | 9 #include "base/macros.h" |
| 10 #include "base/memory/ref_counted.h" | |
| 11 #include "base/sequenced_task_runner.h" | |
| 9 #include "base/strings/pattern.h" | 12 #include "base/strings/pattern.h" |
| 10 #include "base/strings/string_piece.h" | 13 #include "base/strings/string_piece.h" |
| 11 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
| 12 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
| 13 #include "content/browser/frame_host/frame_tree.h" | 16 #include "base/threading/sequenced_task_runner_handle.h" |
| 14 #include "content/browser/frame_host/frame_tree_node.h" | 17 #include "chrome/browser/ui/browser.h" |
| 15 #include "content/browser/frame_host/render_frame_host_impl.h" | 18 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 16 #include "content/browser/web_contents/web_contents_impl.h" | 19 #include "chrome/test/base/in_process_browser_test.h" |
| 20 #include "chrome/test/base/interactive_test_utils.h" | |
| 21 #include "chrome/test/base/ui_test_utils.h" | |
| 17 #include "content/public/browser/render_frame_host.h" | 22 #include "content/public/browser/render_frame_host.h" |
| 18 #include "content/public/browser/web_contents.h" | 23 #include "content/public/browser/web_contents.h" |
| 19 #include "content/public/test/browser_test_utils.h" | 24 #include "content/public/test/browser_test_utils.h" |
| 20 #include "content/public/test/content_browser_test.h" | 25 #include "content/public/test/content_browser_test.h" |
| 21 #include "content/public/test/content_browser_test_utils.h" | 26 #include "content/public/test/content_browser_test_utils.h" |
| 27 #include "content/public/test/test_frame_navigation_observer.h" | |
| 22 #include "content/public/test/test_utils.h" | 28 #include "content/public/test/test_utils.h" |
| 23 #include "content/shell/browser/shell.h" | |
| 24 #include "net/base/escape.h" | 29 #include "net/base/escape.h" |
| 25 #include "net/dns/mock_host_resolver.h" | 30 #include "net/dns/mock_host_resolver.h" |
| 26 #include "net/test/embedded_test_server/embedded_test_server.h" | 31 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 27 #include "testing/gmock/include/gmock/gmock.h" | 32 #include "testing/gmock/include/gmock/gmock.h" |
| 28 #include "testing/gtest/include/gtest/gtest.h" | 33 #include "testing/gtest/include/gtest/gtest.h" |
| 34 #include "ui/aura/client/drag_drop_client.h" | |
| 29 #include "ui/aura/client/drag_drop_delegate.h" | 35 #include "ui/aura/client/drag_drop_delegate.h" |
| 30 #include "ui/aura/client/screen_position_client.h" | 36 #include "ui/aura/client/screen_position_client.h" |
| 31 #include "ui/aura/window.h" | 37 #include "ui/aura/window.h" |
| 32 #include "ui/base/dragdrop/drag_drop_types.h" | 38 #include "ui/base/dragdrop/drag_drop_types.h" |
| 33 #include "ui/base/dragdrop/drop_target_event.h" | 39 #include "ui/base/dragdrop/drop_target_event.h" |
| 34 #include "ui/base/dragdrop/os_exchange_data.h" | 40 #include "ui/base/dragdrop/os_exchange_data.h" |
| 35 #include "ui/gfx/geometry/point.h" | 41 #include "ui/gfx/geometry/point.h" |
| 36 #include "ui/gfx/geometry/rect.h" | 42 #include "ui/gfx/geometry/rect.h" |
| 37 #include "url/gurl.h" | 43 #include "url/gurl.h" |
| 38 | 44 |
| 39 namespace content { | 45 namespace chrome { |
| 40 | 46 |
| 41 namespace { | 47 namespace { |
| 42 | 48 |
| 43 // TODO(lukasza): Support testing on non-Aura platforms (i.e. Android + Mac?). | 49 // TODO(lukasza): Support testing on non-Aura platforms (i.e. Android + Mac?). |
| 44 // | 50 // |
| 45 // Notes for the TODO above: | 51 // Notes for the TODO above: |
| 46 // | 52 // |
| 47 // - Why inject/simulate drag-and-drop events at the aura::Window* level. | 53 // - Why inject/simulate drag-and-drop events at the aura::Window* level. |
| 48 // | 54 // |
| 49 // - It seems better to inject into UI libraries to cover code *inside* these | 55 // - It seems better to inject into UI libraries to cover code *inside* these |
| 50 // libraries. This might complicate simulation a little bit (i.e. picking | 56 // libraries. This might complicate simulation a little bit (i.e. picking |
| 51 // the right aura::Window and/or aura::client::DragDropDelegate to target), | 57 // the right aura::Window and/or aura::client::DragDropDelegate to target), |
| 52 // but otherwise important bits of code wouldn't get test coverage (i.e. | 58 // but otherwise important bits of code wouldn't get test coverage (i.e. |
| 53 // directly injecting into RenderViewHost->DragTargetDragEnter seems wrong). | 59 // directly injecting into RenderViewHost->DragTargetDragEnter seems wrong). |
| 54 // | 60 // |
| 55 // - In theory, we could introduce WebContentsImpl::DragTargetDragEnter (to be | 61 // - In theory, we could introduce WebContentsImpl::DragTargetDragEnter (to be |
| 56 // used by all UI platforms - so reused by web_contents_view_android.cc, | 62 // used by all UI platforms - so reused by web_contents_view_android.cc, |
| 57 // web_contents_view_aura.cc, web_drag_dest_mac.mm), but it feels wrong - UI | 63 // web_contents_view_aura.cc, web_drag_dest_mac.mm), but it feels wrong - UI |
| 58 // libraries should already know which widget is the target of the event and | 64 // libraries should already know which widget is the target of the event and |
| 59 // so should be able to talk directly to the right widget (i.e. WebContents | 65 // so should be able to talk directly to the right widget (i.e. WebContents |
| 60 // should not be responsible for mapping coordinates to a widget - this is | 66 // should not be responsible for mapping coordinates to a widget - this is |
| 61 // the job of the UI library). | 67 // the job of the UI library). |
| 62 // | 68 // |
| 63 // - Unknowns: | 69 // - Unknowns: |
| 64 // | 70 // |
| 65 // - Will this work for WebView and Plugin testing. | 71 // - Will this work for WebView and Plugin testing. |
| 66 // | |
| 67 // - Will this work for simulating dragging from WebContents into outside of | |
| 68 // the browser (without leaving OS drag&drop machinery in a weird state). | |
| 69 | 72 |
| 70 // Test helper for simulating drag and drop happening in WebContents. | 73 // Test helper for simulating drag and drop happening in WebContents. |
| 71 class DragAndDropSimulator { | 74 class DragAndDropSimulator { |
| 72 public: | 75 public: |
| 73 explicit DragAndDropSimulator(WebContents* web_contents) | 76 explicit DragAndDropSimulator(content::WebContents* web_contents) |
| 74 : web_contents_(web_contents) {} | 77 : web_contents_(web_contents) {} |
| 75 | 78 |
| 76 // Simulates notification that |text| was dragged from outside of the browser, | 79 // Simulates notification that |text| was dragged from outside of the browser, |
| 77 // into the specified |location| inside |web_contents|. | 80 // into the specified |location| inside |web_contents|. |
| 78 // |location| is relative to |web_contents|. | 81 // |location| is relative to |web_contents|. |
| 79 // Returns true upon success. | 82 // Returns true upon success. |
| 80 bool SimulateDragEnter(gfx::Point location, const std::string& text) { | 83 bool SimulateDragEnter(gfx::Point location, const std::string& text) { |
| 81 ui::OSExchangeData data; | 84 ui::OSExchangeData data; |
| 82 data.SetString(base::UTF8ToUTF16(text)); | 85 data.SetString(base::UTF8ToUTF16(text)); |
| 83 return SimulateDragEnter(location, data); | 86 return SimulateDragEnter(location, data); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 150 *out_event_location = root_location; | 153 *out_event_location = root_location; |
| 151 } | 154 } |
| 152 | 155 |
| 153 // These are ui::DropTargetEvent::source_operations_ being sent when manually | 156 // These are ui::DropTargetEvent::source_operations_ being sent when manually |
| 154 // trying out drag&drop of an image file from Nemo (Ubuntu's file explorer) | 157 // trying out drag&drop of an image file from Nemo (Ubuntu's file explorer) |
| 155 // into a content_shell. | 158 // into a content_shell. |
| 156 static constexpr int kDefaultSourceOperations = ui::DragDropTypes::DRAG_MOVE | | 159 static constexpr int kDefaultSourceOperations = ui::DragDropTypes::DRAG_MOVE | |
| 157 ui::DragDropTypes::DRAG_COPY | | 160 ui::DragDropTypes::DRAG_COPY | |
| 158 ui::DragDropTypes::DRAG_LINK; | 161 ui::DragDropTypes::DRAG_LINK; |
| 159 | 162 |
| 160 WebContents* web_contents_; | 163 content::WebContents* web_contents_; |
| 161 std::unique_ptr<ui::DropTargetEvent> active_drag_event_; | 164 std::unique_ptr<ui::DropTargetEvent> active_drag_event_; |
| 162 | 165 |
| 163 DISALLOW_COPY_AND_ASSIGN(DragAndDropSimulator); | 166 DISALLOW_COPY_AND_ASSIGN(DragAndDropSimulator); |
| 164 }; | 167 }; |
| 165 | 168 |
| 169 // Helper for waiting until a drag-and-drop starts (e.g. in response to a | |
| 170 // mouse-down + mouse-move simulated by the test). | |
| 171 class DragStartWaiter : public aura::client::DragDropClient { | |
| 172 public: | |
| 173 // Starts monitoring |web_contents| for a start of a drag-and-drop. | |
| 174 // While alive, prevents a real, OS-level drag-and-drop from starting | |
| 175 // for this particular |web_contents|. | |
| 176 explicit DragStartWaiter(content::WebContents* web_contents) | |
| 177 : web_contents_(web_contents), | |
| 178 message_loop_runner_(new content::MessageLoopRunner), | |
| 179 drag_started_(false) { | |
| 180 DCHECK(web_contents_); | |
| 181 | |
| 182 // Intercept calls to the old DragDropClient. | |
| 183 gfx::NativeWindow root_window = | |
| 184 web_contents_->GetContentNativeView()->GetRootWindow(); | |
| 185 old_client_ = aura::client::GetDragDropClient(root_window); | |
| 186 aura::client::SetDragDropClient(root_window, this); | |
| 187 } | |
| 188 | |
| 189 ~DragStartWaiter() override { | |
| 190 // Restore the original DragDropClient. | |
| 191 gfx::NativeWindow root_window = | |
| 192 web_contents_->GetContentNativeView()->GetRootWindow(); | |
| 193 aura::client::SetDragDropClient(root_window, old_client_); | |
| 194 } | |
| 195 | |
| 196 // Waits until we almost report a drag-and-drop start to the OS | |
| 197 // (notifying the OS will be prevented to help the test continue | |
| 198 // without entering a nested message loop). | |
| 199 // | |
| 200 // Returns true if drag and drop has indeed started (and in this | |
| 201 // case populates |text|, |html| and other parameters with data | |
| 202 // that would have been passed to the OS). | |
| 203 bool WaitUntilDragStartIsIntercepted( | |
| 204 std::string* text, | |
| 205 std::string* html, | |
| 206 int* operation, | |
| 207 gfx::Point* location_inside_web_contents) { | |
| 208 message_loop_runner_->Run(); | |
|
sky
2016/11/15 00:37:55
Might StartDragAndDrop already have been called?
Łukasz Anforowicz
2016/11/15 18:28:21
Yes and this is okay - in this case Run will immed
| |
| 209 | |
| 210 if (!drag_started_) | |
|
sky
2016/11/15 00:37:55
DCHECK?
Łukasz Anforowicz
2016/11/15 18:28:21
Done.
| |
| 211 return false; | |
| 212 | |
| 213 *text = text_; | |
|
sky
2016/11/15 00:37:55
Why not copy the pointers and set the values direc
Łukasz Anforowicz
2016/11/15 18:28:21
I think I'd prefer to leave this as-is:
1. This a
| |
| 214 *html = html_; | |
| 215 *operation = operation_; | |
| 216 *location_inside_web_contents = location_inside_web_contents_; | |
| 217 return true; | |
| 218 } | |
| 219 | |
| 220 // aura::client::DragDropClient overrides: | |
| 221 | |
|
sky
2016/11/15 00:37:55
no newline.
Łukasz Anforowicz
2016/11/15 18:28:21
Done.
| |
| 222 int StartDragAndDrop(const ui::OSExchangeData& data, | |
| 223 aura::Window* root_window, | |
| 224 aura::Window* source_window, | |
| 225 const gfx::Point& screen_location, | |
| 226 int operation, | |
| 227 ui::DragDropTypes::DragEventSource source) override { | |
| 228 if (!drag_started_) { | |
|
sky
2016/11/15 00:37:55
DCHECK(!drag_started_)?
Łukasz Anforowicz
2016/11/15 18:28:21
Hmmm... okay. I thought that this class should be
| |
| 229 drag_started_ = true; | |
| 230 message_loop_runner_->Quit(); | |
| 231 | |
| 232 base::string16 text; | |
| 233 if (data.GetString(&text)) | |
| 234 text_ = base::UTF16ToUTF8(text); | |
| 235 else | |
| 236 text_ = "<no text>"; | |
| 237 | |
| 238 GURL base_url; | |
| 239 base::string16 html; | |
| 240 if (data.GetHtml(&html, &base_url)) | |
| 241 html_ = base::UTF16ToUTF8(html); | |
| 242 else | |
| 243 html_ = "<no html>"; | |
| 244 | |
| 245 gfx::Rect bounds = | |
| 246 web_contents_->GetContentNativeView()->GetBoundsInScreen(); | |
| 247 location_inside_web_contents_ = | |
| 248 screen_location - gfx::Vector2d(bounds.x(), bounds.y()); | |
| 249 | |
| 250 operation_ = operation; | |
| 251 } | |
| 252 | |
| 253 // Forwarding to |old_client_| is undesirable, because test cannot control | |
| 254 // next steps after a nested drag-and-drop loop is entered at the OS level | |
| 255 // (as is the case in Windows, via DoDragDrop). Instead, in the test we | |
| 256 // kind of ignore renderer's request to start drag and drop and never | |
| 257 // forward this request to the OS-specific layers. | |
| 258 return 0; | |
| 259 } | |
| 260 | |
| 261 void DragCancel() override { | |
| 262 ADD_FAILURE() << "Unexpected call to DragCancel"; | |
| 263 } | |
| 264 | |
| 265 bool IsDragDropInProgress() override { return drag_started_; } | |
| 266 | |
| 267 private: | |
| 268 content::WebContents* web_contents_; | |
| 269 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; | |
| 270 aura::client::DragDropClient* old_client_; | |
| 271 | |
| 272 // Data captured during the first intercepted StartDragAndDrop call. | |
| 273 bool drag_started_; | |
| 274 std::string text_; | |
| 275 std::string html_; | |
| 276 int operation_; | |
| 277 gfx::Point location_inside_web_contents_; | |
| 278 }; | |
|
sky
2016/11/15 00:37:55
DISALLOW...
Łukasz Anforowicz
2016/11/15 18:28:21
Ooops. Done.
| |
| 279 | |
| 166 // Helper for waiting for notifications from | 280 // Helper for waiting for notifications from |
| 167 // content/test/data/drag_and_drop/event_monitoring.js | 281 // content/test/data/drag_and_drop/event_monitoring.js |
| 168 class DOMDragEventWaiter { | 282 class DOMDragEventWaiter { |
| 169 public: | 283 public: |
| 170 explicit DOMDragEventWaiter(const std::string& event_type_to_wait_for, | 284 explicit DOMDragEventWaiter(const std::string& event_type_to_wait_for, |
| 171 const ToRenderFrameHost& target) | 285 const content::ToRenderFrameHost& target) |
| 172 : target_frame_name_(target.render_frame_host()->GetFrameName()), | 286 : target_frame_name_(target.render_frame_host()->GetFrameName()), |
| 173 event_type_to_wait_for_(event_type_to_wait_for), | 287 event_type_to_wait_for_(event_type_to_wait_for), |
| 174 dom_message_queue_( | 288 dom_message_queue_(content::WebContents::FromRenderFrameHost( |
| 175 WebContents::FromRenderFrameHost(target.render_frame_host())) {} | 289 target.render_frame_host())) {} |
| 176 | 290 |
| 177 // Waits until |target| calls reportDragEvent in | 291 // Waits until |target| calls reportDragEvent in |
| 178 // content/test/data/drag_and_drop/event_monitoring.js with event_type | 292 // chrome/test/data/drag_and_drop/event_monitoring.js with event_type |
| 179 // property set to |event_type_to_wait_for|. (|target| and | 293 // property set to |event_type_to_wait_for|. (|target| and |
| 180 // |event_type_to_wait_for| are passed to the constructor). | 294 // |event_type_to_wait_for| are passed to the constructor). |
| 181 // | 295 // |
| 182 // Returns the event details via |found_event| (in form of a JSON-encoded | 296 // Returns the event details via |found_event| (in form of a JSON-encoded |
| 183 // object). See content/test/data/drag_and_drop/event_monitoring.js for keys | 297 // object). See chrome/test/data/drag_and_drop/event_monitoring.js for keys |
| 184 // and properties that |found_event| is expected to have. | 298 // and properties that |found_event| is expected to have. |
| 185 // | 299 // |
| 186 // Returns true upon success. It is okay if |response| is null. | 300 // Returns true upon success. It is okay if |response| is null. |
| 187 bool WaitForNextMatchingEvent(std::string* found_event) WARN_UNUSED_RESULT { | 301 bool WaitForNextMatchingEvent(std::string* found_event) WARN_UNUSED_RESULT { |
| 188 std::string candidate_event; | 302 std::string candidate_event; |
| 189 bool got_right_event_type = false; | 303 bool got_right_event_type = false; |
| 190 bool got_right_window_name = false; | 304 bool got_right_window_name = false; |
| 191 do { | 305 do { |
| 192 if (!dom_message_queue_.WaitForMessage(&candidate_event)) | 306 if (!dom_message_queue_.WaitForMessage(&candidate_event)) |
| 193 return false; | 307 return false; |
| 194 | 308 |
| 195 got_right_event_type = base::MatchPattern( | 309 got_right_event_type = base::MatchPattern( |
| 196 candidate_event, base::StringPrintf("*\"event_type\":\"%s\"*", | 310 candidate_event, base::StringPrintf("*\"event_type\":\"%s\"*", |
| 197 event_type_to_wait_for_.c_str())); | 311 event_type_to_wait_for_.c_str())); |
| 198 | 312 |
| 199 got_right_window_name = base::MatchPattern( | 313 got_right_window_name = base::MatchPattern( |
| 200 candidate_event, base::StringPrintf("*\"window_name\":\"%s\"*", | 314 candidate_event, base::StringPrintf("*\"window_name\":\"%s\"*", |
| 201 target_frame_name_.c_str())); | 315 target_frame_name_.c_str())); |
| 202 } while (!got_right_event_type || !got_right_window_name); | 316 } while (!got_right_event_type || !got_right_window_name); |
| 203 | 317 |
| 204 if (found_event) | 318 if (found_event) |
| 205 *found_event = candidate_event; | 319 *found_event = candidate_event; |
| 206 | 320 |
| 207 return true; | 321 return true; |
| 208 } | 322 } |
| 209 | 323 |
| 210 private: | 324 private: |
| 211 std::string target_frame_name_; | 325 std::string target_frame_name_; |
| 212 std::string event_type_to_wait_for_; | 326 std::string event_type_to_wait_for_; |
| 213 DOMMessageQueue dom_message_queue_; | 327 content::DOMMessageQueue dom_message_queue_; |
| 328 }; | |
|
sky
2016/11/15 00:37:55
DISALLOW...
Łukasz Anforowicz
2016/11/15 18:28:21
Done.
| |
| 329 | |
| 330 // Helper for verifying contents of DOM events associated with drag-and-drop. | |
| 331 class DOMDragEventVerifier { | |
| 332 public: | |
| 333 DOMDragEventVerifier(){}; | |
|
sky
2016/11/15 00:37:55
no ';' and space between '()' and '{}'.
Łukasz Anforowicz
2016/11/15 18:28:21
Done.
| |
| 334 | |
| 335 void set_expected_drop_effect(const std::string& value) { | |
| 336 expected_drop_effect_ = value; | |
| 337 } | |
| 338 | |
| 339 void set_expected_effect_allowed(const std::string& value) { | |
| 340 expected_effect_allowed_ = value; | |
| 341 } | |
| 342 | |
| 343 void set_expected_mime_types(const std::string& value) { | |
| 344 expected_mime_types_ = value; | |
| 345 } | |
| 346 | |
| 347 // Returns a matcher that will match a std::string (drag event data - e.g. | |
| 348 // one returned by DOMDragEventWaiter::WaitForNextMatchingEvent) if it matches | |
| 349 // the expectations of this DOMDragEventVerifier. | |
| 350 testing::Matcher<std::string> Matches() const { | |
| 351 return testing::AllOf( | |
| 352 FieldMatches("drop_effect", expected_drop_effect_), | |
| 353 FieldMatches("effect_allowed", expected_effect_allowed_), | |
| 354 FieldMatches("mime_types", expected_mime_types_)); | |
| 355 } | |
| 356 | |
| 357 private: | |
| 358 static testing::Matcher<std::string> FieldMatches( | |
| 359 const std::string& field_name, | |
| 360 const std::string& expected_value) { | |
| 361 if (expected_value == "<no expectation>") | |
| 362 return testing::A<std::string>(); | |
| 363 | |
| 364 return testing::HasSubstr(base::StringPrintf( | |
| 365 "\"%s\":\"%s\"", field_name.c_str(), expected_value.c_str())); | |
| 366 } | |
| 367 | |
| 368 std::string expected_drop_effect_ = "<no expectation>"; | |
| 369 std::string expected_effect_allowed_ = "<no expectation>"; | |
| 370 std::string expected_mime_types_ = "<no expectation>"; | |
| 214 }; | 371 }; |
| 215 | 372 |
| 216 const char kTestPagePath[] = "/drag_and_drop/page.html"; | 373 const char kTestPagePath[] = "/drag_and_drop/page.html"; |
| 217 | 374 |
| 218 } // namespace | 375 } // namespace |
| 219 | 376 |
| 220 class DragAndDropBrowserTest : public ContentBrowserTest { | 377 class DragAndDropBrowserTest : public InProcessBrowserTest { |
| 221 public: | 378 public: |
| 222 DragAndDropBrowserTest(){}; | 379 DragAndDropBrowserTest(){}; |
| 223 | 380 |
| 224 protected: | 381 protected: |
| 225 void SetUpOnMainThread() override { | 382 void SetUpOnMainThread() override { |
| 226 host_resolver()->AddRule("*", "127.0.0.1"); | 383 host_resolver()->AddRule("*", "127.0.0.1"); |
| 227 ASSERT_TRUE(embedded_test_server()->Start()); | 384 ASSERT_TRUE(embedded_test_server()->Start()); |
| 228 content::SetupCrossSiteRedirector(embedded_test_server()); | 385 content::SetupCrossSiteRedirector(embedded_test_server()); |
| 229 drag_simulator_.reset(new DragAndDropSimulator(shell()->web_contents())); | 386 drag_simulator_.reset(new DragAndDropSimulator(web_contents())); |
| 230 } | 387 } |
| 231 | 388 |
| 232 // Navigates to content/test/data/drag_and_drop/page.html, with page origin | 389 content::RenderFrameHost* left_frame() { |
| 233 // and frame contents being controlled by the parameters. | 390 AssertTestPageIsLoaded(); |
| 234 bool NavigateToTestPage(const std::string& main_origin, | 391 return GetFrameByName("left"); |
| 235 const std::string& left_frame, | 392 } |
| 236 const std::string& right_frame) { | |
| 237 GURL base_url = embedded_test_server()->GetURL(main_origin, kTestPagePath); | |
| 238 | 393 |
| 239 std::string left_arg; | 394 content::RenderFrameHost* right_frame() { |
| 240 if (!left_frame.empty()) { | 395 AssertTestPageIsLoaded(); |
| 241 left_arg = net::EscapeQueryParamValue( | 396 return GetFrameByName("right"); |
| 242 std::string("/cross-site/") + left_frame, true); | 397 } |
| 243 } | |
| 244 std::string right_arg; | |
| 245 if (!right_frame.empty()) { | |
| 246 right_arg = net::EscapeQueryParamValue( | |
| 247 std::string("/cross-site/") + right_frame, true); | |
| 248 } | |
| 249 std::string query = base::StringPrintf("left=%s&right=%s", left_arg.c_str(), | |
| 250 right_arg.c_str()); | |
| 251 GURL::Replacements query_replacement; | |
| 252 query_replacement.SetQueryStr(query); | |
| 253 GURL target_url = base_url.ReplaceComponents(query_replacement); | |
| 254 | 398 |
| 255 return NavigateToURL(shell(), target_url); | 399 content::WebContents* web_contents() { |
| 400 return browser()->tab_strip_model()->GetActiveWebContents(); | |
| 256 } | 401 } |
| 257 | 402 |
| 403 ////////////////////// | |
| 404 // Navigation helpers. | |
| 405 | |
| 406 bool NavigateToTestPage(const std::string& origin_of_main_frame) { | |
| 407 GURL url = | |
| 408 embedded_test_server()->GetURL(origin_of_main_frame, kTestPagePath); | |
| 409 ui_test_utils::NavigateToURL(browser(), url); | |
| 410 return web_contents()->GetLastCommittedURL() == url; | |
| 411 } | |
| 412 | |
| 413 // Navigates the left frame to |filename| (found under | |
| 414 // chrome/test/data/drag_and_drop directory). | |
| 415 bool NavigateLeftFrame(const std::string& origin, | |
| 416 const std::string& filename) { | |
| 417 AssertTestPageIsLoaded(); | |
| 418 return NavigateNamedFrame("left", origin, filename); | |
| 419 } | |
| 420 | |
| 421 // Navigates the right frame to |filename| (found under | |
| 422 // chrome/test/data/drag_and_drop directory). | |
| 423 bool NavigateRightFrame(const std::string& origin, | |
| 424 const std::string& filename) { | |
| 425 AssertTestPageIsLoaded(); | |
| 426 return NavigateNamedFrame("right", origin, filename); | |
| 427 } | |
| 428 | |
| 429 //////////////////////////////////////////////////////////// | |
| 430 // Simulation of starting a drag-and-drop (using the mouse). | |
| 431 | |
| 432 bool SimulateMouseDownAndDragStartInLeftFrame() { | |
| 433 AssertTestPageIsLoaded(); | |
| 434 if (!SimulateMouseMove(kMiddleOfLeftFrame) || !SimulateMouseDown() || | |
| 435 !SimulateMouseMove(expected_location_of_drag_start_in_left_frame())) | |
| 436 return false; | |
| 437 | |
| 438 return true; | |
| 439 } | |
| 440 | |
| 441 gfx::Point expected_location_of_drag_start_in_left_frame() { | |
| 442 // TODO(crbug.com/653490): The delta below should exceed kDragThresholdX and | |
| 443 // kDragThresholdY from MouseEventManager.cpp in blink. Ideally, it would | |
| 444 // come from the OS instead. | |
| 445 return kMiddleOfLeftFrame + gfx::Vector2d(10, 10); | |
| 446 } | |
| 447 | |
| 448 bool SimulateMouseUp() { | |
| 449 return ui_test_utils::SendMouseEventsSync(ui_controls::LEFT, | |
| 450 ui_controls::UP); | |
| 451 } | |
| 452 | |
| 453 //////////////////////////////////////////////////////////////////// | |
| 454 // Simulation of dragging from outside the browser into web contents | |
| 455 // (using DragAndDropSimulator, not simulating mouse events). | |
| 456 | |
| 258 bool SimulateDragEnterToRightFrame(const std::string& text) { | 457 bool SimulateDragEnterToRightFrame(const std::string& text) { |
| 259 AssertTestPageIsLoaded(); | 458 AssertTestPageIsLoaded(); |
| 260 return drag_simulator_->SimulateDragEnter(kMiddleOfRightFrame, text); | 459 return drag_simulator_->SimulateDragEnter(kMiddleOfRightFrame, text); |
| 261 } | 460 } |
| 262 | 461 |
| 263 bool SimulateDropInRightFrame() { | 462 bool SimulateDropInRightFrame() { |
| 264 AssertTestPageIsLoaded(); | 463 AssertTestPageIsLoaded(); |
| 265 return drag_simulator_->SimulateDrop(kMiddleOfRightFrame); | 464 return drag_simulator_->SimulateDrop(kMiddleOfRightFrame); |
| 266 } | 465 } |
| 267 | 466 |
| 268 RenderFrameHost* right_frame() { | 467 private: |
| 269 AssertTestPageIsLoaded(); | 468 bool SimulateMouseDown() { |
| 270 return GetFrameByName("right"); | 469 return ui_test_utils::SendMouseEventsSync(ui_controls::LEFT, |
| 470 ui_controls::DOWN); | |
| 271 } | 471 } |
| 272 | 472 |
| 273 private: | 473 bool SimulateMouseMove(const gfx::Point& location_inside_web_contents) { |
| 274 RenderFrameHost* GetFrameByName(const std::string& name_to_find) { | 474 gfx::Rect bounds = web_contents()->GetContainerBounds(); |
| 275 WebContentsImpl* web_contents = | 475 return ui_test_utils::SendMouseMoveSync( |
| 276 static_cast<WebContentsImpl*>(shell()->web_contents()); | 476 gfx::Point(bounds.x() + location_inside_web_contents.x(), |
| 277 FrameTree* frame_tree = web_contents->GetFrameTree(); | 477 bounds.y() + location_inside_web_contents.y())); |
| 278 return frame_tree->FindByName(name_to_find)->current_frame_host(); | 478 } |
| 479 | |
| 480 bool NavigateNamedFrame(const std::string& frame_name, | |
| 481 const std::string& origin, | |
| 482 const std::string& filename) { | |
| 483 content::RenderFrameHost* frame = GetFrameByName(frame_name); | |
| 484 if (!frame) | |
| 485 return false; | |
| 486 | |
| 487 std::string script; | |
| 488 int response = 0; | |
| 489 | |
| 490 // Navigate the frame and wait for the load event. | |
| 491 script = base::StringPrintf( | |
| 492 "location.href = '/cross-site/%s/drag_and_drop/%s';\n" | |
| 493 "setTimeout(function() { domAutomationController.send(42); }, 0);", | |
| 494 origin.c_str(), filename.c_str()); | |
| 495 content::TestFrameNavigationObserver observer(frame); | |
| 496 if (!content::ExecuteScriptAndExtractInt(frame, script, &response)) | |
| 497 return false; | |
| 498 if (response != 42) | |
| 499 return false; | |
| 500 observer.Wait(); | |
| 501 | |
| 502 // Wait until frame contents (e.g. images) have painted (which should happen | |
| 503 // in the animation frame that *starts* after the onload event - therefore | |
| 504 // we need to wait for 2 animation frames). | |
| 505 script = std::string( | |
| 506 "requestAnimationFrame(function() {\n" | |
| 507 " requestAnimationFrame(function() {\n" | |
| 508 " domAutomationController.send(43);\n" | |
| 509 " });\n" | |
| 510 "});\n"); | |
| 511 if (!content::ExecuteScriptAndExtractInt(frame, script, &response)) | |
| 512 return false; | |
| 513 if (response != 43) | |
| 514 return false; | |
| 515 | |
| 516 return true; | |
| 517 } | |
| 518 | |
| 519 content::RenderFrameHost* GetFrameByName(const std::string& name_to_find) { | |
| 520 content::RenderFrameHost* result = nullptr; | |
| 521 for (content::RenderFrameHost* rfh : web_contents()->GetAllFrames()) { | |
| 522 if (rfh->GetFrameName() == name_to_find) { | |
| 523 if (result) { | |
| 524 ADD_FAILURE() << "More than one frame named " | |
| 525 << "'" << name_to_find << "'"; | |
| 526 return nullptr; | |
| 527 } | |
| 528 result = rfh; | |
| 529 } | |
| 530 } | |
| 531 | |
| 532 EXPECT_TRUE(result) << "Couldn't find a frame named " | |
| 533 << "'" << name_to_find << "'"; | |
| 534 return result; | |
| 279 } | 535 } |
| 280 | 536 |
| 281 void AssertTestPageIsLoaded() { | 537 void AssertTestPageIsLoaded() { |
| 282 ASSERT_EQ(kTestPagePath, | 538 ASSERT_EQ(kTestPagePath, web_contents()->GetLastCommittedURL().path()); |
| 283 shell()->web_contents()->GetLastCommittedURL().path()); | |
| 284 } | 539 } |
| 285 | 540 |
| 286 std::unique_ptr<DragAndDropSimulator> drag_simulator_; | 541 std::unique_ptr<DragAndDropSimulator> drag_simulator_; |
| 287 | 542 |
| 288 // Constants with coordinates within content/test/data/drag_and_drop/page.html | 543 // Constants with coordinates within content/test/data/drag_and_drop/page.html |
| 289 const gfx::Point kMiddleOfLeftFrame = gfx::Point(200, 200); | 544 const gfx::Point kMiddleOfLeftFrame = gfx::Point(200, 200); |
| 290 const gfx::Point kMiddleOfRightFrame = gfx::Point(400, 200); | 545 const gfx::Point kMiddleOfRightFrame = gfx::Point(400, 200); |
| 291 | 546 |
| 292 DISALLOW_COPY_AND_ASSIGN(DragAndDropBrowserTest); | 547 DISALLOW_COPY_AND_ASSIGN(DragAndDropBrowserTest); |
| 293 }; | 548 }; |
| 294 | 549 |
| 295 IN_PROC_BROWSER_TEST_F(DragAndDropBrowserTest, DropTextFromOutside) { | 550 IN_PROC_BROWSER_TEST_F(DragAndDropBrowserTest, DropTextFromOutside) { |
| 296 ASSERT_TRUE(NavigateToTestPage("a.com", | 551 ASSERT_TRUE(NavigateToTestPage("a.com")); |
| 297 "", // Left frame is unused by this test. | 552 ASSERT_TRUE(NavigateRightFrame("b.com", "drop_target.html")); |
| 298 "c.com/drag_and_drop/drop_target.html")); | |
| 299 | 553 |
| 554 // Setup test expectations. | |
| 555 DOMDragEventVerifier expected_dom_event_data; | |
| 556 expected_dom_event_data.set_expected_drop_effect("none"); | |
| 557 expected_dom_event_data.set_expected_effect_allowed("all"); | |
| 558 expected_dom_event_data.set_expected_mime_types("text/plain"); | |
| 559 | |
| 560 // Drag text from outside the browser into/over the right frame. | |
| 300 { | 561 { |
| 301 std::string dragover_event; | |
| 302 DOMDragEventWaiter dragover_waiter("dragover", right_frame()); | 562 DOMDragEventWaiter dragover_waiter("dragover", right_frame()); |
| 303 ASSERT_TRUE(SimulateDragEnterToRightFrame("Dragged test text")); | 563 ASSERT_TRUE(SimulateDragEnterToRightFrame("Dragged test text")); |
| 564 | |
| 565 std::string dragover_event; | |
| 304 ASSERT_TRUE(dragover_waiter.WaitForNextMatchingEvent(&dragover_event)); | 566 ASSERT_TRUE(dragover_waiter.WaitForNextMatchingEvent(&dragover_event)); |
| 305 EXPECT_THAT(dragover_event, testing::HasSubstr("\"drop_effect\":\"none\"")); | 567 EXPECT_THAT(dragover_event, expected_dom_event_data.Matches()); |
| 306 EXPECT_THAT(dragover_event, | |
| 307 testing::HasSubstr("\"effect_allowed\":\"all\"")); | |
| 308 EXPECT_THAT(dragover_event, | |
| 309 testing::HasSubstr("\"mime_types\":\"text/plain\"")); | |
| 310 } | 568 } |
| 311 | 569 |
| 570 // Drop into the right frame. | |
| 312 { | 571 { |
| 313 std::string drop_event; | |
| 314 DOMDragEventWaiter drop_waiter("drop", right_frame()); | 572 DOMDragEventWaiter drop_waiter("drop", right_frame()); |
| 315 ASSERT_TRUE(SimulateDropInRightFrame()); | 573 ASSERT_TRUE(SimulateDropInRightFrame()); |
| 574 | |
| 575 std::string drop_event; | |
| 316 ASSERT_TRUE(drop_waiter.WaitForNextMatchingEvent(&drop_event)); | 576 ASSERT_TRUE(drop_waiter.WaitForNextMatchingEvent(&drop_event)); |
| 317 EXPECT_THAT(drop_event, testing::HasSubstr("\"drop_effect\":\"none\"")); | 577 EXPECT_THAT(drop_event, expected_dom_event_data.Matches()); |
| 318 EXPECT_THAT(drop_event, testing::HasSubstr("\"effect_allowed\":\"all\"")); | |
| 319 EXPECT_THAT(drop_event, | |
| 320 testing::HasSubstr("\"mime_types\":\"text/plain\"")); | |
| 321 } | 578 } |
| 322 } | 579 } |
| 323 | 580 |
| 581 // The test is disabled on Ozone because of trouble with mouse simulation | |
| 582 // during the test - see https://crbug.com/665042. | |
| 583 #if defined(USE_OZONE) | |
| 584 #define MAYBE_DragStartInFrame DISABLED_DragStartInFrame | |
| 585 #else | |
| 586 #define MAYBE_DragStartInFrame DragStartInFrame | |
| 587 #endif | |
| 588 IN_PROC_BROWSER_TEST_F(DragAndDropBrowserTest, MAYBE_DragStartInFrame) { | |
| 589 std::string frame_site = "b.com"; | |
| 590 ASSERT_TRUE(NavigateToTestPage("a.com")); | |
| 591 ASSERT_TRUE(NavigateLeftFrame(frame_site, "image_source.html")); | |
| 592 | |
| 593 // Setup test expectations. | |
| 594 // (dragstart event handler in image_source.html is asking for "copy" only). | |
| 595 DOMDragEventVerifier expected_dom_event_data; | |
| 596 expected_dom_event_data.set_expected_drop_effect("none"); | |
| 597 expected_dom_event_data.set_expected_effect_allowed("copy"); | |
| 598 expected_dom_event_data.set_expected_mime_types( | |
| 599 "Files,text/html,text/uri-list"); | |
| 600 | |
| 601 // Start the drag in the left frame. | |
| 602 DragStartWaiter drag_start_waiter(web_contents()); | |
| 603 DOMDragEventWaiter dragstart_event_waiter("dragstart", left_frame()); | |
| 604 EXPECT_TRUE(SimulateMouseDownAndDragStartInLeftFrame()); | |
| 605 | |
| 606 // Verify Javascript event data. | |
| 607 { | |
| 608 std::string dragstart_event; | |
| 609 EXPECT_TRUE( | |
| 610 dragstart_event_waiter.WaitForNextMatchingEvent(&dragstart_event)); | |
| 611 EXPECT_THAT(dragstart_event, expected_dom_event_data.Matches()); | |
| 612 } | |
| 613 | |
| 614 // Verify data being passed to the OS. | |
| 615 { | |
| 616 std::string text; | |
| 617 std::string html; | |
| 618 int operation = 0; | |
| 619 gfx::Point location_inside_web_contents; | |
| 620 EXPECT_TRUE(drag_start_waiter.WaitUntilDragStartIsIntercepted( | |
|
sky
2016/11/15 00:37:55
SHould this be an assert? If it fails is there rea
Łukasz Anforowicz
2016/11/15 18:28:21
N/A - after addressing earlier comments WaitUntilD
| |
| 621 &text, &html, &operation, &location_inside_web_contents)); | |
| 622 EXPECT_EQ(embedded_test_server()->GetURL(frame_site, | |
| 623 "/image_decoding/droids.jpg"), | |
| 624 text); | |
| 625 EXPECT_THAT(html, | |
| 626 testing::MatchesRegex("<img .*src=\"" | |
| 627 "http://.*/image_decoding/droids.jpg" | |
| 628 "\">")); | |
| 629 EXPECT_EQ(expected_location_of_drag_start_in_left_frame(), | |
| 630 location_inside_web_contents); | |
| 631 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, operation); | |
| 632 } | |
| 633 | |
| 634 // Try to leave everything in a clean state. | |
| 635 SimulateMouseUp(); | |
| 636 } | |
| 637 | |
| 324 } // namespace chrome | 638 } // namespace chrome |
| OLD | NEW |