• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 using content::WebContents;
37 using test::GetCenterInScreenCoordinates;
38 using test::GetTabStripForBrowser;
39 using test::IDString;
40 using test::ResetIDs;
41 using 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.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest,DragInSameWindow)48 IN_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
IN_PROC_BROWSER_TEST_F(TabDragControllerTest,MAYBE_DragToSeparateWindow)74 IN_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.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest,DetachToOwnWindow)113 IN_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.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest,DeleteBeforeStartedDragging)145 IN_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.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest,DeleteTabWhileAttached)171 IN_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.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest,DeleteTabWhileDetached)201 IN_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.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest,DeleteSourceDetached)226 IN_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.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest,DragAllToSeparateWindow)263 IN_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.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest,DragAllToSeparateWindowAndCancel)311 IN_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