1// Copyright 2013 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 "apps/app_window.h" 6#include "apps/app_window_registry.h" 7#include "base/strings/stringprintf.h" 8#include "base/strings/utf_string_conversions.h" 9#include "chrome/app/chrome_command_ids.h" 10#include "chrome/browser/apps/app_browsertest_util.h" 11#include "chrome/browser/chrome_content_browser_client.h" 12#include "chrome/browser/extensions/extension_test_message_listener.h" 13#include "chrome/browser/guest_view/guest_view_base.h" 14#include "chrome/browser/guest_view/guest_view_manager.h" 15#include "chrome/browser/guest_view/guest_view_manager_factory.h" 16#include "chrome/browser/profiles/profile.h" 17#include "chrome/browser/renderer_context_menu/render_view_context_menu_browsertest_util.h" 18#include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h" 19#include "chrome/test/base/interactive_test_utils.h" 20#include "chrome/test/base/test_launcher_utils.h" 21#include "chrome/test/base/ui_test_utils.h" 22#include "content/public/browser/notification_service.h" 23#include "content/public/browser/render_process_host.h" 24#include "content/public/browser/render_view_host.h" 25#include "content/public/browser/render_widget_host_iterator.h" 26#include "content/public/browser/render_widget_host_view.h" 27#include "content/public/browser/web_contents.h" 28#include "content/public/common/content_switches.h" 29#include "content/public/test/browser_test_utils.h" 30#include "net/test/embedded_test_server/embedded_test_server.h" 31#include "ui/base/ime/composition_text.h" 32#include "ui/base/ime/text_input_client.h" 33#include "ui/base/test/ui_controls.h" 34#include "ui/events/keycodes/keyboard_codes.h" 35 36using apps::AppWindow; 37 38class TestGuestViewManager : public GuestViewManager { 39 public: 40 explicit TestGuestViewManager(content::BrowserContext* context) : 41 GuestViewManager(context), 42 web_contents_(NULL) {} 43 44 content::WebContents* WaitForGuestCreated() { 45 if (web_contents_) 46 return web_contents_; 47 48 message_loop_runner_ = new content::MessageLoopRunner; 49 message_loop_runner_->Run(); 50 return web_contents_; 51 } 52 53 private: 54 // GuestViewManager override: 55 virtual void AddGuest(int guest_instance_id, 56 content::WebContents* guest_web_contents) OVERRIDE{ 57 GuestViewManager::AddGuest(guest_instance_id, guest_web_contents); 58 web_contents_ = guest_web_contents; 59 60 if (message_loop_runner_) 61 message_loop_runner_->Quit(); 62 } 63 64 content::WebContents* web_contents_; 65 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; 66}; 67 68// Test factory for creating test instances of GuestViewManager. 69class TestGuestViewManagerFactory : public GuestViewManagerFactory { 70 public: 71 TestGuestViewManagerFactory() : 72 test_guest_view_manager_(NULL) {} 73 74 virtual ~TestGuestViewManagerFactory() {} 75 76 virtual GuestViewManager* CreateGuestViewManager( 77 content::BrowserContext* context) OVERRIDE { 78 return GetManager(context); 79 } 80 81 TestGuestViewManager* GetManager(content::BrowserContext* context) { 82 if (!test_guest_view_manager_) { 83 test_guest_view_manager_ = new TestGuestViewManager(context); 84 } 85 return test_guest_view_manager_; 86 } 87 88 private: 89 TestGuestViewManager* test_guest_view_manager_; 90 91 DISALLOW_COPY_AND_ASSIGN(TestGuestViewManagerFactory); 92}; 93 94class WebViewInteractiveTest 95 : public extensions::PlatformAppBrowserTest { 96 public: 97 WebViewInteractiveTest() 98 : guest_web_contents_(NULL), 99 embedder_web_contents_(NULL), 100 corner_(gfx::Point()), 101 mouse_click_result_(false), 102 first_click_(true) { 103 GuestViewManager::set_factory_for_testing(&factory_); 104 } 105 106 TestGuestViewManager* GetGuestViewManager() { 107 return factory_.GetManager(browser()->profile()); 108 } 109 110 void MoveMouseInsideWindowWithListener(gfx::Point point, 111 const std::string& message) { 112 ExtensionTestMessageListener move_listener(message, false); 113 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( 114 gfx::Point(corner_.x() + point.x(), corner_.y() + point.y()))); 115 ASSERT_TRUE(move_listener.WaitUntilSatisfied()); 116 } 117 118 void SendMouseClickWithListener(ui_controls::MouseButton button, 119 const std::string& message) { 120 ExtensionTestMessageListener listener(message, false); 121 SendMouseClick(button); 122 ASSERT_TRUE(listener.WaitUntilSatisfied()); 123 } 124 125 void SendMouseClick(ui_controls::MouseButton button) { 126 SendMouseEvent(button, ui_controls::DOWN); 127 SendMouseEvent(button, ui_controls::UP); 128 } 129 130 void MoveMouseInsideWindow(const gfx::Point& point) { 131 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( 132 gfx::Point(corner_.x() + point.x(), corner_.y() + point.y()))); 133 } 134 135 gfx::NativeWindow GetPlatformAppWindow() { 136 const apps::AppWindowRegistry::AppWindowList& app_windows = 137 apps::AppWindowRegistry::Get(browser()->profile())->app_windows(); 138 return (*app_windows.begin())->GetNativeWindow(); 139 } 140 141 void SendKeyPressToPlatformApp(ui::KeyboardCode key) { 142 ASSERT_EQ(1U, GetAppWindowCount()); 143 ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( 144 GetPlatformAppWindow(), key, false, false, false, false)); 145 } 146 147 void SendCopyKeyPressToPlatformApp() { 148 ASSERT_EQ(1U, GetAppWindowCount()); 149#if defined(OS_MACOSX) 150 // Send Cmd+C on MacOSX. 151 ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( 152 GetPlatformAppWindow(), ui::VKEY_C, false, false, false, true)); 153#else 154 // Send Ctrl+C on Windows and Linux/ChromeOS. 155 ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( 156 GetPlatformAppWindow(), ui::VKEY_C, true, false, false, false)); 157#endif 158 } 159 160 void SendStartOfLineKeyPressToPlatformApp() { 161#if defined(OS_MACOSX) 162 // Send Cmd+Left on MacOSX. 163 ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( 164 GetPlatformAppWindow(), ui::VKEY_LEFT, false, false, false, true)); 165#else 166 // Send Ctrl+Left on Windows and Linux/ChromeOS. 167 ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( 168 GetPlatformAppWindow(), ui::VKEY_LEFT, true, false, false, false)); 169#endif 170 } 171 172 void SendBackShortcutToPlatformApp() { 173#if defined(OS_MACOSX) 174 // Send Cmd+[ on MacOSX. 175 ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( 176 GetPlatformAppWindow(), ui::VKEY_OEM_4, false, false, false, true)); 177#else 178 // Send browser back key on Linux/Windows. 179 ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( 180 GetPlatformAppWindow(), ui::VKEY_BROWSER_BACK, 181 false, false, false, false)); 182#endif 183 } 184 185 void SendForwardShortcutToPlatformApp() { 186#if defined(OS_MACOSX) 187 // Send Cmd+] on MacOSX. 188 ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( 189 GetPlatformAppWindow(), ui::VKEY_OEM_6, false, false, false, true)); 190#else 191 // Send browser back key on Linux/Windows. 192 ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( 193 GetPlatformAppWindow(), ui::VKEY_BROWSER_FORWARD, 194 false, false, false, false)); 195#endif 196 } 197 198 void SendMouseEvent(ui_controls::MouseButton button, 199 ui_controls::MouseButtonState state) { 200 if (first_click_) { 201 mouse_click_result_ = ui_test_utils::SendMouseEventsSync(button, 202 state); 203 first_click_ = false; 204 } else { 205 ASSERT_EQ(mouse_click_result_, ui_test_utils::SendMouseEventsSync( 206 button, state)); 207 } 208 } 209 210 enum TestServer { 211 NEEDS_TEST_SERVER, 212 NO_TEST_SERVER 213 }; 214 215 scoped_ptr<ExtensionTestMessageListener> RunAppHelper( 216 const std::string& test_name, 217 const std::string& app_location, 218 TestServer test_server, 219 content::WebContents** embedder_web_contents) { 220 // For serving guest pages. 221 if ((test_server == NEEDS_TEST_SERVER) && !StartEmbeddedTestServer()) { 222 LOG(ERROR) << "FAILED TO START TEST SERVER."; 223 return scoped_ptr<ExtensionTestMessageListener>(); 224 } 225 226 LoadAndLaunchPlatformApp(app_location.c_str(), "Launched"); 227 if (!ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow())) { 228 LOG(ERROR) << "UNABLE TO FOCUS TEST WINDOW."; 229 return scoped_ptr<ExtensionTestMessageListener>(); 230 } 231 232 // Flush any pending events to make sure we start with a clean slate. 233 content::RunAllPendingInMessageLoop(); 234 235 *embedder_web_contents = GetFirstAppWindowWebContents(); 236 237 scoped_ptr<ExtensionTestMessageListener> done_listener( 238 new ExtensionTestMessageListener("TEST_PASSED", false)); 239 done_listener->set_failure_message("TEST_FAILED"); 240 if (!content::ExecuteScript( 241 *embedder_web_contents, 242 base::StringPrintf("runTest('%s')", test_name.c_str()))) { 243 LOG(ERROR) << "UNABLE TO START TEST"; 244 return scoped_ptr<ExtensionTestMessageListener>(); 245 } 246 247 return done_listener.Pass(); 248 } 249 250 void TestHelper(const std::string& test_name, 251 const std::string& app_location, 252 TestServer test_server) { 253 content::WebContents* embedder_web_contents = NULL; 254 scoped_ptr<ExtensionTestMessageListener> done_listener( 255 RunAppHelper( 256 test_name, app_location, test_server, &embedder_web_contents)); 257 258 ASSERT_TRUE(done_listener); 259 ASSERT_TRUE(done_listener->WaitUntilSatisfied()); 260 261 guest_web_contents_ = GetGuestViewManager()->WaitForGuestCreated(); 262 } 263 264 void RunTest(const std::string& app_name) { 265 } 266 void SetupTest(const std::string& app_name, 267 const std::string& guest_url_spec) { 268 ASSERT_TRUE(StartEmbeddedTestServer()); 269 GURL::Replacements replace_host; 270 std::string host_str("localhost"); // Must stay in scope with replace_host. 271 replace_host.SetHostStr(host_str); 272 273 GURL guest_url = embedded_test_server()->GetURL(guest_url_spec); 274 guest_url = guest_url.ReplaceComponents(replace_host); 275 276 ui_test_utils::UrlLoadObserver guest_observer( 277 guest_url, content::NotificationService::AllSources()); 278 279 LoadAndLaunchPlatformApp(app_name.c_str(), "connected"); 280 281 guest_observer.Wait(); 282 content::Source<content::NavigationController> source = 283 guest_observer.source(); 284 EXPECT_TRUE(source->GetWebContents()->GetRenderProcessHost()-> 285 IsIsolatedGuest()); 286 287 guest_web_contents_ = source->GetWebContents(); 288 embedder_web_contents_ = 289 GuestViewBase::FromWebContents(guest_web_contents_)-> 290 embedder_web_contents(); 291 292 gfx::Rect offset = embedder_web_contents_->GetContainerBounds(); 293 corner_ = gfx::Point(offset.x(), offset.y()); 294 295 const testing::TestInfo* const test_info = 296 testing::UnitTest::GetInstance()->current_test_info(); 297 const char* prefix = "DragDropWithinWebView"; 298 if (!strncmp(test_info->name(), prefix, strlen(prefix))) { 299 // In the drag drop test we add 20px padding to the page body because on 300 // windows if we get too close to the edge of the window the resize cursor 301 // appears and we start dragging the window edge. 302 corner_.Offset(20, 20); 303 } 304 } 305 306 content::WebContents* guest_web_contents() { 307 return guest_web_contents_; 308 } 309 310 content::WebContents* embedder_web_contents() { 311 return embedder_web_contents_; 312 } 313 314 gfx::Point corner() { 315 return corner_; 316 } 317 318 void SimulateRWHMouseClick(content::RenderWidgetHost* rwh, 319 blink::WebMouseEvent::Button button, 320 int x, 321 int y) { 322 blink::WebMouseEvent mouse_event; 323 mouse_event.button = button; 324 mouse_event.x = mouse_event.windowX = x; 325 mouse_event.y = mouse_event.windowY = y; 326 mouse_event.modifiers = 0; 327 328 mouse_event.type = blink::WebInputEvent::MouseDown; 329 rwh->ForwardMouseEvent(mouse_event); 330 mouse_event.type = blink::WebInputEvent::MouseUp; 331 rwh->ForwardMouseEvent(mouse_event); 332 } 333 334 class PopupCreatedObserver { 335 public: 336 explicit PopupCreatedObserver() 337 : initial_widget_count_(0), 338 last_render_widget_host_(NULL), 339 seen_new_widget_(false) {} 340 341 ~PopupCreatedObserver() {} 342 343 void Wait() { 344 size_t current_widget_count = CountWidgets(); 345 if (!seen_new_widget_ && 346 current_widget_count == initial_widget_count_ + 1) { 347 seen_new_widget_ = true; 348 } 349 350 // If we haven't seen any new widget or we get 0 size widget, we need to 351 // schedule waiting. 352 bool needs_to_schedule_wait = true; 353 354 if (seen_new_widget_) { 355 gfx::Rect popup_bounds = 356 last_render_widget_host_->GetView()->GetViewBounds(); 357 if (!popup_bounds.size().IsEmpty()) 358 needs_to_schedule_wait = false; 359 } 360 361 if (needs_to_schedule_wait) { 362 ScheduleWait(); 363 } else { 364 // We are done. 365 if (message_loop_) 366 message_loop_->Quit(); 367 } 368 369 if (!message_loop_) { 370 message_loop_ = new content::MessageLoopRunner; 371 message_loop_->Run(); 372 } 373 } 374 375 void Init() { initial_widget_count_ = CountWidgets(); } 376 377 // Returns the last widget created. 378 content::RenderWidgetHost* last_render_widget_host() { 379 return last_render_widget_host_; 380 } 381 382 private: 383 void ScheduleWait() { 384 base::MessageLoop::current()->PostDelayedTask( 385 FROM_HERE, 386 base::Bind(&PopupCreatedObserver::Wait, base::Unretained(this)), 387 base::TimeDelta::FromMilliseconds(200)); 388 } 389 390 size_t CountWidgets() { 391 scoped_ptr<content::RenderWidgetHostIterator> widgets( 392 content::RenderWidgetHost::GetRenderWidgetHosts()); 393 size_t num_widgets = 0; 394 while (content::RenderWidgetHost* widget = widgets->GetNextHost()) { 395 if (widget->IsRenderView()) 396 continue; 397 ++num_widgets; 398 last_render_widget_host_ = widget; 399 } 400 return num_widgets; 401 } 402 403 size_t initial_widget_count_; 404 content::RenderWidgetHost* last_render_widget_host_; 405 scoped_refptr<content::MessageLoopRunner> message_loop_; 406 bool seen_new_widget_; 407 408 DISALLOW_COPY_AND_ASSIGN(PopupCreatedObserver); 409 }; 410 411 void WaitForTitle(const char* title) { 412 base::string16 expected_title(base::ASCIIToUTF16(title)); 413 base::string16 error_title(base::ASCIIToUTF16("FAILED")); 414 content::TitleWatcher title_watcher(guest_web_contents(), expected_title); 415 title_watcher.AlsoWaitForTitle(error_title); 416 ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle()); 417 } 418 419 void PopupTestHelper(const gfx::Point& padding) { 420 PopupCreatedObserver popup_observer; 421 popup_observer.Init(); 422 // Press alt+DOWN to open popup. 423 bool alt = true; 424 content::SimulateKeyPress( 425 guest_web_contents(), ui::VKEY_DOWN, false, false, alt, false); 426 popup_observer.Wait(); 427 428 content::RenderWidgetHost* popup_rwh = 429 popup_observer.last_render_widget_host(); 430 gfx::Rect popup_bounds = popup_rwh->GetView()->GetViewBounds(); 431 432 content::RenderViewHost* embedder_rvh = 433 GetFirstAppWindowWebContents()->GetRenderViewHost(); 434 gfx::Rect embedder_bounds = embedder_rvh->GetView()->GetViewBounds(); 435 gfx::Vector2d diff = popup_bounds.origin() - embedder_bounds.origin(); 436 LOG(INFO) << "DIFF: x = " << diff.x() << ", y = " << diff.y(); 437 438 const int left_spacing = 40 + padding.x(); // div.style.paddingLeft = 40px. 439 // div.style.paddingTop = 50px + (input box height = 26px). 440 const int top_spacing = 50 + 26 + padding.y(); 441 442 // If the popup is placed within |threshold_px| of the expected position, 443 // then we consider the test as a pass. 444 const int threshold_px = 10; 445 446 EXPECT_LE(std::abs(diff.x() - left_spacing), threshold_px); 447 EXPECT_LE(std::abs(diff.y() - top_spacing), threshold_px); 448 449 // Close the popup. 450 content::SimulateKeyPress( 451 guest_web_contents(), ui::VKEY_ESCAPE, false, false, false, false); 452 } 453 454 void DragTestStep1() { 455 // Move mouse to start of text. 456 MoveMouseInsideWindow(gfx::Point(45, 8)); 457 MoveMouseInsideWindow(gfx::Point(45, 9)); 458 SendMouseEvent(ui_controls::LEFT, ui_controls::DOWN); 459 460 MoveMouseInsideWindow(gfx::Point(74, 12)); 461 MoveMouseInsideWindow(gfx::Point(78, 12)); 462 463 // Now wait a bit before moving mouse to initiate drag/drop. 464 base::MessageLoop::current()->PostDelayedTask( 465 FROM_HERE, 466 base::Bind(&WebViewInteractiveTest::DragTestStep2, 467 base::Unretained(this)), 468 base::TimeDelta::FromMilliseconds(200)); 469 } 470 471 void DragTestStep2() { 472 // Drag source over target. 473 MoveMouseInsideWindow(gfx::Point(76, 76)); 474 475 // Create a second mouse over the source to trigger the drag over event. 476 MoveMouseInsideWindow(gfx::Point(76, 77)); 477 478 // Release mouse to drop. 479 SendMouseEvent(ui_controls::LEFT, ui_controls::UP); 480 SendMouseClick(ui_controls::LEFT); 481 482 quit_closure_.Run(); 483 484 // Note that following ExtensionTestMessageListener and ExecuteScript* 485 // call must be after we quit |quit_closure_|. Otherwise the class 486 // here won't be able to receive messages sent by chrome.test.sendMessage. 487 // This is because of the nature of drag and drop code (esp. the 488 // MessageLoop) in it. 489 490 // Now check if we got a drop and read the drop data. 491 embedder_web_contents_ = GetFirstAppWindowWebContents(); 492 ExtensionTestMessageListener drop_listener("guest-got-drop", false); 493 EXPECT_TRUE(content::ExecuteScript(embedder_web_contents_, 494 "window.checkIfGuestGotDrop()")); 495 EXPECT_TRUE(drop_listener.WaitUntilSatisfied()); 496 497 std::string last_drop_data; 498 EXPECT_TRUE(content::ExecuteScriptAndExtractString( 499 embedder_web_contents_, 500 "window.domAutomationController.send(getLastDropData())", 501 &last_drop_data)); 502 503 last_drop_data_ = last_drop_data; 504 } 505 506 protected: 507 TestGuestViewManagerFactory factory_; 508 content::WebContents* guest_web_contents_; 509 content::WebContents* embedder_web_contents_; 510 gfx::Point corner_; 511 bool mouse_click_result_; 512 bool first_click_; 513 // Only used in drag/drop test. 514 base::Closure quit_closure_; 515 std::string last_drop_data_; 516}; 517 518// ui_test_utils::SendMouseMoveSync doesn't seem to work on OS_MACOSX, and 519// likely won't work on many other platforms as well, so for now this test 520// is for Windows and Linux only. As of Sept 17th, 2013 this test is disabled 521// on Windows due to flakines, see http://crbug.com/293445. 522 523// Disabled on Linux Aura because pointer lock does not work on Linux Aura. 524// crbug.com/341876 525 526#if defined(OS_LINUX) && !defined(USE_AURA) 527 528IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, PointerLock) { 529 SetupTest("web_view/pointer_lock", 530 "/extensions/platform_apps/web_view/pointer_lock/guest.html"); 531 532 // Move the mouse over the Lock Pointer button. 533 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( 534 gfx::Point(corner().x() + 75, corner().y() + 25))); 535 536 // Click the Lock Pointer button. The first two times the button is clicked 537 // the permission API will deny the request (intentional). 538 ExtensionTestMessageListener exception_listener("request exception", false); 539 SendMouseClickWithListener(ui_controls::LEFT, "lock error"); 540 ASSERT_TRUE(exception_listener.WaitUntilSatisfied()); 541 SendMouseClickWithListener(ui_controls::LEFT, "lock error"); 542 543 // Click the Lock Pointer button, locking the mouse to lockTarget1. 544 SendMouseClickWithListener(ui_controls::LEFT, "locked"); 545 546 // Attempt to move the mouse off of the lock target, and onto lockTarget2, 547 // (which would trigger a test failure). 548 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( 549 gfx::Point(corner().x() + 74, corner().y() + 74))); 550 MoveMouseInsideWindowWithListener(gfx::Point(75, 75), "mouse-move"); 551 552#if defined(OS_WIN) 553 // When the mouse is unlocked on win aura, sending a test mouse click clicks 554 // where the mouse moved to while locked. I was unable to figure out why, and 555 // since the issue only occurs with the test mouse events, just fix it with 556 // a simple workaround - moving the mouse back to where it should be. 557 // TODO(mthiesse): Fix Win Aura simulated mouse events while mouse locked. 558 MoveMouseInsideWindowWithListener(gfx::Point(75, 25), "mouse-move"); 559#endif 560 561 ExtensionTestMessageListener unlocked_listener("unlocked", false); 562 // Send a key press to unlock the mouse. 563 SendKeyPressToPlatformApp(ui::VKEY_ESCAPE); 564 565 // Wait for page to receive (successful) mouse unlock response. 566 ASSERT_TRUE(unlocked_listener.WaitUntilSatisfied()); 567 568 // After the second lock, guest.js sends a message to main.js to remove the 569 // webview object. main.js then removes the div containing the webview, which 570 // should unlock, and leave the mouse over the mousemove-capture-container 571 // div. We then move the mouse over that div to ensure the mouse was properly 572 // unlocked and that the div receieves the message. 573 ExtensionTestMessageListener move_captured_listener("move-captured", false); 574 move_captured_listener.set_failure_message("timeout"); 575 576 // Mouse should already be over lock button (since we just unlocked), so send 577 // click to re-lock the mouse. 578 SendMouseClickWithListener(ui_controls::LEFT, "deleted"); 579 580 // A mousemove event is triggered on the mousemove-capture-container element 581 // when we delete the webview container (since the mouse moves onto the 582 // element), but just in case, send an explicit mouse movement to be safe. 583 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( 584 gfx::Point(corner().x() + 50, corner().y() + 10))); 585 586 // Wait for page to receive second (successful) mouselock response. 587 bool success = move_captured_listener.WaitUntilSatisfied(); 588 if (!success) { 589 fprintf(stderr, "TIMEOUT - retrying\n"); 590 // About 1 in 40 tests fail to detect mouse moves at this point (why?). 591 // Sending a right click seems to fix this (why?). 592 ExtensionTestMessageListener move_listener2("move-captured", false); 593 SendMouseClick(ui_controls::RIGHT); 594 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( 595 gfx::Point(corner().x() + 51, corner().y() + 11))); 596 ASSERT_TRUE(move_listener2.WaitUntilSatisfied()); 597 } 598} 599 600#endif // defined(OS_LINUX) && !defined(USE_AURA) 601 602// Tests that if a <webview> is focused before navigation then the guest starts 603// off focused. 604IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Focus_FocusBeforeNavigation) { 605 TestHelper("testFocusBeforeNavigation", "web_view/focus", NO_TEST_SERVER); 606} 607 608// Tests that setting focus on the <webview> sets focus on the guest. 609IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Focus_FocusEvent) { 610 TestHelper("testFocusEvent", "web_view/focus", NO_TEST_SERVER); 611} 612 613IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Focus_FocusTracksEmbedder) { 614 content::WebContents* embedder_web_contents = NULL; 615 616 scoped_ptr<ExtensionTestMessageListener> done_listener( 617 RunAppHelper("testFocusTracksEmbedder", "web_view/focus", NO_TEST_SERVER, 618 &embedder_web_contents)); 619 done_listener->WaitUntilSatisfied(); 620 621 ExtensionTestMessageListener next_step_listener("TEST_STEP_PASSED", false); 622 next_step_listener.set_failure_message("TEST_STEP_FAILED"); 623 EXPECT_TRUE(content::ExecuteScript( 624 embedder_web_contents, 625 "window.runCommand('testFocusTracksEmbedderRunNextStep');")); 626 627 // Blur the embedder. 628 embedder_web_contents->GetRenderViewHost()->Blur(); 629 // Ensure that the guest is also blurred. 630 ASSERT_TRUE(next_step_listener.WaitUntilSatisfied()); 631} 632 633IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Focus_AdvanceFocus) { 634 content::WebContents* embedder_web_contents = NULL; 635 636 { 637 scoped_ptr<ExtensionTestMessageListener> done_listener( 638 RunAppHelper("testAdvanceFocus", "web_view/focus", NO_TEST_SERVER, 639 &embedder_web_contents)); 640 done_listener->WaitUntilSatisfied(); 641 } 642 643 { 644 ExtensionTestMessageListener listener("button1-focused", false); 645 listener.set_failure_message("TEST_FAILED"); 646 SimulateRWHMouseClick(embedder_web_contents->GetRenderViewHost(), 647 blink::WebMouseEvent::ButtonLeft, 200, 20); 648 content::SimulateKeyPress(embedder_web_contents, ui::VKEY_TAB, 649 false, false, false, false); 650 ASSERT_TRUE(listener.WaitUntilSatisfied()); 651 } 652 653 { 654 // Wait for button1 to be focused again, this means we were asked to 655 // move the focus to the next focusable element. 656 ExtensionTestMessageListener listener("button1-advance-focus", false); 657 listener.set_failure_message("TEST_FAILED"); 658 // TODO(fsamuel): A third Tab key press should not be necessary. 659 // The <webview> will take keyboard focus but it will not focus an initial 660 // element. The initial element is dependent upon tab direction which blink 661 // does not propagate to the plugin. 662 // See http://crbug.com/147644. 663 content::SimulateKeyPress(embedder_web_contents, ui::VKEY_TAB, 664 false, false, false, false); 665 content::SimulateKeyPress(embedder_web_contents, ui::VKEY_TAB, 666 false, false, false, false); 667 content::SimulateKeyPress(embedder_web_contents, ui::VKEY_TAB, 668 false, false, false, false); 669 ASSERT_TRUE(listener.WaitUntilSatisfied()); 670 } 671} 672 673// Tests that blurring <webview> also blurs the guest. 674IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Focus_BlurEvent) { 675 TestHelper("testBlurEvent", "web_view/focus", NO_TEST_SERVER); 676} 677 678// Tests that guests receive edit commands and respond appropriately. 679IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, EditCommands) { 680 LoadAndLaunchPlatformApp("web_view/edit_commands", "connected"); 681 682 ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow( 683 GetPlatformAppWindow())); 684 685 // Flush any pending events to make sure we start with a clean slate. 686 content::RunAllPendingInMessageLoop(); 687 688 ExtensionTestMessageListener copy_listener("copy", false); 689 SendCopyKeyPressToPlatformApp(); 690 691 // Wait for the guest to receive a 'copy' edit command. 692 ASSERT_TRUE(copy_listener.WaitUntilSatisfied()); 693} 694 695// Tests that guests receive edit commands and respond appropriately. 696IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, EditCommandsNoMenu) { 697 SetupTest("web_view/edit_commands_no_menu", 698 "/extensions/platform_apps/web_view/edit_commands_no_menu/" 699 "guest.html"); 700 701 ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow( 702 GetPlatformAppWindow())); 703 704 // Flush any pending events to make sure we start with a clean slate. 705 content::RunAllPendingInMessageLoop(); 706 707 ExtensionTestMessageListener start_of_line_listener("StartOfLine", false); 708 SendStartOfLineKeyPressToPlatformApp(); 709 // Wait for the guest to receive a 'copy' edit command. 710 ASSERT_TRUE(start_of_line_listener.WaitUntilSatisfied()); 711} 712 713IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, 714 NewWindow_NewWindowNameTakesPrecedence) { 715 TestHelper("testNewWindowNameTakesPrecedence", 716 "web_view/newwindow", 717 NEEDS_TEST_SERVER); 718} 719 720IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, 721 NewWindow_WebViewNameTakesPrecedence) { 722 TestHelper("testWebViewNameTakesPrecedence", 723 "web_view/newwindow", 724 NEEDS_TEST_SERVER); 725} 726 727IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_NoName) { 728 TestHelper("testNoName", 729 "web_view/newwindow", 730 NEEDS_TEST_SERVER); 731} 732 733IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_Redirect) { 734 TestHelper("testNewWindowRedirect", 735 "web_view/newwindow", 736 NEEDS_TEST_SERVER); 737} 738 739IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_Close) { 740 TestHelper("testNewWindowClose", 741 "web_view/newwindow", 742 NEEDS_TEST_SERVER); 743} 744 745IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_ExecuteScript) { 746 TestHelper("testNewWindowExecuteScript", 747 "web_view/newwindow", 748 NEEDS_TEST_SERVER); 749} 750 751IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, 752 NewWindow_DeclarativeWebRequest) { 753 TestHelper("testNewWindowDeclarativeWebRequest", 754 "web_view/newwindow", 755 NEEDS_TEST_SERVER); 756} 757 758IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_WebRequest) { 759 TestHelper("testNewWindowWebRequest", 760 "web_view/newwindow", 761 NEEDS_TEST_SERVER); 762} 763 764// A custom elements bug needs to be addressed to enable this test: 765// See http://crbug.com/282477 for more information. 766IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, 767 DISABLED_NewWindow_WebRequestCloseWindow) { 768 TestHelper("testNewWindowWebRequestCloseWindow", 769 "web_view/newwindow", 770 NEEDS_TEST_SERVER); 771} 772 773IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, 774 NewWindow_WebRequestRemoveElement) { 775 TestHelper("testNewWindowWebRequestRemoveElement", 776 "web_view/newwindow", 777 NEEDS_TEST_SERVER); 778} 779 780// Tests that Ctrl+Click/Cmd+Click on a link fires up the newwindow API. 781IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_OpenInNewTab) { 782 content::WebContents* embedder_web_contents = NULL; 783 784 ExtensionTestMessageListener loaded_listener("Loaded", false); 785 scoped_ptr<ExtensionTestMessageListener> done_listener( 786 RunAppHelper("testNewWindowOpenInNewTab", 787 "web_view/newwindow", 788 NEEDS_TEST_SERVER, 789 &embedder_web_contents)); 790 791 loaded_listener.WaitUntilSatisfied(); 792#if defined(OS_MACOSX) 793 ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( 794 GetPlatformAppWindow(), ui::VKEY_RETURN, 795 false, false, false, true /* cmd */)); 796#else 797 ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( 798 GetPlatformAppWindow(), ui::VKEY_RETURN, 799 true /* ctrl */, false, false, false)); 800#endif 801 802 // Wait for the embedder to receive a 'newwindow' event. 803 ASSERT_TRUE(done_listener->WaitUntilSatisfied()); 804} 805 806 807IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, ExecuteCode) { 808 ASSERT_TRUE(RunPlatformAppTestWithArg( 809 "platform_apps/web_view/common", "execute_code")) << message_; 810} 811 812IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, PopupPositioningBasic) { 813 TestHelper("testBasic", "web_view/popup_positioning", NO_TEST_SERVER); 814 ASSERT_TRUE(guest_web_contents()); 815 PopupTestHelper(gfx::Point()); 816 817 // TODO(lazyboy): Move the embedder window to a random location and 818 // make sure we keep rendering popups correct in webview. 819} 820 821// Tests that moving browser plugin (without resize/UpdateRects) correctly 822// repositions popup. 823IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, PopupPositioningMoved) { 824 TestHelper("testMoved", "web_view/popup_positioning", NO_TEST_SERVER); 825 ASSERT_TRUE(guest_web_contents()); 826 PopupTestHelper(gfx::Point(20, 0)); 827} 828 829// Drag and drop inside a webview is currently only enabled for linux and mac, 830// but the tests don't work on anything except chromeos for now. This is because 831// of simulating mouse drag code's dependency on platforms. 832#if defined(OS_CHROMEOS) 833IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, DragDropWithinWebView) { 834 LoadAndLaunchPlatformApp("web_view/dnd_within_webview", "connected"); 835 ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow())); 836 837 embedder_web_contents_ = GetFirstAppWindowWebContents(); 838 gfx::Rect offset = embedder_web_contents_->GetContainerBounds(); 839 corner_ = gfx::Point(offset.x(), offset.y()); 840 841 // In the drag drop test we add 20px padding to the page body because on 842 // windows if we get too close to the edge of the window the resize cursor 843 // appears and we start dragging the window edge. 844 corner_.Offset(20, 20); 845 846 // Flush any pending events to make sure we start with a clean slate. 847 content::RunAllPendingInMessageLoop(); 848 for (;;) { 849 base::RunLoop run_loop; 850 quit_closure_ = run_loop.QuitClosure(); 851 base::MessageLoop::current()->PostTask( 852 FROM_HERE, 853 base::Bind(&WebViewInteractiveTest::DragTestStep1, 854 base::Unretained(this))); 855 run_loop.Run(); 856 857 if (last_drop_data_ == "Drop me") 858 break; 859 860 LOG(INFO) << "Drag was cancelled in interactive_test, restarting drag"; 861 862 // Reset state for next try. 863 ExtensionTestMessageListener reset_listener("resetStateReply", false); 864 EXPECT_TRUE(content::ExecuteScript(embedder_web_contents_, 865 "window.resetState()")); 866 ASSERT_TRUE(reset_listener.WaitUntilSatisfied()); 867 } 868 ASSERT_EQ("Drop me", last_drop_data_); 869} 870#endif // (defined(OS_CHROMEOS)) 871 872IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Navigation) { 873 TestHelper("testNavigation", "web_view/navigation", NO_TEST_SERVER); 874} 875 876IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Navigation_BackForwardKeys) { 877 LoadAndLaunchPlatformApp("web_view/navigation", "Launched"); 878 ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow( 879 GetPlatformAppWindow())); 880 // Flush any pending events to make sure we start with a clean slate. 881 content::RunAllPendingInMessageLoop(); 882 883 content::WebContents* embedder_web_contents = GetFirstAppWindowWebContents(); 884 ASSERT_TRUE(embedder_web_contents); 885 886 ExtensionTestMessageListener done_listener( 887 "TEST_PASSED", false); 888 done_listener.set_failure_message("TEST_FAILED"); 889 ExtensionTestMessageListener ready_back_key_listener( 890 "ReadyForBackKey", false); 891 ExtensionTestMessageListener ready_forward_key_listener( 892 "ReadyForForwardKey", false); 893 894 EXPECT_TRUE(content::ExecuteScript( 895 embedder_web_contents, 896 "runTest('testBackForwardKeys')")); 897 898 ASSERT_TRUE(ready_back_key_listener.WaitUntilSatisfied()); 899 SendBackShortcutToPlatformApp(); 900 901 ASSERT_TRUE(ready_forward_key_listener.WaitUntilSatisfied()); 902 SendForwardShortcutToPlatformApp(); 903 904 ASSERT_TRUE(done_listener.WaitUntilSatisfied()); 905} 906 907IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, 908 PointerLock_PointerLockLostWithFocus) { 909 TestHelper("testPointerLockLostWithFocus", 910 "web_view/pointerlock", 911 NO_TEST_SERVER); 912} 913 914// This test exercies the following scenario: 915// 1. An <input> in guest has focus. 916// 2. User takes focus to embedder by clicking e.g. an <input> in embedder. 917// 3. User brings back the focus directly to the <input> in #1. 918// 919// Now we need to make sure TextInputTypeChanged fires properly for the guest's 920// view upon step #3. We simply read the input type's state after #3 to 921// make sure it's not TEXT_INPUT_TYPE_NONE. 922IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Focus_FocusRestored) { 923 TestHelper("testFocusRestored", "web_view/focus", NO_TEST_SERVER); 924 content::WebContents* embedder_web_contents = GetFirstAppWindowWebContents(); 925 ASSERT_TRUE(embedder_web_contents); 926 ASSERT_TRUE(guest_web_contents()); 927 928 // 1) We click on the guest so that we get a focus event. 929 ExtensionTestMessageListener next_step_listener("TEST_STEP_PASSED", false); 930 next_step_listener.set_failure_message("TEST_STEP_FAILED"); 931 { 932 content::SimulateMouseClickAt(guest_web_contents(), 933 0, 934 blink::WebMouseEvent::ButtonLeft, 935 gfx::Point(10, 10)); 936 EXPECT_TRUE(content::ExecuteScript( 937 embedder_web_contents, 938 "window.runCommand('testFocusRestoredRunNextStep', 1);")); 939 } 940 // Wait for the next step to complete. 941 ASSERT_TRUE(next_step_listener.WaitUntilSatisfied()); 942 943 // 2) We click on the embedder so the guest's focus goes away and it observes 944 // a blur event. 945 next_step_listener.Reset(); 946 { 947 content::SimulateMouseClickAt(embedder_web_contents, 948 0, 949 blink::WebMouseEvent::ButtonLeft, 950 gfx::Point(200, 20)); 951 EXPECT_TRUE(content::ExecuteScript( 952 embedder_web_contents, 953 "window.runCommand('testFocusRestoredRunNextStep', 2);")); 954 } 955 // Wait for the next step to complete. 956 ASSERT_TRUE(next_step_listener.WaitUntilSatisfied()); 957 958 // 3) We click on the guest again to bring back focus directly to the previous 959 // input element, then we ensure text_input_type is properly set. 960 next_step_listener.Reset(); 961 { 962 content::SimulateMouseClickAt(guest_web_contents(), 963 0, 964 blink::WebMouseEvent::ButtonLeft, 965 gfx::Point(10, 10)); 966 EXPECT_TRUE(content::ExecuteScript( 967 embedder_web_contents, 968 "window.runCommand('testFocusRestoredRunNextStep', 3)")); 969 } 970 // Wait for the next step to complete. 971 ASSERT_TRUE(next_step_listener.WaitUntilSatisfied()); 972 973 // |text_input_client| is not available for mac and android. 974#if !defined(OS_MACOSX) && !defined(OS_ANDROID) 975 ui::TextInputClient* text_input_client = 976 embedder_web_contents->GetRenderViewHost()->GetView() 977 ->GetTextInputClient(); 978 ASSERT_TRUE(text_input_client); 979 ASSERT_TRUE(text_input_client->GetTextInputType() != 980 ui::TEXT_INPUT_TYPE_NONE); 981#endif 982} 983 984// ui::TextInputClient is NULL for mac and android. 985#if !defined(OS_MACOSX) && !defined(OS_ANDROID) 986IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Focus_InputMethod) { 987 content::WebContents* embedder_web_contents = NULL; 988 scoped_ptr<ExtensionTestMessageListener> done_listener( 989 RunAppHelper("testInputMethod", "web_view/focus", NO_TEST_SERVER, 990 &embedder_web_contents)); 991 ASSERT_TRUE(done_listener->WaitUntilSatisfied()); 992 993 ui::TextInputClient* text_input_client = 994 embedder_web_contents->GetRenderViewHost()->GetView() 995 ->GetTextInputClient(); 996 ASSERT_TRUE(text_input_client); 997 998 ExtensionTestMessageListener next_step_listener("TEST_STEP_PASSED", false); 999 next_step_listener.set_failure_message("TEST_STEP_FAILED"); 1000 1001 // An input element inside the <webview> gets focus and is given some 1002 // user input via IME. 1003 { 1004 ui::CompositionText composition; 1005 composition.text = base::UTF8ToUTF16("InputTest123"); 1006 text_input_client->SetCompositionText(composition); 1007 EXPECT_TRUE(content::ExecuteScript( 1008 embedder_web_contents, 1009 "window.runCommand('testInputMethodRunNextStep', 1);")); 1010 1011 // Wait for the next step to complete. 1012 ASSERT_TRUE(next_step_listener.WaitUntilSatisfied()); 1013 } 1014 1015 // A composition is committed via IME. 1016 { 1017 next_step_listener.Reset(); 1018 1019 ui::CompositionText composition; 1020 composition.text = base::UTF8ToUTF16("InputTest456"); 1021 text_input_client->SetCompositionText(composition); 1022 text_input_client->ConfirmCompositionText(); 1023 EXPECT_TRUE(content::ExecuteScript( 1024 embedder_web_contents, 1025 "window.runCommand('testInputMethodRunNextStep', 2);")); 1026 1027 // Wait for the next step to complete. 1028 EXPECT_TRUE(next_step_listener.WaitUntilSatisfied()); 1029 } 1030 1031 // Moving focus causes IME cancel, and the composition will be committed 1032 // in first <input> in the <webview>, not in the second <input>. 1033 { 1034 next_step_listener.Reset(); 1035 ui::CompositionText composition; 1036 composition.text = base::UTF8ToUTF16("InputTest789"); 1037 text_input_client->SetCompositionText(composition); 1038 EXPECT_TRUE(content::ExecuteScript( 1039 embedder_web_contents, 1040 "window.runCommand('testInputMethodRunNextStep', 3);")); 1041 1042 // Wait for the next step to complete. 1043 EXPECT_TRUE(next_step_listener.WaitUntilSatisfied()); 1044 } 1045 1046 // Tests ExtendSelectionAndDelete message works in <webview>. 1047 { 1048 next_step_listener.Reset(); 1049 1050 // At this point we have set focus on first <input> in the <webview>, 1051 // and the value it contains is 'InputTestABC' with caret set after 'T'. 1052 // Now we delete 'Test' in 'InputTestABC', as the caret is after 'T': 1053 // delete before 1 character ('T') and after 3 characters ('est'). 1054 text_input_client->ExtendSelectionAndDelete(1, 3); 1055 EXPECT_TRUE(content::ExecuteScript( 1056 embedder_web_contents, 1057 "window.runCommand('testInputMethodRunNextStep', 4);")); 1058 1059 // Wait for the next step to complete. 1060 EXPECT_TRUE(next_step_listener.WaitUntilSatisfied()); 1061 } 1062} 1063#endif 1064 1065#if defined(OS_MACOSX) 1066IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, TextSelection) { 1067 SetupTest("web_view/text_selection", 1068 "/extensions/platform_apps/web_view/text_selection/guest.html"); 1069 ASSERT_TRUE(guest_web_contents()); 1070 ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow( 1071 GetPlatformAppWindow())); 1072 1073 // Wait until guest sees a context menu, select an arbitrary item (copy). 1074 ExtensionTestMessageListener ctx_listener("MSG_CONTEXTMENU", false); 1075 ContextMenuNotificationObserver menu_observer(IDC_CONTENT_CONTEXT_COPY); 1076 SimulateRWHMouseClick(guest_web_contents()->GetRenderViewHost(), 1077 blink::WebMouseEvent::ButtonRight, 20, 20); 1078 ASSERT_TRUE(ctx_listener.WaitUntilSatisfied()); 1079 1080 // Now verify that the selection text propagates properly to RWHV. 1081 content::RenderWidgetHostView* guest_rwhv = 1082 guest_web_contents()->GetRenderWidgetHostView(); 1083 ASSERT_TRUE(guest_rwhv); 1084 std::string selected_text = base::UTF16ToUTF8(guest_rwhv->GetSelectedText()); 1085 ASSERT_TRUE(selected_text.size() >= 10u); 1086 ASSERT_EQ("AAAAAAAAAA", selected_text.substr(0, 10)); 1087} 1088#endif 1089