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.
5 #include "chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.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"
36 using content::WebContents
;
37 using test::GetCenterInScreenCoordinates
;
38 using test::GetTabStripForBrowser
;
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
47 // Creates a browser with two tabs, drags the second to the first.
48 IN_PROC_BROWSER_TEST_F(TabDragControllerTest
, DragInSameWindow
) {
49 AddTabAndResetBrowser(browser());
51 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
52 TabStripModel
* model
= browser()->tab_strip_model();
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());
67 // Creates two browsers, drags from first into second.
68 // This test often crashes on Vista <http://crbug.com/156787>
70 #define MAYBE_DragToSeparateWindow DISABLED_DragToSeparateWindow
72 #define MAYBE_DragToSeparateWindow DragToSeparateWindow
74 IN_PROC_BROWSER_TEST_F(TabDragControllerTest
, MAYBE_DragToSeparateWindow
) {
75 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
77 // Add another tab to browser().
78 AddTabAndResetBrowser(browser());
80 // Create another browser.
81 Browser
* browser2
= CreateAnotherWindowBrowserAndRelayout();
82 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
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());
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()));
100 ASSERT_TRUE(TabDragController::IsActive());
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()));
112 // Drags from browser to separate window and releases mouse.
113 IN_PROC_BROWSER_TEST_F(TabDragControllerTest
, DetachToOwnWindow
) {
115 AddTabAndResetBrowser(browser());
116 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
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
));
129 // Should no longer be dragging.
130 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
131 ASSERT_FALSE(TabDragController::IsActive());
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());
140 EXPECT_EQ("0", IDString(new_browser
->tab_strip_model()));
141 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
144 // Deletes a tab being dragged before the user moved enough to start a drag.
145 IN_PROC_BROWSER_TEST_F(TabDragControllerTest
, DeleteBeforeStartedDragging
) {
147 AddTabAndResetBrowser(browser());
148 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
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
));
156 // Should be dragging.
157 ASSERT_TRUE(tab_strip
->IsDragSessionActive());
158 ASSERT_TRUE(TabDragController::IsActive());
160 // Delete the tab being dragged.
161 delete browser()->tab_strip_model()->GetWebContentsAt(0);
163 // Should have canceled dragging.
164 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
165 ASSERT_FALSE(TabDragController::IsActive());
167 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
170 // Deletes a tab being dragged while still attached.
171 IN_PROC_BROWSER_TEST_F(TabDragControllerTest
, DeleteTabWhileAttached
) {
173 AddTabAndResetBrowser(browser());
174 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
176 // Click on the first tab and move it enough so that it starts dragging but is
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())));
185 // Should be dragging.
186 ASSERT_TRUE(tab_strip
->IsDragSessionActive());
187 ASSERT_TRUE(TabDragController::IsActive());
189 // Delete the tab being dragged.
190 delete browser()->tab_strip_model()->GetWebContentsAt(0);
192 // Should have canceled dragging.
193 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
194 ASSERT_FALSE(TabDragController::IsActive());
196 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
199 // Deletes a tab being dragged after dragging a tab so that a new window is
201 IN_PROC_BROWSER_TEST_F(TabDragControllerTest
, DeleteTabWhileDetached
) {
203 AddTabAndResetBrowser(browser());
204 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
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)));
217 // Should not be dragging.
218 ASSERT_FALSE(tab_strip
->IsDragSessionActive());
219 ASSERT_FALSE(TabDragController::IsActive());
221 EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
224 // Detaches a tab and while detached deletes a tab from the source and releases
226 IN_PROC_BROWSER_TEST_F(TabDragControllerTest
, DeleteSourceDetached
) {
228 AddTabAndResetBrowser(browser());
229 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
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)));
242 // Should still be dragging.
243 ASSERT_TRUE(tab_strip
->IsDragSessionActive());
244 ASSERT_TRUE(TabDragController::IsActive());
246 // Release the mouse.
247 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
248 ui_controls::LEFT
, ui_controls::UP
));
250 // Releasing the mouse should destroy the existing browser and create a new
252 ASSERT_EQ(1u, native_browser_list
->size());
253 Browser
* new_browser
= native_browser_list
->get(0);
254 EXPECT_NE(new_browser
, browser());
256 ASSERT_FALSE(GetTabStripForBrowser(new_browser
)->IsDragSessionActive());
257 ASSERT_FALSE(TabDragController::IsActive());
259 EXPECT_EQ("0", IDString(new_browser
->tab_strip_model()));
262 // Creates two browsers, selects all tabs in first and drags into second.
263 IN_PROC_BROWSER_TEST_F(TabDragControllerTest
, DragAllToSeparateWindow
) {
264 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
266 // Add another tab to browser().
267 AddTabAndResetBrowser(browser());
269 // Create another browser.
270 Browser
* browser2
= CreateAnotherWindowBrowserAndRelayout();
271 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
273 browser()->tab_strip_model()->AddTabAtToSelection(0);
274 browser()->tab_strip_model()->AddTabAtToSelection(1);
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)));
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());
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()));
298 // Should now be attached to tab_strip2.
299 ASSERT_TRUE(tab_strip
->IsDragSessionActive());
300 ASSERT_TRUE(TabDragController::IsActive());
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()));
309 // Creates two browsers, selects all tabs in first, drags into second, then hits
311 IN_PROC_BROWSER_TEST_F(TabDragControllerTest
,
312 DragAllToSeparateWindowAndCancel
) {
313 TabStrip
* tab_strip
= GetTabStripForBrowser(browser());
315 // Add another tab to browser().
316 AddTabAndResetBrowser(browser());
318 // Create another browser.
319 Browser
* browser2
= CreateAnotherWindowBrowserAndRelayout();
320 TabStrip
* tab_strip2
= GetTabStripForBrowser(browser2
);
322 browser()->tab_strip_model()->AddTabAtToSelection(0);
323 browser()->tab_strip_model()->AddTabAtToSelection(1);
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());
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()));
346 ASSERT_TRUE(tab_strip
->IsDragSessionActive());
347 ASSERT_TRUE(TabDragController::IsActive());
348 ASSERT_EQ(2u, native_browser_list
->size());
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());
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());
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()));