Skip to content

Commit

Permalink
Add pixel tests for Autofill popups.
Browse files Browse the repository at this point in the history
This CL adds pixel tests for Autofill popups. These pixel tests
add a test case for every AutofillPopupRowView subclass.

At the same time, they are not exhaustive in the current state:
1) They do not test the widget border
2) They do not test every possible autofill::Suggestion setup
3) They do not test hover/ selection status.

Changing 1) would require changing how screenshots are taken in the
pixel test setup.

2) and 3) can be addressed in follow-up work, but it will likely
not be necessary to reproduce every possible type of suggestion
to test all variations of AutofillPopupRowView.

Bug: 1411172
Change-Id: Iad147323e5675f10c451ed93bec9585464bb97ce
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4203632
Commit-Queue: Jan Keitel <jkeitel@google.com>
Reviewed-by: Christoph Schwering <schwering@google.com>
Reviewed-by: Mohamed Amir Yosef <mamir@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1100363}
  • Loading branch information
Jan Keitel authored and Chromium LUCI CQ committed Feb 2, 2023
1 parent fcc7c88 commit db3c3f9
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 45 deletions.
45 changes: 23 additions & 22 deletions chrome/browser/autofill/mock_autofill_popup_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "chrome/browser/ui/autofill/autofill_popup_controller.h"
#include "components/autofill/core/browser/ui/suggestion.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/test/scoped_default_font_description.h"

Expand All @@ -26,25 +27,23 @@ class MockAutofillPopupController
MockAutofillPopupController();
~MockAutofillPopupController() override;

// AutofillPopupViewDelegate
MOCK_METHOD1(Hide, void(PopupHidingReason reason));
MOCK_METHOD0(ViewDestroyed, void());
MOCK_METHOD1(SetSelectionAtPoint, void(const gfx::Point& point));
MOCK_METHOD0(AcceptSelectedLine, bool());
MOCK_METHOD0(SelectionCleared, void());
MOCK_CONST_METHOD0(HasSelection, bool());
MOCK_CONST_METHOD0(popup_bounds, gfx::Rect());
MOCK_CONST_METHOD0(container_view, gfx::NativeView());
MOCK_CONST_METHOD0(GetWebContents, content::WebContents*());
// AutofillPopupViewDelegate:
MOCK_METHOD(void, Hide, (PopupHidingReason), (override));
MOCK_METHOD(void, ViewDestroyed, (), (override));
MOCK_METHOD(void, SelectionCleared, (), (override));
MOCK_METHOD(bool, HasSelection, (), (const override));
MOCK_METHOD(gfx::Rect, popup_bounds, (), (const override));
MOCK_METHOD(gfx::NativeView, container_view, (), (const override));
MOCK_METHOD(content::WebContents*, GetWebContents, (), (const override));
const gfx::RectF& element_bounds() const override {
static const gfx::RectF bounds(100, 100, 250, 50);
return bounds;
}
MOCK_CONST_METHOD0(IsRTL, bool());
MOCK_METHOD(bool, IsRTL, (), (const override));

// AutofillPopupController
MOCK_METHOD0(OnSuggestionsChanged, void());
MOCK_METHOD1(AcceptSuggestion, void(int index));
// AutofillPopupController:
MOCK_METHOD(void, OnSuggestionsChanged, (), (override));
MOCK_METHOD(void, AcceptSuggestion, (int), (override));
std::vector<Suggestion> GetSuggestions() const override {
return suggestions_;
}
Expand Down Expand Up @@ -72,12 +71,14 @@ class MockAutofillPopupController
return weak_ptr_factory_.GetWeakPtr();
}

MOCK_METHOD3(GetRemovalConfirmationText,
bool(int index, std::u16string* title, std::u16string* body));
MOCK_METHOD1(RemoveSuggestion, bool(int index));
MOCK_METHOD1(SetSelectedLine, void(absl::optional<int> selected_line));
MOCK_CONST_METHOD0(selected_line, absl::optional<int>());
MOCK_CONST_METHOD0(GetPopupType, PopupType());
MOCK_METHOD(bool,
GetRemovalConfirmationText,
(int, std::u16string*, std::u16string*),
(override));
MOCK_METHOD(bool, RemoveSuggestion, (int), (override));
MOCK_METHOD(void, SetSelectedLine, (absl::optional<int>), (override));
MOCK_METHOD(absl::optional<int>, selected_line, (), (const override));
MOCK_METHOD(PopupType, GetPopupType, (), (const override));

void set_suggestions(const std::vector<int>& ids) {
for (const auto& id : ids) {
Expand All @@ -88,8 +89,8 @@ class MockAutofillPopupController
}
}

