Commit 3e66e1af authored by myid.shin's avatar myid.shin Committed by Commit bot

Add a test for the mouseleave event on window.

When opening the new window, it is opened on the current
window. Even though the mouse position is not updated, the
mouse leave event should be triggered on the previous
window. However, when showing the context menu or the popup,
the mouse leave event shouldn't be triggered.

The test checks if the mouseleave event is triggered when
showing the UI.

BUG=450631
R=pkotwicz@chromium.org

Review URL: https://codereview.chromium.org/891213002

Cr-Commit-Position: refs/heads/master@{#321280}
parent 4ae512e3
...@@ -4,11 +4,17 @@ ...@@ -4,11 +4,17 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu_browsertest_util.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/ui_test_utils.h"
#include "components/app_modal/app_modal_dialog.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h" #include "content/public/test/browser_test_utils.h"
#include "ui/base/test/ui_controls.h" #include "ui/base/test/ui_controls.h"
...@@ -19,24 +25,19 @@ class MouseLeaveTest : public InProcessBrowserTest { ...@@ -19,24 +25,19 @@ class MouseLeaveTest : public InProcessBrowserTest {
public: public:
MouseLeaveTest() {} MouseLeaveTest() {}
void MouseLeaveTestCommon() { void LoadTestPageAndWaitForMouseOver(content::WebContents* tab) {
gfx::Rect tab_view_bounds = tab->GetContainerBounds();
GURL test_url = ui_test_utils::GetTestUrl( GURL test_url = ui_test_utils::GetTestUrl(
base::FilePath(), base::FilePath(FILE_PATH_LITERAL("mouseleave.html"))); base::FilePath(), base::FilePath(FILE_PATH_LITERAL("mouseleave.html")));
content::WebContents* tab = gfx::Point in_content(tab_view_bounds.x() + tab_view_bounds.width() / 2,
browser()->tab_strip_model()->GetActiveWebContents(); tab_view_bounds.y() + 10);
gfx::Rect tab_view_bounds = tab->GetContainerBounds(); out_of_content_ =
gfx::Point(tab_view_bounds.x() + tab_view_bounds.width() / 2,
gfx::Point in_content_point( tab_view_bounds.y() - 2);
tab_view_bounds.x() + tab_view_bounds.width() / 2,
tab_view_bounds.y() + 10);
gfx::Point above_content_point(
tab_view_bounds.x() + tab_view_bounds.width() / 2,
tab_view_bounds.y() - 2);
// Start by moving the point just above the content. // Start by moving the point just above the content.
ui_controls::SendMouseMove(above_content_point.x(), ui_controls::SendMouseMove(out_of_content_.x(), out_of_content_.y());
above_content_point.y());
// Navigate to the test html page. // Navigate to the test html page.
base::string16 load_expected_title(base::ASCIIToUTF16("onload")); base::string16 load_expected_title(base::ASCIIToUTF16("onload"));
...@@ -46,19 +47,25 @@ class MouseLeaveTest : public InProcessBrowserTest { ...@@ -46,19 +47,25 @@ class MouseLeaveTest : public InProcessBrowserTest {
// next part of the test. // next part of the test.
EXPECT_EQ(load_expected_title, load_title_watcher.WaitAndGetTitle()); EXPECT_EQ(load_expected_title, load_title_watcher.WaitAndGetTitle());
// Move the cursor to the top-center of the content, which will trigger // Move the cursor to the top-center of the content which will trigger
// a javascript onMouseOver event. // a javascript onMouseOver event.
ui_controls::SendMouseMove(in_content_point.x(), in_content_point.y()); ui_controls::SendMouseMove(in_content.x(), in_content.y());
// Wait on the correct intermediate title. // Wait on the correct intermediate title.
base::string16 entered_expected_title(base::ASCIIToUTF16("entered")); base::string16 entered_expected_title(base::ASCIIToUTF16("entered"));
content::TitleWatcher entered_title_watcher(tab, entered_expected_title); content::TitleWatcher entered_title_watcher(tab, entered_expected_title);
EXPECT_EQ(entered_expected_title, entered_title_watcher.WaitAndGetTitle()); EXPECT_EQ(entered_expected_title, entered_title_watcher.WaitAndGetTitle());
}
void MouseLeaveTestCommon() {
content::WebContents* tab =
browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_NO_FATAL_FAILURE(LoadTestPageAndWaitForMouseOver(tab));
// Move the cursor above the content again, which should trigger // Move the cursor above the content again, which should trigger
// a javascript onMouseOut event. // a javascript onMouseOut event.
ui_controls::SendMouseMove(above_content_point.x(), ui_controls::SendMouseMove(out_of_content_.x(), out_of_content_.y());
above_content_point.y());
// Wait on the correct final value of the cookie. // Wait on the correct final value of the cookie.
base::string16 left_expected_title(base::ASCIIToUTF16("left")); base::string16 left_expected_title(base::ASCIIToUTF16("left"));
...@@ -66,6 +73,9 @@ class MouseLeaveTest : public InProcessBrowserTest { ...@@ -66,6 +73,9 @@ class MouseLeaveTest : public InProcessBrowserTest {
EXPECT_EQ(left_expected_title, left_title_watcher.WaitAndGetTitle()); EXPECT_EQ(left_expected_title, left_title_watcher.WaitAndGetTitle());
} }
// The coordinates out of the content to move the mouse point
gfx::Point out_of_content_;
DISALLOW_COPY_AND_ASSIGN(MouseLeaveTest); DISALLOW_COPY_AND_ASSIGN(MouseLeaveTest);
}; };
...@@ -95,4 +105,68 @@ IN_PROC_BROWSER_TEST_F(MouseLeaveTest, MouseDownOnBrowserCaption) { ...@@ -95,4 +105,68 @@ IN_PROC_BROWSER_TEST_F(MouseLeaveTest, MouseDownOnBrowserCaption) {
} }
#endif #endif
#if defined(OS_WIN) || defined(OS_MACOSX)
// Test that a mouseleave is not triggered when showing the context menu.
// If the test is failed, it means that Blink gets the mouseleave event
// when showing the context menu and it could make the unexpecting
// content behavior such as clearing the hover status.
// Please refer to the below issue for understanding what happens .
// TODO: Make test pass on OS_WIN and OS_MACOSX
// OS_WIN: http://crbug.com/450138
// OS_MACOSX: Missing automation provider support: http://crbug.com/45892.
#define MAYBE_ContextMenu DISABLED_ContextMenu
#else
#define MAYBE_ContextMenu ContextMenu
#endif
IN_PROC_BROWSER_TEST_F(MouseLeaveTest, MAYBE_ContextMenu) {
content::WebContents* tab =
browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_NO_FATAL_FAILURE(LoadTestPageAndWaitForMouseOver(tab));
ContextMenuWaiter menu_observer(content::NotificationService::AllSources());
ui_controls::SendMouseClick(ui_controls::RIGHT);
// Wait until the context menu is opened and closed.
menu_observer.WaitForMenuOpenAndClose();
tab->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16("done()"));
const base::string16 success_title = base::ASCIIToUTF16("without mouseleave");
const base::string16 failure_title = base::ASCIIToUTF16("with mouseleave");
content::TitleWatcher done_title_watcher(tab, success_title);
done_title_watcher.AlsoWaitForTitle(failure_title);
EXPECT_EQ(success_title, done_title_watcher.WaitAndGetTitle());
}
#if defined(OS_WIN) || defined(OS_MACOSX)
// Test that a mouseleave is not triggered when showing a modal dialog.
// Sample regression: crbug.com/394672
// TODO: Make test pass on OS_WIN and OS_MACOSX
// OS_WIN: http://crbug.com/450138
// OS_MACOSX: Missing automation provider support: http://crbug.com/45892.
#define MAYBE_ModalDialog DISABLED_ModalDialog
#else
#define MAYBE_ModalDialog ModalDialog
#endif
IN_PROC_BROWSER_TEST_F(MouseLeaveTest, MAYBE_ModalDialog) {
content::WebContents* tab =
browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_NO_FATAL_FAILURE(LoadTestPageAndWaitForMouseOver(tab));
tab->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16("alert()"));
app_modal::AppModalDialog* alert = ui_test_utils::WaitForAppModalDialog();
// Cancel the dialog.
alert->CloseModalDialog();
tab->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16("done()"));
const base::string16 success_title = base::ASCIIToUTF16("without mouseleave");
const base::string16 failure_title = base::ASCIIToUTF16("with mouseleave");
content::TitleWatcher done_title_watcher(tab, success_title);
done_title_watcher.AlsoWaitForTitle(failure_title);
EXPECT_EQ(success_title, done_title_watcher.WaitAndGetTitle());
}
} // namespace } // namespace
...@@ -254,8 +254,7 @@ IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, OpenIncognitoNoneReferrer) { ...@@ -254,8 +254,7 @@ IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, OpenIncognitoNoneReferrer) {
// Check filename on clicking "Save Link As" via a "real" context menu. // Check filename on clicking "Save Link As" via a "real" context menu.
IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, SuggestedFileName) { IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, SuggestedFileName) {
// Register observer. // Register observer.
SaveLinkAsContextMenuObserver menu_observer( ContextMenuWaiter menu_observer(content::NotificationService::AllSources());
content::NotificationService::AllSources());
// Go to a page with a link having download attribute. // Go to a page with a link having download attribute.
const std::string kSuggestedFilename("test_filename.png"); const std::string kSuggestedFilename("test_filename.png");
...@@ -277,10 +276,10 @@ IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, SuggestedFileName) { ...@@ -277,10 +276,10 @@ IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, SuggestedFileName) {
tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event); tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
// Wait for context menu to be visible. // Wait for context menu to be visible.
menu_observer.WaitForMenu(); menu_observer.WaitForMenuOpenAndClose();
// Compare filename. // Compare filename.
base::string16 suggested_filename = menu_observer.GetSuggestedFilename(); base::string16 suggested_filename = menu_observer.params().suggested_filename;
ASSERT_EQ(kSuggestedFilename, base::UTF16ToUTF8(suggested_filename).c_str()); ASSERT_EQ(kSuggestedFilename, base::UTF16ToUTF8(suggested_filename).c_str());
} }
......
...@@ -50,29 +50,26 @@ void ContextMenuNotificationObserver::ExecuteCommand( ...@@ -50,29 +50,26 @@ void ContextMenuNotificationObserver::ExecuteCommand(
context_menu->Cancel(); context_menu->Cancel();
} }
SaveLinkAsContextMenuObserver::SaveLinkAsContextMenuObserver( ContextMenuWaiter::ContextMenuWaiter(const content::NotificationSource& source)
const content::NotificationSource& source) : menu_visible_(false) {
: ContextMenuNotificationObserver(IDC_CONTENT_CONTEXT_SAVELINKAS), registrar_.Add(this, chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN,
menu_visible_(false) { content::NotificationService::AllSources());
} }
SaveLinkAsContextMenuObserver::~SaveLinkAsContextMenuObserver() { ContextMenuWaiter::~ContextMenuWaiter() {
} }
void SaveLinkAsContextMenuObserver::Observe( void ContextMenuWaiter::Observe(int type,
int type, const content::NotificationSource& source,
const content::NotificationSource& source, const content::NotificationDetails& details) {
const content::NotificationDetails& details) {
switch (type) { switch (type) {
case chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN: { case chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN: {
menu_visible_ = true; menu_visible_ = true;
RenderViewContextMenu* context_menu = RenderViewContextMenu* context_menu =
content::Source<RenderViewContextMenu>(source).ptr(); content::Source<RenderViewContextMenu>(source).ptr();
base::MessageLoop::current()->PostTask( base::MessageLoop::current()->PostTask(
FROM_HERE, FROM_HERE, base::Bind(&ContextMenuWaiter::Cancel,
base::Bind(&SaveLinkAsContextMenuObserver::Cancel, base::Unretained(this), context_menu));
base::Unretained(this),
context_menu));
break; break;
} }
...@@ -81,21 +78,22 @@ void SaveLinkAsContextMenuObserver::Observe( ...@@ -81,21 +78,22 @@ void SaveLinkAsContextMenuObserver::Observe(
} }
} }
void SaveLinkAsContextMenuObserver::WaitForMenu() { void ContextMenuWaiter::WaitForMenuOpenAndClose() {
content::WindowedNotificationObserver menu_observer( content::WindowedNotificationObserver menu_observer(
chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN, chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN,
content::NotificationService::AllSources()); content::NotificationService::AllSources());
if (!menu_visible_) if (!menu_visible_)
menu_observer.Wait(); menu_observer.Wait();
content::RunAllPendingInMessageLoop();
menu_visible_ = false; menu_visible_ = false;
} }
base::string16 SaveLinkAsContextMenuObserver::GetSuggestedFilename() { content::ContextMenuParams& ContextMenuWaiter::params() {
return params_.suggested_filename; return params_;
} }
void SaveLinkAsContextMenuObserver::Cancel( void ContextMenuWaiter::Cancel(RenderViewContextMenu* context_menu) {
RenderViewContextMenu* context_menu) {
params_ = context_menu->params(); params_ = context_menu->params();
context_menu->Cancel(); context_menu->Cancel();
} }
...@@ -32,21 +32,19 @@ class ContextMenuNotificationObserver : public content::NotificationObserver { ...@@ -32,21 +32,19 @@ class ContextMenuNotificationObserver : public content::NotificationObserver {
DISALLOW_COPY_AND_ASSIGN(ContextMenuNotificationObserver); DISALLOW_COPY_AND_ASSIGN(ContextMenuNotificationObserver);
}; };
class SaveLinkAsContextMenuObserver : public ContextMenuNotificationObserver { class ContextMenuWaiter : public content::NotificationObserver {
public: public:
// Register to listen for notifications of // Register to listen for notifications of
// NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN from either // NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN from either
// a specific source, or from all sources if |source| is // a specific source, or from all sources if |source| is
// NotificationService::AllSources(). // NotificationService::AllSources().
explicit SaveLinkAsContextMenuObserver( explicit ContextMenuWaiter(const content::NotificationSource& source);
const content::NotificationSource& source); ~ContextMenuWaiter() override;
~SaveLinkAsContextMenuObserver() override;
// Suggested filename for file downloaded through "Save Link As" option. content::ContextMenuParams& params();
base::string16 GetSuggestedFilename();
// Wait for context menu to be visible. // Wait until the context menu is opened and closed.
void WaitForMenu(); void WaitForMenuOpenAndClose();
private: private:
void Observe(int type, void Observe(int type,
...@@ -57,8 +55,9 @@ class SaveLinkAsContextMenuObserver : public ContextMenuNotificationObserver { ...@@ -57,8 +55,9 @@ class SaveLinkAsContextMenuObserver : public ContextMenuNotificationObserver {
bool menu_visible_; bool menu_visible_;
content::ContextMenuParams params_; content::ContextMenuParams params_;
content::NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(SaveLinkAsContextMenuObserver); DISALLOW_COPY_AND_ASSIGN(ContextMenuWaiter);
}; };
#endif // CHROME_BROWSER_RENDERER_CONTEXT_MENU_RENDER_VIEW_CONTEXT_MENU_BROWSERTEST_UTIL_H_ #endif // CHROME_BROWSER_RENDERER_CONTEXT_MENU_RENDER_VIEW_CONTEXT_MENU_BROWSERTEST_UTIL_H_
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
</style> </style>
<script> <script>
var state = ''; var state = '';
var hasLeave = false;
function load() { function load() {
state = 'initial'; state = 'initial';
document.getElementById("mystatus").innerHTML = state; document.getElementById("mystatus").innerHTML = state;
...@@ -29,10 +30,16 @@ ...@@ -29,10 +30,16 @@
document.title = "entered"; document.title = "entered";
} }
function leave() { function leave() {
hasLeave = true;
state += ',left'; state += ',left';
document.getElementById("mystatus").innerHTML = state; document.getElementById("mystatus").innerHTML = state;
document.title = "left"; document.title = "left";
} }
function done() {
state += ',done';
document.getElementById("mystatus").innerHTML = state;
document.title = hasLeave ? "with mouseleave" : "without mouseleave";
}
</script> </script>
</head> </head>
<body onload="load()"> <body onload="load()">
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment