blob: 3d61f51cd3695e92aaaf9efc77360dd468efbc48 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// 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/autofill/autofill_field_promo_view_impl.h"
#include <optional>
#include "base/memory/weak_ptr.h"
#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
#include "chrome/browser/ui/autofill/autofill_field_promo_view.h"
#include "chrome/browser/ui/browser_element_identifiers.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/test_with_browser_view.h"
#include "content/public/browser/picture_in_picture_window_controller.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/views/view_class_properties.h"
#include "ui/views/widget/widget.h"
#include "url/origin.h"
namespace autofill {
namespace {
class TestPictureInPictureWindowController
: public content::PictureInPictureWindowController {
public:
void Show() override {}
void FocusInitiator() override {}
void Close(bool) override {}
void CloseAndFocusInitiator() override {}
void OnWindowDestroyed(bool) override {}
content::WebContents* GetWebContents() override { return nullptr; }
content::WebContents* GetChildWebContents() override { return nullptr; }
std::optional<url::Origin> GetOrigin() override { return std::nullopt; }
std::optional<gfx::Rect> GetWindowBounds() override { return bounds_; }
void SetWindowBounds(gfx::Rect bounds) { bounds_ = bounds; }
private:
gfx::Rect bounds_;
};
AutofillFieldPromoViewImpl* GetViewRawPtr(
base::WeakPtr<AutofillFieldPromoView> view) {
return static_cast<AutofillFieldPromoViewImpl*>(view.get());
}
} // namespace
class AutofillFieldPromoViewImplTest : public TestWithBrowserView {
public:
void SetUp() override {
TestWithBrowserView::SetUp();
// Create the first tab so that `web_contents()` exists.
AddTab(browser(), GURL(chrome::kChromeUINewTabURL));
}
void TearDown() override {
if (view_) {
view_->Close();
}
TestWithBrowserView::TearDown();
}
content::WebContents* web_contents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
const ui::ElementIdentifier& element_identifier() {
return test_promo_element_identifier_;
}
base::WeakPtr<AutofillFieldPromoView> CreateView(
gfx::RectF bounds = gfx::RectF(0, 0, 1, 1)) {
// Always close previously created view in order to avoid dangling pointers.
if (view_) {
view_->Close();
}
view_ = AutofillFieldPromoView::CreateAndShow(
web_contents(), bounds, test_promo_element_identifier_);
return view_;
}
#if BUILDFLAG(IS_MAC)
// On Mac, web contents bounds cannot be easily modified. As an alternative,
// the bounds of the containing widget are changed.
// This works based on the assumption that the top chrome UI bounds do not
// change. There are only a few operations which can do that (ex: toggling the
// bookmark bar) and none of them occur in this test fixture and they should
// never occur in the future.
void ChangeBrowserWindowBoundsForDesiredWebContentsBounds(
gfx::Rect expected_web_contents_bounds) {
views::Widget* widget =
views::Widget::GetWidgetForNativeView(web_contents()->GetNativeView());
gfx::Vector2d origin_offset_between_widget_and_content_area =
widget->GetWindowBoundsInScreen().origin() -
web_contents()->GetContainerBounds().origin();
gfx::Size size_offset_between_widget_and_content_area =
widget->GetWindowBoundsInScreen().size() -
web_contents()->GetContainerBounds().size();
gfx::Rect widget_bounds;
widget_bounds.set_origin(expected_web_contents_bounds.origin() +
origin_offset_between_widget_and_content_area);
widget_bounds.set_size(expected_web_contents_bounds.size() +
size_offset_between_widget_and_content_area);
widget->SetBounds(widget_bounds);
}
#endif // BUILDFLAG(IS_MAC)
private:
const ui::ElementIdentifier test_promo_element_identifier_ =
kAutofillStandaloneCvcSuggestionElementId;
base::WeakPtr<AutofillFieldPromoView> view_;
};
TEST_F(AutofillFieldPromoViewImplTest, BoundsAreCorrect) {
// Set custom web contents bounds.
#if BUILDFLAG(IS_MAC)
ChangeBrowserWindowBoundsForDesiredWebContentsBounds(
gfx::Rect(300, 300, 1000, 1000));
#else
web_contents()->GetNativeView()->SetBoundsInScreen(
gfx::Rect(300, 300, 1000, 1000),
display::Screen::GetScreen()->GetDisplayForNewWindows());
#endif // BUILDFLAG(IS_MAC)
// Element is within the boundaries of `web_contents()`.
EXPECT_EQ(GetViewRawPtr(CreateView(gfx::RectF(400, 400, 300, 300)))->bounds(),
gfx::Rect(400, 699, 300, 1));
// Element partially exceeds the upper limit of `web_contents()`.
EXPECT_EQ(GetViewRawPtr(CreateView(gfx::RectF(800, 800, 300, 300)))->bounds(),
gfx::Rect(800, 999, 200, 1));
// Element partially exceeds the lower limit of `web_contents()`.
EXPECT_EQ(
GetViewRawPtr(CreateView(gfx::RectF(-100, -100, 300, 300)))->bounds(),
gfx::Rect(0, 199, 200, 1));
}
TEST_F(AutofillFieldPromoViewImplTest, LifetimeIsManagedCorrectlyOnClose) {
base::WeakPtr<AutofillFieldPromoView> view = CreateView();
AutofillFieldPromoViewImpl* view_ptr = GetViewRawPtr(view);
EXPECT_TRUE(BrowserView::GetBrowserViewForBrowser(browser())
->contents_web_view()
->Contains(view_ptr));
view->Close();
EXPECT_FALSE(view);
}
TEST_F(AutofillFieldPromoViewImplTest, OverlapsWithPictureInPictureWindow) {
base::WeakPtr<AutofillFieldPromoView> view =
CreateView(gfx::RectF(200, 200, 300, 300));
TestPictureInPictureWindowController picture_in_picture_window_controller;
PictureInPictureWindowManager::GetInstance()
->set_window_controller_for_testing(
&picture_in_picture_window_controller);
picture_in_picture_window_controller.SetWindowBounds(
gfx::Rect(100, 100, 50, 50));
EXPECT_FALSE(view->OverlapsWithPictureInPictureWindow());
picture_in_picture_window_controller.SetWindowBounds(
gfx::Rect(100, 100, 1000, 1000));
EXPECT_TRUE(view->OverlapsWithPictureInPictureWindow());
}
TEST_F(AutofillFieldPromoViewImplTest, ElementIdForIphIsCorrect) {
EXPECT_EQ(
GetViewRawPtr(CreateView())->GetProperty(views::kElementIdentifierKey),
element_identifier());
}
} // namespace autofill