1// Copyright (c) 2012 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 "chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h" 6 7#include "base/bind.h" 8#include "base/callback.h" 9#include "base/command_line.h" 10#include "base/strings/string_number_conversions.h" 11#include "base/win/windows_version.h" 12#include "chrome/browser/chrome_notification_types.h" 13#include "chrome/browser/ui/browser.h" 14#include "chrome/browser/ui/browser_list.h" 15#include "chrome/browser/ui/browser_window.h" 16#include "chrome/browser/ui/tabs/tab_strip_model.h" 17#include "chrome/browser/ui/views/frame/browser_view.h" 18#include "chrome/browser/ui/views/tabs/tab.h" 19#include "chrome/browser/ui/views/tabs/tab_drag_controller.h" 20#include "chrome/browser/ui/views/tabs/tab_strip.h" 21#include "chrome/common/chrome_switches.h" 22#include "chrome/test/base/in_process_browser_test.h" 23#include "chrome/test/base/interactive_test_utils.h" 24#include "chrome/test/base/ui_test_utils.h" 25#include "content/public/browser/notification_details.h" 26#include "content/public/browser/notification_observer.h" 27#include "content/public/browser/notification_service.h" 28#include "content/public/browser/notification_source.h" 29#include "content/public/browser/web_contents.h" 30#include "ui/base/test/ui_controls.h" 31#include "ui/gfx/screen.h" 32#include "ui/views/controls/textfield/textfield.h" 33#include "ui/views/view.h" 34#include "ui/views/widget/widget.h" 35 36using content::WebContents; 37using test::GetCenterInScreenCoordinates; 38using test::GetTabStripForBrowser; 39using test::IDString; 40using test::ResetIDs; 41using test::SetID; 42 43// The tests in this file exercise detaching the dragged tab into a standalone 44// window (not a Browser). They are not applicable to aura as aura forces real 45// window dragging. 46 47// Creates a browser with two tabs, drags the second to the first. 48IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DragInSameWindow) { 49 AddTabAndResetBrowser(browser()); 50 51 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 52 TabStripModel* model = browser()->tab_strip_model(); 53 54 gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1))); 55 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_1_center)); 56 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 57 ui_controls::LEFT, ui_controls::DOWN)); 58 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 59 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); 60 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 61 ui_controls::LEFT, ui_controls::UP)); 62 EXPECT_EQ("1 0", IDString(model)); 63 EXPECT_FALSE(TabDragController::IsActive()); 64 EXPECT_FALSE(tab_strip->IsDragSessionActive()); 65} 66 67// Creates two browsers, drags from first into second. 68// This test often crashes on Vista <http://crbug.com/156787> 69#if defined(OS_WIN) 70#define MAYBE_DragToSeparateWindow DISABLED_DragToSeparateWindow 71#else 72#define MAYBE_DragToSeparateWindow DragToSeparateWindow 73#endif 74IN_PROC_BROWSER_TEST_F(TabDragControllerTest, MAYBE_DragToSeparateWindow) { 75 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 76 77 // Add another tab to browser(). 78 AddTabAndResetBrowser(browser()); 79 80 // Create another browser. 81 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout(); 82 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); 83 84 // Move to the first tab and drag it enough so that it detaches, but not 85 // enough that it attaches to browser2. 86 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 87 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); 88 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 89 ui_controls::LEFT, ui_controls::DOWN)); 90 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( 91 gfx::Point(tab_0_center.x(), 92 tab_0_center.y() + tab_strip->height() + 20))); 93 ASSERT_TRUE(TabDragController::IsActive()); 94 95 // Drag into the second browser. 96 gfx::Point target_point(tab_strip2->width() -1, tab_strip2->height() / 2); 97 views::View::ConvertPointToScreen(tab_strip2, &target_point); 98 ASSERT_TRUE(ui_controls::SendMouseMove(target_point.x(), target_point.y())); 99 100 ASSERT_TRUE(TabDragController::IsActive()); 101 102 // Release the mouse, ending the drag session. 103 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 104 ui_controls::LEFT, ui_controls::UP)); 105 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 106 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 107 ASSERT_FALSE(TabDragController::IsActive()); 108 EXPECT_EQ("100 0", IDString(browser2->tab_strip_model())); 109 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 110} 111 112// Drags from browser to separate window and releases mouse. 113IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DetachToOwnWindow) { 114 // Add another tab. 115 AddTabAndResetBrowser(browser()); 116 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 117 118 // Move to the first tab and drag it enough so that it detaches. 119 gfx::Point tab_0_center( 120 GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 121 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); 122 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 123 ui_controls::LEFT, ui_controls::DOWN)); 124 ASSERT_TRUE(ui_controls::SendMouseMove( 125 tab_0_center.x(), tab_0_center.y() + tab_strip->height() + 20)); 126 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 127 ui_controls::LEFT, ui_controls::UP)); 128 129 // Should no longer be dragging. 130 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 131 ASSERT_FALSE(TabDragController::IsActive()); 132 133 // There should now be another browser. 134 ASSERT_EQ(2u, native_browser_list->size()); 135 Browser* new_browser = native_browser_list->get(1); 136 ASSERT_TRUE(new_browser->window()->IsActive()); 137 TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser); 138 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 139 140 EXPECT_EQ("0", IDString(new_browser->tab_strip_model())); 141 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 142} 143 144// Deletes a tab being dragged before the user moved enough to start a drag. 145IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DeleteBeforeStartedDragging) { 146 // Add another tab. 147 AddTabAndResetBrowser(browser()); 148 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 149 150 // Click on the first tab, but don't move it. 151 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 152 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); 153 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 154 ui_controls::LEFT, ui_controls::DOWN)); 155 156 // Should be dragging. 157 ASSERT_TRUE(tab_strip->IsDragSessionActive()); 158 ASSERT_TRUE(TabDragController::IsActive()); 159 160 // Delete the tab being dragged. 161 delete browser()->tab_strip_model()->GetWebContentsAt(0); 162 163 // Should have canceled dragging. 164 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 165 ASSERT_FALSE(TabDragController::IsActive()); 166 167 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 168} 169 170// Deletes a tab being dragged while still attached. 171IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DeleteTabWhileAttached) { 172 // Add another tab. 173 AddTabAndResetBrowser(browser()); 174 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 175 176 // Click on the first tab and move it enough so that it starts dragging but is 177 // still attached. 178 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 179 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); 180 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 181 ui_controls::LEFT, ui_controls::DOWN)); 182 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( 183 gfx::Point(tab_0_center.x() + 20, tab_0_center.y()))); 184 185 // Should be dragging. 186 ASSERT_TRUE(tab_strip->IsDragSessionActive()); 187 ASSERT_TRUE(TabDragController::IsActive()); 188 189 // Delete the tab being dragged. 190 delete browser()->tab_strip_model()->GetWebContentsAt(0); 191 192 // Should have canceled dragging. 193 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 194 ASSERT_FALSE(TabDragController::IsActive()); 195 196 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 197} 198 199// Deletes a tab being dragged after dragging a tab so that a new window is 200// created. 201IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DeleteTabWhileDetached) { 202 // Add another tab. 203 AddTabAndResetBrowser(browser()); 204 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 205 206 // Move to the first tab and drag it enough so that it detaches. 207 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 208 WebContents* to_delete = browser()->tab_strip_model()->GetWebContentsAt(0); 209 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); 210 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 211 ui_controls::LEFT, ui_controls::DOWN)); 212 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( 213 gfx::Point(tab_0_center.x(), 214 tab_0_center.y() + tab_strip->height() + 20))); 215 delete to_delete; 216 217 // Should not be dragging. 218 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 219 ASSERT_FALSE(TabDragController::IsActive()); 220 221 EXPECT_EQ("1", IDString(browser()->tab_strip_model())); 222} 223 224// Detaches a tab and while detached deletes a tab from the source and releases 225// the mouse. 226IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DeleteSourceDetached) { 227 // Add another tab. 228 AddTabAndResetBrowser(browser()); 229 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 230 231 // Move to the first tab and drag it enough so that it detaches. 232 gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 233 WebContents* to_delete = browser()->tab_strip_model()->GetWebContentsAt(1); 234 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); 235 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 236 ui_controls::LEFT, ui_controls::DOWN)); 237 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( 238 gfx::Point(tab_0_center.x(), 239 tab_0_center.y() + tab_strip->height() + 20))); 240 delete to_delete; 241 242 // Should still be dragging. 243 ASSERT_TRUE(tab_strip->IsDragSessionActive()); 244 ASSERT_TRUE(TabDragController::IsActive()); 245 246 // Release the mouse. 247 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 248 ui_controls::LEFT, ui_controls::UP)); 249 250 // Releasing the mouse should destroy the existing browser and create a new 251 // one. 252 ASSERT_EQ(1u, native_browser_list->size()); 253 Browser* new_browser = native_browser_list->get(0); 254 EXPECT_NE(new_browser, browser()); 255 256 ASSERT_FALSE(GetTabStripForBrowser(new_browser)->IsDragSessionActive()); 257 ASSERT_FALSE(TabDragController::IsActive()); 258 259 EXPECT_EQ("0", IDString(new_browser->tab_strip_model())); 260} 261 262// Creates two browsers, selects all tabs in first and drags into second. 263IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DragAllToSeparateWindow) { 264 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 265 266 // Add another tab to browser(). 267 AddTabAndResetBrowser(browser()); 268 269 // Create another browser. 270 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout(); 271 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); 272 273 browser()->tab_strip_model()->AddTabAtToSelection(0); 274 browser()->tab_strip_model()->AddTabAtToSelection(1); 275 276 // Move to the first tab and drag it enough so that it detaches, but not 277 // enough that it attaches to browser2. 278 gfx::Point tab_0_center( 279 GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 280 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); 281 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 282 ui_controls::LEFT, ui_controls::DOWN)); 283 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( 284 gfx::Point(tab_0_center.x(), 285 tab_0_center.y() + tab_strip->height() + 20))); 286 287 ASSERT_TRUE(tab_strip->IsDragSessionActive()); 288 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 289 ASSERT_TRUE(TabDragController::IsActive()); 290 ASSERT_EQ(2u, native_browser_list->size()); 291 292 // Drag to tab_strip2. 293 gfx::Point target_point(tab_strip2->width() - 1, 294 tab_strip2->height() / 2); 295 views::View::ConvertPointToScreen(tab_strip2, &target_point); 296 ASSERT_TRUE(ui_controls::SendMouseMove(target_point.x(), target_point.y())); 297 298 // Should now be attached to tab_strip2. 299 ASSERT_TRUE(tab_strip->IsDragSessionActive()); 300 ASSERT_TRUE(TabDragController::IsActive()); 301 302 // Release the mouse, stopping the drag session. 303 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 304 ui_controls::LEFT, ui_controls::UP)); 305 ASSERT_FALSE(TabDragController::IsActive()); 306 EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model())); 307} 308 309// Creates two browsers, selects all tabs in first, drags into second, then hits 310// escape. 311IN_PROC_BROWSER_TEST_F(TabDragControllerTest, 312 DragAllToSeparateWindowAndCancel) { 313 TabStrip* tab_strip = GetTabStripForBrowser(browser()); 314 315 // Add another tab to browser(). 316 AddTabAndResetBrowser(browser()); 317 318 // Create another browser. 319 Browser* browser2 = CreateAnotherWindowBrowserAndRelayout(); 320 TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); 321 322 browser()->tab_strip_model()->AddTabAtToSelection(0); 323 browser()->tab_strip_model()->AddTabAtToSelection(1); 324 325 // Move to the first tab and drag it enough so that it detaches, but not 326 // enough that it attaches to browser2. 327 gfx::Point tab_0_center( 328 GetCenterInScreenCoordinates(tab_strip->tab_at(0))); 329 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); 330 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( 331 ui_controls::LEFT, ui_controls::DOWN)); 332 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( 333 gfx::Point(tab_0_center.x(), 334 tab_0_center.y() + tab_strip->height() + 20))); 335 ASSERT_TRUE(tab_strip->IsDragSessionActive()); 336 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 337 ASSERT_TRUE(TabDragController::IsActive()); 338 ASSERT_EQ(2u, native_browser_list->size()); 339 340 // Drag to tab_strip2. 341 gfx::Point target_point(tab_strip2->width() - 1, 342 tab_strip2->height() / 2); 343 views::View::ConvertPointToScreen(tab_strip2, &target_point); 344 ASSERT_TRUE(ui_controls::SendMouseMove(target_point.x(), target_point.y())); 345 346 ASSERT_TRUE(tab_strip->IsDragSessionActive()); 347 ASSERT_TRUE(TabDragController::IsActive()); 348 ASSERT_EQ(2u, native_browser_list->size()); 349 350 // Cancel the drag. 351 // TODO(msw): Fix this on "XP Tests (1)"; see http://crbug.com/227444 352 if (base::win::GetVersion() == base::win::VERSION_XP) { 353 LOG(INFO) << "Try SendKeyPressToWindowSync [esc]; maybe this works???"; 354 ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( 355 browser2->window()->GetNativeWindow(), ui::VKEY_ESCAPE, 356 false, false, false, false)); 357 LOG(INFO) << "Tab strip 1 drag active (expect 0): " 358 << tab_strip->IsDragSessionActive(); 359 LOG(INFO) << "Tab strip 2 drag active (expect 0): " 360 << tab_strip2->IsDragSessionActive(); 361 LOG(INFO) << "Tab drag controller active (expect 0): " 362 << TabDragController::IsActive(); 363 LOG(INFO) << "Native browser list size (expect 2): " 364 << native_browser_list->size(); 365 LOG(INFO) << "Tab strip 1 model string (expect '0 1'): " 366 << IDString(browser()->tab_strip_model()); 367 LOG(INFO) << "Tab strip 2 model string (expect '100'): " 368 << IDString(browser2->tab_strip_model()); 369 370 LOG(INFO) << "Try SendKeyPressSync [esc]; is this needed???"; 371 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 372 browser2, ui::VKEY_ESCAPE, false, false, false, false)); 373 LOG(INFO) << "Tab strip 1 drag active (expect 0): " 374 << tab_strip->IsDragSessionActive(); 375 LOG(INFO) << "Tab strip 2 drag active (expect 0): " 376 << tab_strip2->IsDragSessionActive(); 377 LOG(INFO) << "Tab drag controller active (expect 0): " 378 << TabDragController::IsActive(); 379 LOG(INFO) << "Native browser list size (expect 2): " 380 << native_browser_list->size(); 381 LOG(INFO) << "Tab strip 1 model string (expect '0 1'): " 382 << IDString(browser()->tab_strip_model()); 383 LOG(INFO) << "Tab strip 2 model string (expect '100'): " 384 << IDString(browser2->tab_strip_model()); 385 } else { 386 ASSERT_TRUE(ui_test_utils::SendKeyPressSync( 387 browser2, ui::VKEY_ESCAPE, false, false, false, false)); 388 ASSERT_FALSE(tab_strip->IsDragSessionActive()); 389 ASSERT_FALSE(tab_strip2->IsDragSessionActive()); 390 ASSERT_FALSE(TabDragController::IsActive()); 391 ASSERT_EQ(2u, native_browser_list->size()); 392 EXPECT_EQ("0 1", IDString(browser()->tab_strip_model())); 393 EXPECT_EQ("100", IDString(browser2->tab_strip_model())); 394 } 395} 396