void set_suggestions(const std::vector<Suggestion>& suggestions) {
suggestions_ = suggestions;
void set_suggestions(std::vector<Suggestion> suggestions) {
suggestions_ = std::move(suggestions);
}

private:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "chrome/browser/ui/views/autofill/autofill_popup_base_view.h"

#include <utility>

#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "build/build_config.h"
Expand All @@ -14,6 +16,7 @@
#include "chrome/test/base/in_process_browser_test.h"
#include "components/autofill/core/browser/ui/suggestion.h"
#include "components/autofill/core/common/autofill_features.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
Expand All @@ -35,19 +38,17 @@ using testing::ReturnRef;

class MockAutofillPopupViewDelegate : public AutofillPopupViewDelegate {
public:
MOCK_METHOD1(Hide, void(PopupHidingReason));
MOCK_METHOD0(ViewDestroyed, void());
MOCK_METHOD1(SetSelectionAtPoint, void(const gfx::Point&));
MOCK_METHOD0(AcceptSelectedLine, bool());
MOCK_METHOD0(SelectionCleared, void());
MOCK_CONST_METHOD0(HasSelection, bool());

// TODO(jdduke): Mock this method upon resolution of crbug.com/352463.
MOCK_CONST_METHOD0(popup_bounds, gfx::Rect());
MOCK_CONST_METHOD0(container_view, gfx::NativeView());
MOCK_CONST_METHOD0(GetWebContents, content::WebContents*());
MOCK_CONST_METHOD0(element_bounds, gfx::RectF&());
MOCK_CONST_METHOD0(IsRTL, bool());
MockAutofillPopupViewDelegate() = default;
~MockAutofillPopupViewDelegate() override = default;

MOCK_METHOD(void, Hide, (PopupHidingReason), (override));
MOCK_METHOD(void, ViewDestroyed, (), (override));
MOCK_METHOD(void, SelectionCleared, (), (override));

MOCK_METHOD(gfx::NativeView, container_view, (), (const override));
MOCK_METHOD(content::WebContents*, GetWebContents, (), (const override));
MOCK_METHOD(const gfx::RectF&, element_bounds, (), (const override));
MOCK_METHOD(bool, IsRTL, (), (const override));

base::WeakPtr<AutofillPopupViewDelegate> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
Expand Down Expand Up @@ -85,20 +86,13 @@ class AutofillPopupBaseViewTest : public InProcessBrowserTest {
browser()->window()->GetNativeWindow()));
}

void ShowView() { view_->DoShow(); }

ui::GestureEvent CreateGestureEvent(ui::EventType type, gfx::Point point) {
return ui::GestureEvent(point.x(), point.y(), 0, ui::EventTimeForNow(),
ui::GestureEventDetails(type));
}
void TearDownOnMainThread() override { view_ = nullptr; }

void SimulateGesture(ui::GestureEvent* event) {
view_->OnGestureEvent(event);
}
void ShowView() { view_->DoShow(); }

protected:
testing::NiceMock<MockAutofillPopupViewDelegate> mock_delegate_;
raw_ptr<AutofillPopupBaseView, DanglingUntriaged> view_;
raw_ptr<AutofillPopupBaseView> view_ = nullptr;
};

IN_PROC_BROWSER_TEST_F(AutofillPopupBaseViewTest, CorrectBoundsTest) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// Copyright 2023 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_popup_view_native_views.h"

#include <tuple>
#include <utility>

#include "base/memory/raw_ptr.h"
#include "base/scoped_environment_variable_override.h"
#include "base/strings/strcat.h"
#include "chrome/browser/autofill/mock_autofill_popup_controller.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/test/test_browser_ui.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/autofill/core/browser/ui/suggestion.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/test/browser_test.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gfx/render_text.h"
#include "ui/views/widget/widget.h"

