File: chrome_autofill_client_interactive_uitest.cc

package info (click to toggle)
chromium 138.0.7204.157-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,864 kB
  • sloc: cpp: 34,936,859; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,967; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (202 lines) | stat: -rw-r--r-- 8,284 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// 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 "base/i18n/rtl.h"
#include "base/memory/weak_ptr.h"
#include "base/test/run_until.h"
#include "chrome/browser/ui/autofill/chrome_autofill_client.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/content/browser/test_autofill_client_injector.h"
#include "components/autofill/content/browser/test_autofill_driver_injector.h"
#include "components/autofill/core/browser/filling/filling_product.h"
#include "components/autofill/core/browser/foundations/browser_autofill_manager.h"
#include "components/autofill/core/browser/foundations/browser_autofill_manager_test_api.h"
#include "components/autofill/core/browser/suggestions/suggestion.h"
#include "components/autofill/core/browser/test_utils/autofill_test_utils.h"
#include "components/autofill/core/browser/ui/autofill_external_delegate.h"
#include "components/autofill/core/browser/ui/popup_open_enums.h"
#include "components/autofill/core/common/aliases.h"
#include "components/autofill/core/common/autofill_test_utils.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_data_test_api.h"
#include "components/feature_engagement/public/feature_constants.h"
#include "components/feature_engagement/test/scoped_iph_feature_list.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"
#include "ui/gfx/geometry/rect_f.h"
#include "url/gurl.h"

namespace autofill {

namespace {

using ::testing::Not;
using ::testing::Optional;
using ::testing::Return;

class TestAutofillExternalDelegate : public AutofillExternalDelegate {
 public:
  explicit TestAutofillExternalDelegate(
      BrowserAutofillManager* autofill_manager)
      : AutofillExternalDelegate(autofill_manager) {}
  ~TestAutofillExternalDelegate() override = default;

  void OnSuggestionsShown(base::span<const Suggestion>) override {
    ++show_counter_;
  }

  FillingProduct GetMainFillingProduct() const override {
    return FillingProduct::kAutocomplete;
  }

  int show_counter() const { return show_counter_; }

 private:
  int show_counter_ = 0;
};

// This test class is needed to make the constructor public.
class TestChromeAutofillClient : public ChromeAutofillClient {
 public:
  explicit TestChromeAutofillClient(content::WebContents* web_contents)
      : ChromeAutofillClient(web_contents) {}
  ~TestChromeAutofillClient() override = default;
};

class ChromeAutofillClientBrowserTest : public InProcessBrowserTest {
 public:
  void SetUpInProcessBrowserTestFixture() override {
    // `BrowserWindow::MaybeShowFeaturePromo()` doesn't work in tests unless the
    // IPH feature is explicitly enabled.
    iph_feature_list_.InitAndEnableFeatures(
        {feature_engagement::kIPHAutofillAiOptInFeature});
  }

  void SetUpOnMainThread() override {
    ASSERT_TRUE(
        ui_test_utils::NavigateToURL(browser(), GURL("http://test.com")));

    test_api(browser_autofill_manager())
        .SetExternalDelegate(std::make_unique<TestAutofillExternalDelegate>(
            &browser_autofill_manager()));
  }

  TestChromeAutofillClient* client() {
    return autofill_client_injector_[web_contents()];
  }

  ContentAutofillDriver* driver() {
    return autofill_driver_injector_[web_contents()->GetPrimaryMainFrame()];
  }

  BrowserAutofillManager& browser_autofill_manager() {
    return static_cast<BrowserAutofillManager&>(driver()->GetAutofillManager());
  }

  content::WebContents* web_contents() const {
    return browser()->tab_strip_model()->GetActiveWebContents();
  }

  AutofillClient::SuggestionUiSessionId ShowSuggestions(
      const gfx::RectF& bounds) {
    return client()->ShowAutofillSuggestions(
        ChromeAutofillClient::PopupOpenArgs(
            bounds, base::i18n::TextDirection::LEFT_TO_RIGHT,
            {Suggestion(u"test")},
            AutofillSuggestionTriggerSource::kFormControlElementClicked,
            /*form_control_ax_id=*/0, PopupAnchorType::kField),
        test_api(browser_autofill_manager())
            .external_delegate()
            ->GetWeakPtrForTest());
  }

