#include "ash/system/notification_center/message_popup_animation_waiter.h"
#include "ash/system/notification_center/notification_center_test_api.h"
#include "ash/system/notification_center/notification_center_tray.h"
#include "ash/system/notification_center/views/ash_notification_expand_button.h"
#include "ash/system/notification_center/views/ash_notification_view.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/ash_test_util.h"
#include "ash/test/pixel/ash_pixel_differ.h"
#include "ash/test/pixel/ash_pixel_test_helper.h"
#include "ash/test/pixel/ash_pixel_test_init_params.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "chromeos/constants/chromeos_features.h"
#include "ui/base/models/image_model.h"
#include "ui/compositor/layer.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notifier_id.h"
#include "ui/message_center/views/message_popup_view.h"
#include "ui/message_center/views/notification_control_buttons_view.h"
namespace ash {
namespace {
constexpr char kShortTitleString[] = "Short Title";
constexpr char kMediumTitleString[] = "Test Notification's Multiline Title";
constexpr char kLongTitleString[] =
"Test Notification's Very Very Very Very Very Very Very Very Very Very "
"Very Very Very Very Very Very Very Very Very Very Very Very Very Very "
"Very Very Very Very Long Multiline Title";
constexpr char kLongMessageString[] =
"Test Notification's Very Very Very Very Very Very Very Very Very Very "
"Very Very Very Very Very Very Very Very Very Very Very Very Very Very "
"Very Very Very Very Long Message";
constexpr char kShortTitleScreenshot[] = "ash_notification_short_title";
constexpr char kMediumTitleScreenshot[] =
"ash_notification_multiline_medium_title";
constexpr char kLongTitleScreenshot[] = "ash_notification_multiline_long_title";
const ui::ImageModel test_green_icon = ui::ImageModel::FromImageSkia(
CreateSolidColorTestImage(gfx::Size(48, 48),
SK_ColorGREEN));
}
class AshPixelTestBase : public AshTestBase {
public:
AshPixelTestBase(bool increase_notification_width, bool enable_system_blur)
: increase_notification_width_(increase_notification_width),
enable_system_blur_(enable_system_blur) {}
std::optional<pixel_test::InitParams> CreatePixelTestInitParams()
const override {
pixel_test::InitParams init_params;
init_params.system_blur_enabled = enable_system_blur_;
return init_params;
}
void SetUp() override {
AshTestBase::SetUp();
test_api_ = std::make_unique<NotificationCenterTestApi>();
}
std::string GenerateScreenshotName(const std::string& title) override {
return pixel_test_helper()->GenerateScreenshotName(
title + (increase_notification_width_ ? "_new_width" : "_old_width"));
}
NotificationCenterTestApi* test_api() { return test_api_.get(); }
private:
const bool increase_notification_width_;
const bool enable_system_blur_;
std::unique_ptr<NotificationCenterTestApi> test_api_;
};
class AshNotificationViewPixelTest
: public AshPixelTestBase,
public testing::WithParamInterface<
std::tuple</*IsNotificationWidthIncreaseEnabled()=*/bool,
/*IsSystemBlurEnabled()=*/bool>> {
public:
AshNotificationViewPixelTest()
: AshPixelTestBase(IsNotificationWidthIncreaseEnabled(),
IsSystemBlurEnabled()) {}
bool IsNotificationWidthIncreaseEnabled() const {
return std::get<0>(GetParam());
}
bool IsSystemBlurEnabled() const { return std::get<1>(GetParam()); }
void SetUp() override {
scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
scoped_feature_list_->InitWithFeatureState(
chromeos::features::kNotificationWidthIncrease,
IsNotificationWidthIncreaseEnabled());
AshPixelTestBase::SetUp();
}
private:
std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
};
INSTANTIATE_TEST_SUITE_P(
All,
AshNotificationViewPixelTest,
testing::Combine(testing::Bool(),
testing::Bool()));
TEST_P(AshNotificationViewPixelTest, CloseButtonFocused) {
const auto id = test_api()->AddNotification();
test_api()->ToggleBubble();
auto* notification_view = static_cast<AshNotificationView*>(
test_api()->GetNotificationViewForId(id));
auto* control_buttons_layer =
notification_view->GetControlButtonsView()->layer();
auto* close_button =
notification_view->GetControlButtonsView()->close_button();
EXPECT_EQ(control_buttons_layer->opacity(), 0);
EXPECT_FALSE(close_button->HasFocus());
close_button->GetWidget()->widget_delegate()->SetCanActivate(true);
close_button->RequestFocus();
EXPECT_TRUE(close_button->HasFocus());
EXPECT_EQ(control_buttons_layer->opacity(), 1);
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
GenerateScreenshotName("close_button_focused"),
pixel_test_helper()->IsSystemBlurEnabled() ? 5 : 0,
notification_view));
}
TEST_P(AshNotificationViewPixelTest, DISABLED_CollapsedNoMessage) {
const std::string id = test_api()->AddCustomNotification(
u"Notification title", u"", test_green_icon);
test_api()->ToggleBubble();
auto* notification_view = static_cast<AshNotificationView*>(
test_api()->GetNotificationViewForId(id));
notification_view->SetExpanded(false);
ASSERT_FALSE(notification_view->IsExpanded());
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
GenerateScreenshotName("collapsed_no_message"),
pixel_test_helper()->IsSystemBlurEnabled() ? 5 : 0,
notification_view));
}
TEST_P(AshNotificationViewPixelTest, ProgressCollapsed) {
const std::string id = test_api()->AddProgressNotification();
test_api()->AddNotification();
test_api()->ToggleBubble();
auto* notification_view = static_cast<AshNotificationView*>(
test_api()->GetNotificationViewForId(id));
ASSERT_FALSE(notification_view->IsExpanded());
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
GenerateScreenshotName("progress_collapsed"),
pixel_test_helper()->IsSystemBlurEnabled() ? 5 : 0,
notification_view));
}
TEST_P(AshNotificationViewPixelTest, CloseControlButton) {
const std::string id = test_api()->AddNotification();
test_api()->ToggleBubble();
auto* notification_view = static_cast<AshNotificationView*>(
test_api()->GetNotificationViewForId(id));
GetEventGenerator()->MoveMouseTo(
notification_view->GetBoundsInScreen().CenterPoint(), 10);
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
GenerateScreenshotName("close_control_button"),
pixel_test_helper()->IsSystemBlurEnabled() ? 5 : 0,
notification_view));
}
TEST_P(AshNotificationViewPixelTest, SettingsAndCloseControlButtons) {
const std::string id = test_api()->AddNotificationWithSettingsButton();
test_api()->ToggleBubble();
auto* notification_view = static_cast<AshNotificationView*>(
test_api()->GetNotificationViewForId(id));
GetEventGenerator()->MoveMouseTo(
notification_view->GetBoundsInScreen().CenterPoint(), 10);
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
GenerateScreenshotName("settings_and_close_control_buttons"),
pixel_test_helper()->IsSystemBlurEnabled() ? 5 : 0,
notification_view));
}
TEST_P(AshNotificationViewPixelTest, InlineReply) {
message_center::RichNotificationData rich_data;
message_center::ButtonInfo button_info(u"Reply");
button_info.placeholder = std::make_optional(u"Send Message");
rich_data.buttons.push_back(button_info);
const std::string id = test_api()->AddCustomNotification(
u"title", u"message", ui::ImageModel(),
std::u16string(), GURL(),
message_center::NotifierId(),
rich_data);
test_api()->ToggleBubble();
auto* notification_view = static_cast<AshNotificationView*>(
test_api()->GetNotificationViewForId(id));
LeftClickOn(notification_view->GetActionButtonsForTest().front());
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
GenerateScreenshotName("inline_reply_focused"),
pixel_test_helper()->IsSystemBlurEnabled() ? 5 : 0,
notification_view));
}
TEST_P(AshNotificationViewPixelTest, ExpandButtonFocusRing) {
const std::string id = test_api()->AddNotification();
test_api()->ToggleBubble();
auto* notification_view = views::AsViewClass<AshNotificationView>(
test_api()->GetNotificationViewForId(id));
while (!notification_view->expand_button_for_test()->HasFocus()) {
PressAndReleaseKey(ui::VKEY_TAB);
}
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
GenerateScreenshotName("expand_button_focus_ring"),
pixel_test_helper()->IsSystemBlurEnabled() ? 5 : 0,
notification_view));
}
TEST_P(AshNotificationViewPixelTest, NotificationViewFocusRing) {
const std::string id = test_api()->AddNotification();
test_api()->ToggleBubble();
PressAndReleaseKey(ui::VKEY_TAB);
auto* notification_view = test_api()->GetNotificationViewForId(id);
ASSERT_TRUE(notification_view->HasFocus());
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
GenerateScreenshotName("notification_view_focus_ring"),
pixel_test_helper()->IsSystemBlurEnabled() ? 5 : 0,
notification_view));
}
TEST_P(AshNotificationViewPixelTest, NotificationPopupFocusRing) {
const std::string id = test_api()->AddNotification();
MessagePopupAnimationWaiter(
GetPrimaryNotificationCenterTray()->popup_collection())
.Wait();
auto* notification_view = test_api()->GetPopupViewForId(id);
notification_view->message_view()->RequestFocus();
ASSERT_TRUE(notification_view->message_view()->HasFocus());
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
GenerateScreenshotName("notification_popup_focus_ring"),
pixel_test_helper()->IsSystemBlurEnabled() ? 5 : 0,
notification_view));
}
class AshNotificationViewIconPixelTest
: public AshPixelTestBase,
public testing::WithParamInterface<std::tuple<int, bool, bool>> {
public:
AshNotificationViewIconPixelTest()
: AshPixelTestBase(IsNotificationWidthIncreaseEnabled(),
IsSystemBlurEnabled()) {}
int GetIconSize() { return std::get<0>(GetParam()); }
bool IsNotificationWidthIncreaseEnabled() { return std::get<1>(GetParam()); }
bool IsSystemBlurEnabled() { return std::get<2>(GetParam()); }
void SetUp() override {
scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
scoped_feature_list_->InitWithFeatureState(
chromeos::features::kNotificationWidthIncrease,
IsNotificationWidthIncreaseEnabled());
AshPixelTestBase::SetUp();
}
private:
std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
};
INSTANTIATE_TEST_SUITE_P(
IconTest,
AshNotificationViewIconPixelTest,
testing::Combine(testing::ValuesIn({
16,
32,
128,
512,
}),
testing::Bool(),
testing::Bool()));
TEST_P(AshNotificationViewIconPixelTest, DISABLED_NotificationIcon) {
int size = GetIconSize();
const std::string id = test_api()->AddCustomNotification(
u"Notification title", u"Notification message",
ui::ImageModel::FromImageSkia(CreateSolidColorTestImage(
gfx::Size(size, size), SK_ColorGREEN)));
test_api()->ToggleBubble();
auto* notification_view = static_cast<AshNotificationView*>(
test_api()->GetNotificationViewForId(id));
ASSERT_TRUE(notification_view->IsExpanded());
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
GenerateScreenshotName(base::StringPrintf("expanded_icon_size_%u", size)),
pixel_test_helper()->IsSystemBlurEnabled() ? 5 : 0,
notification_view));
notification_view->ToggleExpand();
ASSERT_FALSE(notification_view->IsExpanded());
notification_view = static_cast<AshNotificationView*>(
test_api()->GetNotificationViewForId(id));
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
GenerateScreenshotName(
base::StringPrintf("collapsed_icon_size_%u", size)),
pixel_test_helper()->IsSystemBlurEnabled() ? 4 : 0,
notification_view));
}
class AshNotificationViewTitlePixelTest
: public AshPixelTestBase,
public testing::WithParamInterface<
std::tuple<const char* /*notification title string*/,
bool /*notification width increase*/,
bool /*system blur enabled*/>> {
public:
AshNotificationViewTitlePixelTest()
: AshPixelTestBase(IsNotificationWidthIncreaseEnabled(),
IsSystemBlurEnabled()) {}
const std::string GetTitle() { return std::get<0>(GetParam()); }
bool IsNotificationWidthIncreaseEnabled() { return std::get<1>(GetParam()); }
bool IsSystemBlurEnabled() { return std::get<2>(GetParam()); }
void SetUp() override {
scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
scoped_feature_list_->InitWithFeatureState(
chromeos::features::kNotificationWidthIncrease,
IsNotificationWidthIncreaseEnabled());
AshPixelTestBase::SetUp();
}
private:
std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
};
INSTANTIATE_TEST_SUITE_P(
TitleTest,
AshNotificationViewTitlePixelTest,
testing::Combine(testing::ValuesIn({kShortTitleString,
kMediumTitleString,
kLongTitleString}),
testing::Bool(),
testing::Bool()));
TEST_P(AshNotificationViewTitlePixelTest, DISABLED_NotificationTitleTest) {
const std::string title = GetTitle();
const std::string id = test_api()->AddCustomNotification(
base::UTF8ToUTF16(title), u"Notification Content", test_green_icon);
test_api()->ToggleBubble();
message_center::MessageView* notification_view =
test_api()->GetNotificationViewForId(id);
ASSERT_TRUE(notification_view);
EXPECT_TRUE(notification_view->GetVisible());
std::string screenshot_name;
if (title == kShortTitleString) {
screenshot_name = kShortTitleScreenshot;
} else if (title == kMediumTitleString) {
screenshot_name = kMediumTitleScreenshot;
} else {
screenshot_name = kLongTitleScreenshot;
}
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
GenerateScreenshotName(screenshot_name),
pixel_test_helper()->IsSystemBlurEnabled() ? 5 : 0,
notification_view));
}
class AshNotificationViewCollapsedLongTextPixelTest
: public AshPixelTestBase,
public testing::WithParamInterface<
std::tuple<bool /*whether there is an icon*/,
bool /*whether there is a settings control button*/,
bool /*notification width increase*/,
bool /*system blur enabled*/>> {
public:
AshNotificationViewCollapsedLongTextPixelTest()
: AshPixelTestBase(IsNotificationWidthIncreaseEnabled(),
IsSystemBlurEnabled()) {}
bool HasIcon() { return std::get<0>(GetParam()); }
bool HasSettingsControlButton() { return std::get<1>(GetParam()); }
bool IsNotificationWidthIncreaseEnabled() { return std::get<2>(GetParam()); }
bool IsSystemBlurEnabled() { return std::get<3>(GetParam()); }
void SetUp() override {
scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
scoped_feature_list_->InitWithFeatureState(
chromeos::features::kNotificationWidthIncrease,
IsNotificationWidthIncreaseEnabled());
AshPixelTestBase::SetUp();
}
private:
std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
};
INSTANTIATE_TEST_SUITE_P(
All,
AshNotificationViewCollapsedLongTextPixelTest,
testing::Combine(testing::Bool(),
testing::Bool(),
testing::Bool(),
testing::Bool()));
TEST_P(AshNotificationViewCollapsedLongTextPixelTest,
DISABLED_ElidedTextSpacing) {
message_center::RichNotificationData optional_fields;
if (HasSettingsControlButton()) {
optional_fields.settings_button_handler =
message_center::SettingsButtonHandler::DELEGATE;
}
const std::string id = test_api()->AddCustomNotification(
base::UTF8ToUTF16(std::string(kLongTitleString)),
base::UTF8ToUTF16(std::string(kLongMessageString)),
HasIcon() ? test_green_icon : ui::ImageModel(),
u"", GURL(),
message_center::NotifierId(), optional_fields);
test_api()->AddNotification();
test_api()->ToggleBubble();
auto* notification_view = static_cast<AshNotificationView*>(
test_api()->GetNotificationViewForId(id));
ASSERT_FALSE(notification_view->IsExpanded());
GetEventGenerator()->MoveMouseTo(
notification_view->GetBoundsInScreen().CenterPoint(), 10);
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
GenerateScreenshotName("elided_text_spacing"),
pixel_test_helper()->IsSystemBlurEnabled() ? 5 : 0,
notification_view));
}
}