namespace autofill {

using testing::NiceMock;
using testing::Return;

// If the boolean test parameter is `true`, dark mode is enforced.
class AutofillPopupViewNativeViewsTest
: public UiBrowserTest,
public testing::WithParamInterface<bool> {
public:
AutofillPopupViewNativeViewsTest() = default;
~AutofillPopupViewNativeViewsTest() override = default;

void SetUpCommandLine(base::CommandLine* command_line) override {
if (GetParam()) {
command_line->AppendSwitch(switches::kForceDarkMode);
}
}

void SetUpOnMainThread() override {
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
gfx::NativeView native_view = web_contents->GetNativeView();
EXPECT_CALL(controller_, container_view())
.WillRepeatedly(Return(native_view));
EXPECT_CALL(controller_, GetWebContents())
.WillRepeatedly(Return(web_contents));
}

void PrepareSuggestions(std::vector<Suggestion> suggestions) {
controller_.set_suggestions(std::move(suggestions));
}

void ShowUi(const std::string& name) override {
EXPECT_CALL(controller_, ViewDestroyed());
view_ = new AutofillPopupViewNativeViews(
controller_.GetWeakPtr(), views::Widget::GetWidgetForNativeWindow(
browser()->window()->GetNativeWindow()));
view_->Show();
}

bool VerifyUi() override {
if (!view_) {
return false;
}

views::Widget* widget = view_->GetWidget();
if (!widget) {
return false;
}

// VerifyPixelUi works only for these platforms.
// TODO(crbug.com/958242): Revise this if supported platforms change.
#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
auto* test_info = testing::UnitTest::GetInstance()->current_test_info();
const std::string screenshot_name =
base::StrCat({test_info->test_case_name(), "_", test_info->name()});

return VerifyPixelUi(widget, "AutofillPopupViewNativeViewsTest",
screenshot_name);
#else
return true;
#endif
}

void WaitForUserDismissal() override {
ui_test_utils::WaitForBrowserToClose();
}

void TearDownOnMainThread() override { view_ = nullptr; }

private:
std::unique_ptr<base::ScopedEnvironmentVariableOverride> scoped_env_override_;
NiceMock<autofill::MockAutofillPopupController> controller_;
raw_ptr<AutofillPopupViewNativeViews> view_ = nullptr;
};

IN_PROC_BROWSER_TEST_P(AutofillPopupViewNativeViewsTest,
InvokeUi_Autocomplete) {
PrepareSuggestions({Suggestion("Autocomplete entry 1", "", "", 0),
Suggestion("Autocomplete entry 2", "", "", 0)});
ShowAndVerifyUi();
}

IN_PROC_BROWSER_TEST_P(AutofillPopupViewNativeViewsTest,
InvokeUi_Autofill_Profile) {
std::vector<Suggestion> suggestions;
suggestions.emplace_back("123 Apple St.", "Charles", "accountIcon", 1);
suggestions.emplace_back("3734 Elvis Presley Blvd.", "Elvis", "accountIcon",
2);

suggestions.emplace_back(POPUP_ITEM_ID_SEPARATOR);

Suggestion settings(l10n_util::GetStringUTF16(IDS_AUTOFILL_MANAGE_ADDRESSES));
settings.frontend_id = POPUP_ITEM_ID_AUTOFILL_OPTIONS;
settings.icon = "settingsIcon";
suggestions.push_back(std::move(settings));

PrepareSuggestions(std::move(suggestions));
ShowAndVerifyUi();
}

IN_PROC_BROWSER_TEST_P(AutofillPopupViewNativeViewsTest,
InvokeUi_Passwords_PasswordField) {
// An account store entry.
std::vector<Suggestion> suggestions;
Suggestion entry1(u"User1");
entry1.main_text.is_primary = Suggestion::Text::IsPrimary(true);
entry1.additional_label =
std::u16string(10, gfx::RenderText::kPasswordReplacementChar);
entry1.frontend_id = POPUP_ITEM_ID_ACCOUNT_STORAGE_PASSWORD_ENTRY;
entry1.icon = "globeIcon";
entry1.trailing_icon = "google";
suggestions.push_back(std::move(entry1));

// A profile store entry.
Suggestion entry2(u"User2");
entry2.main_text.is_primary = Suggestion::Text::IsPrimary(true);
entry2.additional_label =
std::u16string(6, gfx::RenderText::kPasswordReplacementChar);
entry2.frontend_id = POPUP_ITEM_ID_PASSWORD_ENTRY;
entry2.icon = "globeIcon";
entry2.trailing_icon = "";
suggestions.push_back(std::move(entry2));

suggestions.emplace_back(POPUP_ITEM_ID_SEPARATOR);

// The entry to open settings.
Suggestion settings(
l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_MANAGE_PASSWORDS));
settings.frontend_id = POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY;
settings.icon = "settingsIcon";
settings.trailing_icon = "googlePasswordManager";
suggestions.push_back(std::move(settings));

PrepareSuggestions(std::move(suggestions));
ShowAndVerifyUi();
}

IN_PROC_BROWSER_TEST_P(AutofillPopupViewNativeViewsTest,
InvokeUi_InsecureContext_PaymentDisabled) {
Suggestion warning(
l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_INSECURE_CONNECTION));
warning.frontend_id = POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE;
PrepareSuggestions({std::move(warning)});
ShowAndVerifyUi();
}

INSTANTIATE_TEST_SUITE_P(All,
AutofillPopupViewNativeViewsTest,
testing::Bool());

} // namespace autofill
1 change: 1 addition & 0 deletions chrome/test/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -3401,6 +3401,7 @@ if (!is_android) {
"../browser/ui/global_error/global_error_service_browsertest.cc",
"../browser/ui/media_router/presentation_receiver_window_controller_browsertest.cc",
"../browser/ui/views/autofill/autofill_popup_base_view_browsertest.cc",
"../browser/ui/views/autofill/autofill_popup_view_native_views_browsertest.cc",
"../browser/ui/views/autofill/payments/autofill_error_dialog_view_native_views_browsertest.cc",
"../browser/ui/views/autofill/payments/autofill_progress_dialog_views_browsertest.cc",
"../browser/ui/views/autofill/payments/card_unmask_authentication_selection_dialog_browsertest.cc",
Expand Down
1 change: 1 addition & 0 deletions testing/buildbot/filters/pixel_tests.filter
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ AccessCodeCastDialogBrowserTest.*
AppInfoDialogBrowserTest.*
AskGoogleForSuggestionsDialogTest.*
AssistantOnboardingViewBrowserTest.InvokeUi_*
*AutofillPopupViewNativeViewsTest*
BookmarkBubbleViewBrowserTest.*
BookmarkEditorViewBrowserTest.*
BubbleFrameViewBrowserTest.*
Expand Down

0 comments on commit db3c3f9

Please sign in to comment.