blob: 5263b7d639530d2b92584c9a2a650ce329572bce [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "base/win/windows_version.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/tabs/tab.h"
#include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/test/ui_controls.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
using content::WebContents;
using test::GetCenterInScreenCoordinates;
using test::GetTabStripForBrowser;
using test::IDString;
using test::ResetIDs;
using test::SetID;
// The tests in this file exercise detaching the dragged tab into a standalone
// window (not a Browser). They are not applicable to aura as aura forces real
// window dragging.
// Creates a browser with two tabs, drags the second to the first.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DragInSameWindow) {
AddTabAndResetBrowser(browser());
TabStrip* tab_strip = GetTabStripForBrowser(browser());
TabStripModel* model = browser()->tab_strip_model();
gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_1_center));
ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
ui_controls::LEFT, ui_controls::DOWN));
gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center));
ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
ui_controls::LEFT, ui_controls::UP));
EXPECT_EQ("1 0", IDString(model));
EXPECT_FALSE(TabDragController::IsActive());
EXPECT_FALSE(tab_strip->IsDragSessionActive());
}
// Creates two browsers, drags from first into second.
// This test often crashes on Vista <http://crbug.com/156787>
#if defined(OS_WIN)
#define MAYBE_DragToSeparateWindow DISABLED_DragToSeparateWindow
#else
#define MAYBE_DragToSeparateWindow DragToSeparateWindow
#endif
IN_PROC_BROWSER_TEST_F(TabDragControllerTest, MAYBE_DragToSeparateWindow) {
TabStrip* tab_strip = GetTabStripForBrowser(browser());
// Add another tab to browser().
AddTabAndResetBrowser(browser());
// Create another browser.
Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
// Move to the first tab and drag it enough so that it detaches, but not
// enough that it attaches to browser2.
gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center));
ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
ui_controls::LEFT, ui_controls::DOWN));
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
gfx::Point(tab_0_center.x(),
tab_0_center.y() + tab_strip->height() + 20)));
ASSERT_TRUE(TabDragController::IsActive());
// Drag into the second browser.
gfx::Point target_point(tab_strip2->width() -1, tab_strip2->height() / 2);
views::View::ConvertPointToScreen(tab_strip2, &target_point);
ASSERT_TRUE(ui_controls::SendMouseMove(target_point.x(), target_point.y()));
ASSERT_TRUE(TabDragController::IsActive());
// Release the mouse, ending the drag session.
ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
ui_controls::LEFT, ui_controls::UP));
ASSERT_FALSE(tab_strip2->IsDragSessionActive());
ASSERT_FALSE(tab_strip->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_EQ("100 0", IDString(browser2->tab_strip_model()));
EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
}
// Drags from browser to separate window and releases mouse.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DetachToOwnWindow) {
// Add another tab.
AddTabAndResetBrowser(browser());
TabStrip* tab_strip = GetTabStripForBrowser(browser());
// Move to the first tab and drag it enough so that it detaches.
gfx::Point tab_0_center(
GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center));
ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
ui_controls::LEFT, ui_controls::DOWN));
ASSERT_TRUE(ui_controls::SendMouseMove(
tab_0_center.x(), tab_0_center.y() + tab_strip->height() + 20));
ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
ui_controls::LEFT, ui_controls::UP));
// Should no longer be dragging.
ASSERT_FALSE(tab_strip->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
// There should now be another browser.
ASSERT_EQ(2u, native_browser_list->size());
Browser* new_browser = native_browser_list->get(1);
ASSERT_TRUE(new_browser->window()->IsActive());
TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
ASSERT_FALSE(tab_strip2->IsDragSessionActive());
EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
}
// Deletes a tab being dragged before the user moved enough to start a drag.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DeleteBeforeStartedDragging) {
// Add another tab.
AddTabAndResetBrowser(browser());
TabStrip* tab_strip = GetTabStripForBrowser(browser());
// Click on the first tab, but don't move it.
gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center));
ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
ui_controls::LEFT, ui_controls::DOWN));
// Should be dragging.
ASSERT_TRUE(tab_strip->IsDragSessionActive());
ASSERT_TRUE(TabDragController::IsActive());
// Delete the tab being dragged.
delete browser()->tab_strip_model()->GetWebContentsAt(0);
// Should have canceled dragging.
ASSERT_FALSE(tab_strip->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
}
// Deletes a tab being dragged while still attached.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DeleteTabWhileAttached) {
// Add another tab.
AddTabAndResetBrowser(browser());
TabStrip* tab_strip = GetTabStripForBrowser(browser());
// Click on the first tab and move it enough so that it starts dragging but is
// still attached.
gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center));
ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
ui_controls::LEFT, ui_controls::DOWN));
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
gfx::Point(tab_0_center.x() + 20, tab_0_center.y())));
// Should be dragging.
ASSERT_TRUE(tab_strip->IsDragSessionActive());
ASSERT_TRUE(TabDragController::IsActive());
// Delete the tab being dragged.
delete browser()->tab_strip_model()->GetWebContentsAt(0);
// Should have canceled dragging.
ASSERT_FALSE(tab_strip->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
}
// Deletes a tab being dragged after dragging a tab so that a new window is
// created.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DeleteTabWhileDetached) {
// Add another tab.
AddTabAndResetBrowser(browser());
TabStrip* tab_strip = GetTabStripForBrowser(browser());
// Move to the first tab and drag it enough so that it detaches.
gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
WebContents* to_delete = browser()->tab_strip_model()->GetWebContentsAt(0);
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center));
ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
ui_controls::LEFT, ui_controls::DOWN));
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
gfx::Point(tab_0_center.x(),
tab_0_center.y() + tab_strip->height() + 20)));
delete to_delete;
// Should not be dragging.
ASSERT_FALSE(tab_strip->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
}
// Detaches a tab and while detached deletes a tab from the source and releases
// the mouse.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DeleteSourceDetached) {
// Add another tab.
AddTabAndResetBrowser(browser());
TabStrip* tab_strip = GetTabStripForBrowser(browser());
// Move to the first tab and drag it enough so that it detaches.
gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
WebContents* to_delete = browser()->tab_strip_model()->GetWebContentsAt(1);
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center));
ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
ui_controls::LEFT, ui_controls::DOWN));
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
gfx::Point(tab_0_center.x(),
tab_0_center.y() + tab_strip->height() + 20)));
delete to_delete;
// Should still be dragging.
ASSERT_TRUE(tab_strip->IsDragSessionActive());
ASSERT_TRUE(TabDragController::IsActive());
// Release the mouse.
ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
ui_controls::LEFT, ui_controls::UP));
// Releasing the mouse should destroy the existing browser and create a new
// one.
ASSERT_EQ(1u, native_browser_list->size());
Browser* new_browser = native_browser_list->get(0);
EXPECT_NE(new_browser, browser());
ASSERT_FALSE(GetTabStripForBrowser(new_browser)->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
}
// Creates two browsers, selects all tabs in first and drags into second.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DragAllToSeparateWindow) {
TabStrip* tab_strip = GetTabStripForBrowser(browser());
// Add another tab to browser().
AddTabAndResetBrowser(browser());
// Create another browser.
Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
browser()->tab_strip_model()->AddTabAtToSelection(0);
browser()->tab_strip_model()->AddTabAtToSelection(1);
// Move to the first tab and drag it enough so that it detaches, but not
// enough that it attaches to browser2.
gfx::Point tab_0_center(
GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center));
ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
ui_controls::LEFT, ui_controls::DOWN));
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
gfx::Point(tab_0_center.x(),
tab_0_center.y() + tab_strip->height() + 20)));
ASSERT_TRUE(tab_strip->IsDragSessionActive());
ASSERT_FALSE(tab_strip2->IsDragSessionActive());
ASSERT_TRUE(TabDragController::IsActive());
ASSERT_EQ(2u, native_browser_list->size());
// Drag to tab_strip2.
gfx::Point target_point(tab_strip2->width() - 1,
tab_strip2->height() / 2);
views::View::ConvertPointToScreen(tab_strip2, &target_point);
ASSERT_TRUE(ui_controls::SendMouseMove(target_point.x(), target_point.y()));
// Should now be attached to tab_strip2.
ASSERT_TRUE(tab_strip->IsDragSessionActive());
ASSERT_TRUE(TabDragController::IsActive());
// Release the mouse, stopping the drag session.
ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
ui_controls::LEFT, ui_controls::UP));
ASSERT_FALSE(TabDragController::IsActive());
EXPECT_EQ("100 0 1", IDString(browser2->tab_strip_model()));
}
// Creates two browsers, selects all tabs in first, drags into second, then hits
// escape.
IN_PROC_BROWSER_TEST_F(TabDragControllerTest,
DragAllToSeparateWindowAndCancel) {
TabStrip* tab_strip = GetTabStripForBrowser(browser());
// Add another tab to browser().
AddTabAndResetBrowser(browser());
// Create another browser.
Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
browser()->tab_strip_model()->AddTabAtToSelection(0);
browser()->tab_strip_model()->AddTabAtToSelection(1);
// Move to the first tab and drag it enough so that it detaches, but not
// enough that it attaches to browser2.
gfx::Point tab_0_center(
GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center));
ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(
ui_controls::LEFT, ui_controls::DOWN));
ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
gfx::Point(tab_0_center.x(),
tab_0_center.y() + tab_strip->height() + 20)));
ASSERT_TRUE(tab_strip->IsDragSessionActive());
ASSERT_FALSE(tab_strip2->IsDragSessionActive());
ASSERT_TRUE(TabDragController::IsActive());
ASSERT_EQ(2u, native_browser_list->size());
// Drag to tab_strip2.
gfx::Point target_point(tab_strip2->width() - 1,
tab_strip2->height() / 2);
views::View::ConvertPointToScreen(tab_strip2, &target_point);
ASSERT_TRUE(ui_controls::SendMouseMove(target_point.x(), target_point.y()));
ASSERT_TRUE(tab_strip->IsDragSessionActive());
ASSERT_TRUE(TabDragController::IsActive());
ASSERT_EQ(2u, native_browser_list->size());
// Cancel the drag.
// TODO(msw): Fix this on "XP Tests (1)"; see http://crbug.com/227444
if (base::win::GetVersion() == base::win::VERSION_XP &&
views::Textfield::IsViewsTextfieldEnabled()) {
LOG(INFO) << "Try SendKeyPressToWindowSync [esc]; maybe this works???";
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
browser2->window()->GetNativeWindow(), ui::VKEY_ESCAPE,
false, false, false, false));
LOG(INFO) << "Tab strip 1 drag active (expect 0): "
<< tab_strip->IsDragSessionActive();
LOG(INFO) << "Tab strip 2 drag active (expect 0): "
<< tab_strip2->IsDragSessionActive();
LOG(INFO) << "Tab drag controller active (expect 0): "
<< TabDragController::IsActive();
LOG(INFO) << "Native browser list size (expect 2): "
<< native_browser_list->size();
LOG(INFO) << "Tab strip 1 model string (expect '0 1'): "
<< IDString(browser()->tab_strip_model());
LOG(INFO) << "Tab strip 2 model string (expect '100'): "
<< IDString(browser2->tab_strip_model());
LOG(INFO) << "Try SendKeyPressSync [esc]; is this needed???";
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser2, ui::VKEY_ESCAPE, false, false, false, false));
LOG(INFO) << "Tab strip 1 drag active (expect 0): "
<< tab_strip->IsDragSessionActive();
LOG(INFO) << "Tab strip 2 drag active (expect 0): "
<< tab_strip2->IsDragSessionActive();
LOG(INFO) << "Tab drag controller active (expect 0): "
<< TabDragController::IsActive();
LOG(INFO) << "Native browser list size (expect 2): "
<< native_browser_list->size();
LOG(INFO) << "Tab strip 1 model string (expect '0 1'): "
<< IDString(browser()->tab_strip_model());
LOG(INFO) << "Tab strip 2 model string (expect '100'): "
<< IDString(browser2->tab_strip_model());
} else {
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser2, ui::VKEY_ESCAPE, false, false, false, false));
ASSERT_FALSE(tab_strip->IsDragSessionActive());
ASSERT_FALSE(tab_strip2->IsDragSessionActive());
ASSERT_FALSE(TabDragController::IsActive());
ASSERT_EQ(2u, native_browser_list->size());
EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
EXPECT_EQ("100", IDString(browser2->tab_strip_model()));
}
}