blob: 04d7b0a45e3afdc34f4c204baf0fec2cf49f9a1b [file] [log] [blame]
// Copyright 2018 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 "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_command_controller.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/test/test_browser_dialog.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_close_button.h"
#include "chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h"
#include "chrome/browser/ui/views/tabs/tab_hover_card_controller.h"
#include "chrome/browser/ui/views/tabs/tab_hover_card_metrics.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/test/browser_test.h"
#include "ui/gfx/animation/animation_test_api.h"
#include "ui/views/controls/label.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
using views::Widget;
class TabHoverCardBubbleViewBrowserTest : public DialogBrowserTest {
public:
TabHoverCardBubbleViewBrowserTest()
: animation_mode_reset_(gfx::AnimationTestApi::SetRichAnimationRenderMode(
gfx::Animation::RichAnimationRenderMode::FORCE_DISABLED)) {
TabHoverCardController::disable_animations_for_testing_ = true;
}
TabHoverCardBubbleViewBrowserTest(const TabHoverCardBubbleViewBrowserTest&) =
delete;
TabHoverCardBubbleViewBrowserTest& operator=(
const TabHoverCardBubbleViewBrowserTest&) = delete;
~TabHoverCardBubbleViewBrowserTest() override = default;
void SetUpOnMainThread() override {
DialogBrowserTest::SetUpOnMainThread();
tab_strip_ = BrowserView::GetBrowserViewForBrowser(browser())->tabstrip();
}
TabStrip* tab_strip() { return tab_strip_; }
TabHoverCardBubbleView* hover_card() {
return tab_strip()->hover_card_controller_->hover_card_;
}
std::u16string GetHoverCardTitle() {
return hover_card()->GetTitleTextForTesting();
}
std::u16string GetHoverCardDomain() {
return hover_card()->GetDomainTextForTesting();
}
int GetHoverCardsSeenCount() {
return tab_strip()
->hover_card_controller_->metrics_for_testing()
->cards_seen_count();
}
void MouseExitTabStrip() {
ui::MouseEvent stop_hover_event(ui::ET_MOUSE_EXITED, gfx::Point(),
gfx::Point(), base::TimeTicks(),
ui::EF_NONE, 0);
tab_strip()->OnMouseExited(stop_hover_event);
}
void ClickMouseOnTab(int index) {
Tab* const tab = tab_strip()->tab_at(index);
ui::MouseEvent click_event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
base::TimeTicks(), ui::EF_NONE, 0);
tab->OnMousePressed(click_event);
}
void HoverMouseOverTabAt(int index) {
// We don't use Tab::OnMouseEntered here to invoke the hover card because
// that path is disabled in browser tests. If we enabled it, the real mouse
// might interfere with the test.
tab_strip()->UpdateHoverCard(tab_strip()->tab_at(index),
TabController::HoverCardUpdateType::kHover);
}
// DialogBrowserTest:
void ShowUi(const std::string& name) override {
HoverMouseOverTabAt(0);
views::test::WidgetVisibleWaiter(hover_card()->GetWidget()).Wait();
}
private:
std::unique_ptr<base::AutoReset<gfx::Animation::RichAnimationRenderMode>>
animation_mode_reset_;
TabStrip* tab_strip_ = nullptr;
};
IN_PROC_BROWSER_TEST_F(TabHoverCardBubbleViewBrowserTest,
InvokeUi_tab_hover_card) {
ShowAndVerifyUi();
}
// Verify hover card is visible while hovering and not visible outside of the
// tabstrip.
// TODO(crbug.com/1050765): the test is flaky.
#if defined(OS_WIN)
#define MAYBE_WidgetVisibleOnHover DISABLED_WidgetVisibleOnHover
#else
#define MAYBE_WidgetVisibleOnHover WidgetVisibleOnHover
#endif
IN_PROC_BROWSER_TEST_F(TabHoverCardBubbleViewBrowserTest,
MAYBE_WidgetVisibleOnHover) {
ShowUi("default");
Widget* const widget = hover_card()->GetWidget();
ASSERT_NE(nullptr, widget);
EXPECT_TRUE(widget->IsVisible());
MouseExitTabStrip();
EXPECT_FALSE(widget->IsVisible());
}
// Verify hover card is visible when tab is focused.
// TODO(crbug.com/1050765): the test is flaky.
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
#define MAYBE_WidgetVisibleOnTabFocus DISABLED_WidgetVisibleOnTabFocus
#else
#define MAYBE_WidgetVisibleOnTabFocus WidgetVisibleOnTabFocus
#endif
IN_PROC_BROWSER_TEST_F(TabHoverCardBubbleViewBrowserTest,
MAYBE_WidgetVisibleOnTabFocus) {
Tab* const tab = tab_strip()->tab_at(0);
tab_strip()->GetFocusManager()->SetFocusedView(tab);
Widget* const widget = hover_card()->GetWidget();
ASSERT_NE(nullptr, widget);
views::test::WidgetVisibleWaiter(widget).Wait();
EXPECT_TRUE(widget->IsVisible());
}
// Verify hover card is visible when focus moves from the tab to tab close
// button.
// TODO(crbug.com/1050765): the test is flaky.
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
#define MAYBE_WidgetVisibleOnTabCloseButtonFocusAfterTabFocus \
DISABLED_WidgetVisibleOnTabCloseButtonFocusAfterTabFocus
#else
#define MAYBE_WidgetVisibleOnTabCloseButtonFocusAfterTabFocus \
WidgetVisibleOnTabCloseButtonFocusAfterTabFocus
#endif
IN_PROC_BROWSER_TEST_F(TabHoverCardBubbleViewBrowserTest,
MAYBE_WidgetVisibleOnTabCloseButtonFocusAfterTabFocus) {
Tab* const tab = tab_strip()->tab_at(0);
tab_strip()->GetFocusManager()->SetFocusedView(tab);
Widget* const widget = hover_card()->GetWidget();
ASSERT_NE(nullptr, widget);
views::test::WidgetVisibleWaiter(widget).Wait();
EXPECT_TRUE(widget->IsVisible());
tab_strip()->GetFocusManager()->SetFocusedView(tab->close_button_);
views::test::WidgetVisibleWaiter(widget).Wait();
EXPECT_TRUE(widget->IsVisible());
}
// Verify hover card is visible when tab is focused and a key is pressed.
IN_PROC_BROWSER_TEST_F(TabHoverCardBubbleViewBrowserTest,
WidgetVisibleOnKeyPressAfterTabFocus) {
Tab* const tab = tab_strip()->tab_at(0);
tab_strip()->GetFocusManager()->SetFocusedView(tab);
Widget* const widget = hover_card()->GetWidget();
ASSERT_NE(nullptr, widget);
views::test::WidgetVisibleWaiter(widget).Wait();
EXPECT_TRUE(widget->IsVisible());
ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, 0);
tab->OnKeyPressed(key_event);
EXPECT_TRUE(widget->IsVisible());
}
// Verify hover card is not visible when tab is focused and the mouse is
// pressed.
IN_PROC_BROWSER_TEST_F(TabHoverCardBubbleViewBrowserTest,
WidgetNotVisibleOnMousePressAfterTabFocus) {
Tab* const tab = tab_strip()->tab_at(0);
tab_strip()->GetFocusManager()->SetFocusedView(tab);
Widget* const widget = hover_card()->GetWidget();
ASSERT_NE(nullptr, widget);
views::test::WidgetVisibleWaiter(widget).Wait();
EXPECT_TRUE(widget->IsVisible());
ClickMouseOnTab(0);
EXPECT_FALSE(widget->IsVisible());
}
// Verify hover card is visible after navigating to the tab strip using keyboard
// accelerators.
// TODO(crbug.com/1050765): the test is flaky.
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
#define MAYBE_WidgetVisibleOnTabFocusFromKeyboardAccelerator \
DISABLED_WidgetVisibleOnTabFocusFromKeyboardAccelerator
#else
#define MAYBE_WidgetVisibleOnTabFocusFromKeyboardAccelerator \
WidgetVisibleOnTabFocusFromKeyboardAccelerator
#endif
IN_PROC_BROWSER_TEST_F(TabHoverCardBubbleViewBrowserTest,
MAYBE_WidgetVisibleOnTabFocusFromKeyboardAccelerator) {
TabRendererData new_tab_data = TabRendererData();
new_tab_data.title = u"Test Tab 2";
new_tab_data.last_committed_url =
GURL("http://example.com/this/should/not/be/seen");
tab_strip()->AddTabAt(1, new_tab_data, false);
// Cycle focus until it reaches a tab.
while (!tab_strip()->IsFocusInTabs())
browser()->command_controller()->ExecuteCommand(IDC_FOCUS_NEXT_PANE);
Widget* const widget = hover_card()->GetWidget();
ASSERT_NE(nullptr, widget);
views::test::WidgetVisibleWaiter(widget).Wait();
EXPECT_TRUE(widget->IsVisible());
// Move focus forward to the close button or next tab dependent on window
// size.
tab_strip()->AcceleratorPressed(ui::Accelerator(ui::VKEY_RIGHT, ui::EF_NONE));
EXPECT_TRUE(widget->IsVisible());
}
// Verify hover card is not visible after clicking on a tab.
// TODO(crbug.com/1050765): the test is flaky.
#if defined(OS_WIN)
#define MAYBE_WidgetNotVisibleOnClick DISABLED_WidgetNotVisibleOnClick
#else
#define MAYBE_WidgetNotVisibleOnClick WidgetNotVisibleOnClick
#endif
IN_PROC_BROWSER_TEST_F(TabHoverCardBubbleViewBrowserTest,
MAYBE_WidgetNotVisibleOnClick) {
ShowUi("default");
Widget* const widget = hover_card()->GetWidget();
ASSERT_NE(nullptr, widget);
EXPECT_TRUE(widget->IsVisible());
ClickMouseOnTab(0);
EXPECT_FALSE(widget->IsVisible());
}
// Verify title, domain, and anchor are correctly updated when moving hover
// from one tab to another.
// TODO(crbug.com/1050765): the test is flaky.
#if defined(OS_WIN)
#define MAYBE_WidgetDataUpdate DISABLED_WidgetDataUpdate
#else
#define MAYBE_WidgetDataUpdate WidgetDataUpdate
#endif
IN_PROC_BROWSER_TEST_F(TabHoverCardBubbleViewBrowserTest,
MAYBE_WidgetDataUpdate) {
TabRendererData new_tab_data = TabRendererData();
new_tab_data.title = u"Test Tab 2";
new_tab_data.last_committed_url =
GURL("http://example.com/this/should/not/be/seen");
tab_strip()->AddTabAt(1, new_tab_data, false);
ShowUi("default");
Widget* const widget = hover_card()->GetWidget();
ASSERT_NE(nullptr, widget);
EXPECT_TRUE(widget->IsVisible());
HoverMouseOverTabAt(1);
ASSERT_NE(nullptr, widget);
EXPECT_TRUE(widget->IsVisible());
Tab* const tab = tab_strip()->tab_at(1);
EXPECT_EQ(GetHoverCardTitle(), u"Test Tab 2");
EXPECT_EQ(GetHoverCardDomain(), u"example.com");
EXPECT_EQ(hover_card()->GetAnchorView(), static_cast<views::View*>(tab));
}
// Verify inactive window remains inactive when showing a hover card for a tab
// in the inactive window.
// TODO(crbug.com/1050765): the test is flaky.
#if defined(OS_WIN)
#define MAYBE_InactiveWindowStaysInactiveOnHover \
DISABLED_InactiveWindowStaysInactiveOnHover
#else
#define MAYBE_InactiveWindowStaysInactiveOnHover \
InactiveWindowStaysInactiveOnHover
#endif
IN_PROC_BROWSER_TEST_F(TabHoverCardBubbleViewBrowserTest,
MAYBE_InactiveWindowStaysInactiveOnHover) {
const BrowserList* active_browser_list_ = BrowserList::GetInstance();
// Open a second window. On Windows, Widget::Deactivate() works by activating
// the next topmost window on the z-order stack. So instead we use two windows
// and Widget::Activate() here to prevent Widget::Deactivate() from
// undesirably activating another window when tests are being run in parallel.
ui_test_utils::NavigateToURLWithDisposition(
browser(), GURL(url::kAboutBlankURL), WindowOpenDisposition::NEW_WINDOW,
ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
ShowUi("default");
ASSERT_EQ(2u, active_browser_list_->size());
Browser* active_window = active_browser_list_->get(0);
Browser* inactive_window = active_browser_list_->get(1);
views::test::WidgetActivationWaiter waiter(
BrowserView::GetBrowserViewForBrowser(inactive_window)->frame(), false);
BrowserView::GetBrowserViewForBrowser(active_window)->Activate();
waiter.Wait();
ASSERT_FALSE(
BrowserView::GetBrowserViewForBrowser(inactive_window)->IsActive());
HoverMouseOverTabAt(0);
ASSERT_FALSE(
BrowserView::GetBrowserViewForBrowser(inactive_window)->IsActive());
}
IN_PROC_BROWSER_TEST_F(TabHoverCardBubbleViewBrowserTest,
HoverCardsSeenRatioMetric) {
tab_strip()->AddTabAt(1, TabRendererData(), false);
tab_strip()->AddTabAt(2, TabRendererData(), false);
HoverMouseOverTabAt(0);
Widget* const widget = hover_card()->GetWidget();
ASSERT_NE(nullptr, widget);
views::test::WidgetVisibleWaiter(widget).Wait();
EXPECT_EQ(GetHoverCardsSeenCount(), 1);
EXPECT_TRUE(widget->IsVisible());
HoverMouseOverTabAt(1);
EXPECT_EQ(GetHoverCardsSeenCount(), 2);
EXPECT_TRUE(widget->IsVisible());
ui::ListSelectionModel selection;
selection.SetSelectedIndex(1);
tab_strip()->SetSelection(selection);
EXPECT_EQ(GetHoverCardsSeenCount(), 0);
EXPECT_FALSE(widget->IsVisible());
}