  // Waits until the suggestions have been at least once more since calling this
  // function.
  void WaitUntilSuggestionsHaveBeenShown(
      const base::Location& location = FROM_HERE) {
    EXPECT_TRUE(base::test::RunUntil([this, initial_count =
                                                suggestion_show_counter()]() {
      return suggestion_show_counter() > initial_count;
    })) << location.ToString()
        << ": Showing Autofill suggestions timed out.";
  }

  // Returns show many times the suggestions have been shown or updated.
  int suggestion_show_counter() {
    return static_cast<TestAutofillExternalDelegate*>(
               test_api(browser_autofill_manager()).external_delegate())
        ->show_counter();
  }

 private:
  test::AutofillBrowserTestEnvironment autofill_test_environment_;
  feature_engagement::test::ScopedIphFeatureList iph_feature_list_;
  TestAutofillClientInjector<TestChromeAutofillClient>
      autofill_client_injector_;
  TestAutofillDriverInjector<ContentAutofillDriver> autofill_driver_injector_;
};

// This test displays an autofill field IPH, and then tries to show the Autofill
// Popup on top of it (they would overlap). The expected behaviour is
// that the IPH is hidden and the Autofill Popup is successfully shown.
IN_PROC_BROWSER_TEST_F(ChromeAutofillClientBrowserTest,
                       AutofillPopupIsShownIfOverlappingWithIph) {
  FormData form = test::CreateTestAddressFormData();
  test_api(form).field(0).set_bounds(gfx::RectF(10, 10));
  client()->ShowAutofillFieldIphForFeature(
      form.fields()[0], AutofillClient::IphFeature::kAutofillAi);

  // Set the bounds such that the Autofill Popup would overlap with the IPH (the
  // IPH is displayed right below `form.fields[0]`, whose bounds are set above).
  ShowSuggestions(/*bounds=*/gfx::RectF(100, 100));
  WaitUntilSuggestionsHaveBeenShown();

  EXPECT_FALSE(browser()->window()->IsFeaturePromoActive(
      feature_engagement::kIPHAutofillAiOptInFeature));
}

IN_PROC_BROWSER_TEST_F(ChromeAutofillClientBrowserTest, SuggestionUiSessionId) {
  // Before a popup is showing, no identifier is returned.
  EXPECT_EQ(client()->GetSessionIdForCurrentAutofillSuggestions(),
            std::nullopt);

  // Showing suggestions leads (asynchronously) to showing a popup with the
  // identifier returned by ShowAutofillSuggestions.
  const AutofillClient::SuggestionUiSessionId first_id =
      ShowSuggestions(gfx::RectF(50, 50));
  WaitUntilSuggestionsHaveBeenShown();
  EXPECT_THAT(client()->GetSessionIdForCurrentAutofillSuggestions(),
              std::make_optional(first_id));

  const AutofillClient::SuggestionUiSessionId second_id =
      ShowSuggestions(gfx::RectF(60, 60));
  EXPECT_NE(first_id, second_id);
  // Since showing suggestions is asynchronous, the identifier returned by
  // ShowAutofillSuggestions can be different from the one currently showing.
  EXPECT_THAT(client()->GetSessionIdForCurrentAutofillSuggestions(),
              Not(Optional(second_id)));
  // But once the new popup has been shown, they will be the same.
  WaitUntilSuggestionsHaveBeenShown();
  EXPECT_THAT(client()->GetSessionIdForCurrentAutofillSuggestions(),
              Optional(second_id));

  // Updating the suggestions does not lead to a new identifier. Note that
  // updating the suggestions is synchronous.
  const int old_count = suggestion_show_counter();
  client()->UpdateAutofillSuggestions(
      {Suggestion(u"other text")}, FillingProduct::kAutocomplete,
      AutofillSuggestionTriggerSource::kUnspecified);
  EXPECT_GT(suggestion_show_counter(), old_count);
  EXPECT_THAT(client()->GetSessionIdForCurrentAutofillSuggestions(),
              Optional(second_id));
}

}  // namespace
}  // namespace autofill