1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "base/command_line.h"
8 #include "base/compiler_specific.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/test/histogram_tester.h"
13 #include "components/autofill/core/browser/autofill_manager.h"
14 #include "components/autofill/core/browser/autofill_metrics.h"
15 #include "components/autofill/core/browser/popup_item_ids.h"
16 #include "components/autofill/core/browser/suggestion_test_helpers.h"
17 #include "components/autofill/core/browser/test_autofill_client.h"
18 #include "components/autofill/core/browser/test_autofill_driver.h"
19 #include "components/autofill/core/browser/test_autofill_external_delegate.h"
20 #include "components/autofill/core/common/autofill_switches.h"
21 #include "components/autofill/core/common/form_data.h"
22 #include "components/autofill/core/common/form_field_data.h"
23 #include "components/autofill/core/common/password_form_fill_data.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "ui/gfx/geometry/rect.h"
28 using base::ASCIIToUTF16
;
35 // A constant value to use as the Autofill query ID.
36 const int kQueryId
= 5;
38 // A constant value to use as an Autofill profile ID.
39 const int kAutofillProfileId
= 1;
41 class MockAutofillDriver
: public TestAutofillDriver
{
43 MockAutofillDriver() {}
44 // Mock methods to enable testability.
45 MOCK_METHOD1(RendererShouldAcceptDataListSuggestion
,
46 void(const base::string16
&));
47 MOCK_METHOD0(RendererShouldClearFilledForm
, void());
48 MOCK_METHOD0(RendererShouldClearPreviewedForm
, void());
49 MOCK_METHOD1(RendererShouldFillFieldWithValue
, void(const base::string16
&));
50 MOCK_METHOD1(RendererShouldPreviewFieldWithValue
,
51 void(const base::string16
&));
54 DISALLOW_COPY_AND_ASSIGN(MockAutofillDriver
);
57 class MockAutofillClient
: public TestAutofillClient
{
59 MockAutofillClient() {}
61 MOCK_METHOD1(ScanCreditCard
,
62 void(const CreditCardScanCallback
& callbacK
));
64 MOCK_METHOD4(ShowAutofillPopup
,
65 void(const gfx::RectF
& element_bounds
,
66 base::i18n::TextDirection text_direction
,
67 const std::vector
<Suggestion
>& suggestions
,
68 base::WeakPtr
<AutofillPopupDelegate
> delegate
));
70 MOCK_METHOD2(UpdateAutofillPopupDataListValues
,
71 void(const std::vector
<base::string16
>& values
,
72 const std::vector
<base::string16
>& lables
));
74 MOCK_METHOD0(HideAutofillPopup
, void());
77 DISALLOW_COPY_AND_ASSIGN(MockAutofillClient
);
80 class MockAutofillManager
: public AutofillManager
{
82 MockAutofillManager(AutofillDriver
* driver
, MockAutofillClient
* client
)
83 // Force to use the constructor designated for unit test, but we don't
84 // really need personal_data in this test so we pass a NULL pointer.
85 : AutofillManager(driver
, client
, NULL
) {}
86 virtual ~MockAutofillManager() {}
88 MOCK_METHOD2(ShouldShowScanCreditCard
,
89 bool(const FormData
& form
, const FormFieldData
& field
));
91 MOCK_METHOD5(FillOrPreviewForm
,
92 void(AutofillDriver::RendererFormDataAction action
,
95 const FormFieldData
& field
,
98 MOCK_METHOD4(FillCreditCardForm
,
100 const FormData
& form
,
101 const FormFieldData
& field
,
102 const CreditCard
& credit_card
));
105 DISALLOW_COPY_AND_ASSIGN(MockAutofillManager
);
110 class AutofillExternalDelegateUnitTest
: public testing::Test
{
112 void SetUp() override
{
113 autofill_driver_
.reset(new testing::NiceMock
<MockAutofillDriver
>());
114 autofill_manager_
.reset(
115 new MockAutofillManager(autofill_driver_
.get(), &autofill_client_
));
116 external_delegate_
.reset(
117 new AutofillExternalDelegate(
118 autofill_manager_
.get(), autofill_driver_
.get()));
121 void TearDown() override
{
122 // Order of destruction is important as AutofillManager relies on
123 // PersonalDataManager to be around when it gets destroyed.
124 autofill_manager_
.reset();
125 external_delegate_
.reset();
126 autofill_driver_
.reset();
129 // Issue an OnQuery call with the given |query_id|.
130 void IssueOnQuery(int query_id
) {
133 field
.is_focusable
= true;
134 field
.should_autocomplete
= true;
135 const gfx::RectF element_bounds
;
137 external_delegate_
->OnQuery(query_id
, form
, field
, element_bounds
);
140 void IssueOnSuggestionsReturned() {
141 std::vector
<Suggestion
> suggestions
;
142 suggestions
.push_back(Suggestion());
143 suggestions
[0].frontend_id
= kAutofillProfileId
;
144 external_delegate_
->OnSuggestionsReturned(kQueryId
, suggestions
);
147 testing::NiceMock
<MockAutofillClient
> autofill_client_
;
148 scoped_ptr
<testing::NiceMock
<MockAutofillDriver
>> autofill_driver_
;
149 scoped_ptr
<MockAutofillManager
> autofill_manager_
;
150 scoped_ptr
<AutofillExternalDelegate
> external_delegate_
;
152 base::MessageLoop message_loop_
;
155 // Test that our external delegate called the virtual methods at the right time.
156 TEST_F(AutofillExternalDelegateUnitTest
, TestExternalDelegateVirtualCalls
) {
157 IssueOnQuery(kQueryId
);
159 // The enums must be cast to ints to prevent compile errors on linux_rel.
160 auto element_ids
= testing::ElementsAre(
162 #if !defined(OS_ANDROID)
163 static_cast<int>(POPUP_ITEM_ID_SEPARATOR
),
165 static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS
));
168 ShowAutofillPopup(_
, _
, SuggestionVectorIdsAre(element_ids
), _
));
170 // This should call ShowAutofillPopup.
171 std::vector
<Suggestion
> autofill_item
;
172 autofill_item
.push_back(Suggestion());
173 autofill_item
[0].frontend_id
= kAutofillProfileId
;
174 external_delegate_
->OnSuggestionsReturned(kQueryId
, autofill_item
);
176 EXPECT_CALL(*autofill_manager_
,
178 AutofillDriver::FORM_DATA_ACTION_FILL
, _
, _
, _
, _
));
179 EXPECT_CALL(autofill_client_
, HideAutofillPopup());
181 // This should trigger a call to hide the popup since we've selected an
183 external_delegate_
->DidAcceptSuggestion(autofill_item
[0].value
,
184 autofill_item
[0].frontend_id
,
188 // Test that data list elements for a node will appear in the Autofill popup.
189 TEST_F(AutofillExternalDelegateUnitTest
, ExternalDelegateDataList
) {
190 IssueOnQuery(kQueryId
);
192 std::vector
<base::string16
> data_list_items
;
193 data_list_items
.push_back(base::string16());
197 UpdateAutofillPopupDataListValues(data_list_items
, data_list_items
));
199 external_delegate_
->SetCurrentDataListValues(data_list_items
,
202 // The enums must be cast to ints to prevent compile errors on linux_rel.
203 auto element_ids
= testing::ElementsAre(
204 static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY
),
205 #if !defined(OS_ANDROID)
206 static_cast<int>(POPUP_ITEM_ID_SEPARATOR
),
209 #if !defined(OS_ANDROID)
210 static_cast<int>(POPUP_ITEM_ID_SEPARATOR
),
212 static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS
));
215 ShowAutofillPopup(_
, _
, SuggestionVectorIdsAre(element_ids
), _
));
217 // This should call ShowAutofillPopup.
218 std::vector
<Suggestion
> autofill_item
;
219 autofill_item
.push_back(Suggestion());
220 autofill_item
[0].frontend_id
= kAutofillProfileId
;
221 external_delegate_
->OnSuggestionsReturned(kQueryId
, autofill_item
);
223 // Try calling OnSuggestionsReturned with no Autofill values and ensure
224 // the datalist items are still shown.
225 // The enum must be cast to an int to prevent compile errors on linux_rel.
231 SuggestionVectorIdsAre(testing::ElementsAre(
232 static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY
))),
235 autofill_item
.clear();
236 external_delegate_
->OnSuggestionsReturned(kQueryId
, autofill_item
);
239 // Test that datalist values can get updated while a popup is showing.
240 TEST_F(AutofillExternalDelegateUnitTest
, UpdateDataListWhileShowingPopup
) {
241 IssueOnQuery(kQueryId
);
243 EXPECT_CALL(autofill_client_
, ShowAutofillPopup(_
, _
, _
, _
))
246 // Make sure just setting the data list values doesn't cause the popup to
248 std::vector
<base::string16
> data_list_items
;
249 data_list_items
.push_back(base::string16());
253 UpdateAutofillPopupDataListValues(data_list_items
, data_list_items
));
255 external_delegate_
->SetCurrentDataListValues(data_list_items
,
258 // The enums must be cast to ints to prevent compile errors on linux_rel.
259 auto element_ids
= testing::ElementsAre(
260 static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY
),
261 #if !defined(OS_ANDROID)
262 static_cast<int>(POPUP_ITEM_ID_SEPARATOR
),
265 #if !defined(OS_ANDROID)
266 static_cast<int>(POPUP_ITEM_ID_SEPARATOR
),
268 static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS
));
271 ShowAutofillPopup(_
, _
, SuggestionVectorIdsAre(element_ids
), _
));
273 // Ensure the popup is displayed.
274 std::vector
<Suggestion
> autofill_item
;
275 autofill_item
.push_back(Suggestion());
276 autofill_item
[0].frontend_id
= kAutofillProfileId
;
277 external_delegate_
->OnSuggestionsReturned(kQueryId
, autofill_item
);
279 // This would normally get called from ShowAutofillPopup, but it is mocked so
280 // we need to call OnPopupShown ourselves.
281 external_delegate_
->OnPopupShown();
283 // Update the current data list and ensure the popup is updated.
284 data_list_items
.push_back(base::string16());
286 // The enums must be cast to ints to prevent compile errors on linux_rel.
289 UpdateAutofillPopupDataListValues(data_list_items
, data_list_items
));
291 external_delegate_
->SetCurrentDataListValues(data_list_items
,
295 // Test that the Autofill popup is able to display warnings explaining why
296 // Autofill is disabled for a website.
297 // Regression test for http://crbug.com/247880
298 TEST_F(AutofillExternalDelegateUnitTest
, AutofillWarnings
) {
299 IssueOnQuery(kQueryId
);
301 // The enums must be cast to ints to prevent compile errors on linux_rel.
307 SuggestionVectorIdsAre(testing::ElementsAre(
308 static_cast<int>(POPUP_ITEM_ID_WARNING_MESSAGE
))),
311 // This should call ShowAutofillPopup.
312 std::vector
<Suggestion
> autofill_item
;
313 autofill_item
.push_back(Suggestion());
314 autofill_item
[0].frontend_id
= POPUP_ITEM_ID_WARNING_MESSAGE
;
315 external_delegate_
->OnSuggestionsReturned(kQueryId
, autofill_item
);
318 // Test that the Autofill delegate doesn't try and fill a form with a
319 // negative unique id.
320 TEST_F(AutofillExternalDelegateUnitTest
, ExternalDelegateInvalidUniqueId
) {
321 // Ensure it doesn't try to preview the negative id.
322 EXPECT_CALL(*autofill_manager_
, FillOrPreviewForm(_
, _
, _
, _
, _
)).Times(0);
323 EXPECT_CALL(*autofill_driver_
, RendererShouldClearPreviewedForm()).Times(1);
324 external_delegate_
->DidSelectSuggestion(base::string16(), -1);
326 // Ensure it doesn't try to fill the form in with the negative id.
327 EXPECT_CALL(autofill_client_
, HideAutofillPopup());
328 EXPECT_CALL(*autofill_manager_
, FillOrPreviewForm(_
, _
, _
, _
, _
)).Times(0);
329 external_delegate_
->DidAcceptSuggestion(base::string16(), -1, 0);
332 // Test that the ClearPreview call is only sent if the form was being previewed
333 // (i.e. it isn't autofilling a password).
334 TEST_F(AutofillExternalDelegateUnitTest
, ExternalDelegateClearPreviewedForm
) {
335 // Ensure selecting a new password entries or Autofill entries will
336 // cause any previews to get cleared.
337 EXPECT_CALL(*autofill_driver_
, RendererShouldClearPreviewedForm()).Times(1);
338 external_delegate_
->DidSelectSuggestion(ASCIIToUTF16("baz foo"),
339 POPUP_ITEM_ID_PASSWORD_ENTRY
);
340 EXPECT_CALL(*autofill_driver_
, RendererShouldClearPreviewedForm()).Times(1);
341 EXPECT_CALL(*autofill_manager_
,
343 AutofillDriver::FORM_DATA_ACTION_PREVIEW
, _
, _
, _
, _
));
344 external_delegate_
->DidSelectSuggestion(ASCIIToUTF16("baz foo"), 1);
346 // Ensure selecting an autocomplete entry will cause any previews to
348 EXPECT_CALL(*autofill_driver_
, RendererShouldClearPreviewedForm()).Times(1);
349 EXPECT_CALL(*autofill_driver_
, RendererShouldPreviewFieldWithValue(
350 ASCIIToUTF16("baz foo")));
351 external_delegate_
->DidSelectSuggestion(ASCIIToUTF16("baz foo"),
352 POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY
);
355 // Test that the popup is hidden once we are done editing the autofill field.
356 TEST_F(AutofillExternalDelegateUnitTest
,
357 ExternalDelegateHidePopupAfterEditing
) {
358 EXPECT_CALL(autofill_client_
, ShowAutofillPopup(_
, _
, _
, _
));
359 GenerateTestAutofillPopup(external_delegate_
.get());
361 EXPECT_CALL(autofill_client_
, HideAutofillPopup());
362 external_delegate_
->DidEndTextFieldEditing();
365 // Test that the driver is directed to accept the data list after being notified
366 // that the user accepted the data list suggestion.
367 TEST_F(AutofillExternalDelegateUnitTest
,
368 ExternalDelegateAcceptDatalistSuggestion
) {
369 EXPECT_CALL(autofill_client_
, HideAutofillPopup());
370 base::string16
dummy_string(ASCIIToUTF16("baz qux"));
371 EXPECT_CALL(*autofill_driver_
,
372 RendererShouldAcceptDataListSuggestion(dummy_string
));
373 external_delegate_
->DidAcceptSuggestion(dummy_string
,
374 POPUP_ITEM_ID_DATALIST_ENTRY
,
378 // Test that an accepted autofill suggestion will fill the form and log the
380 TEST_F(AutofillExternalDelegateUnitTest
,
381 ExternalDelegateAcceptAutofillSuggestion
) {
382 EXPECT_CALL(autofill_client_
, HideAutofillPopup());
383 base::string16
dummy_string(ASCIIToUTF16("John Legend"));
384 EXPECT_CALL(*autofill_manager_
,
386 AutofillDriver::FORM_DATA_ACTION_FILL
, _
, _
, _
,
387 kAutofillProfileId
));
388 base::HistogramTester histogram
;
389 external_delegate_
->DidAcceptSuggestion(dummy_string
,
392 histogram
.ExpectUniqueSample("Autofill.SuggestionAcceptedIndex", 2, 1);
395 // Test that the driver is directed to clear the form after being notified that
396 // the user accepted the suggestion to clear the form.
397 TEST_F(AutofillExternalDelegateUnitTest
, ExternalDelegateClearForm
) {
398 EXPECT_CALL(autofill_client_
, HideAutofillPopup());
399 EXPECT_CALL(*autofill_driver_
, RendererShouldClearFilledForm());
401 external_delegate_
->DidAcceptSuggestion(base::string16(),
402 POPUP_ITEM_ID_CLEAR_FORM
,
406 // Test that autofill client will scan a credit card after use accepted the
407 // suggestion to scan a credit card.
408 TEST_F(AutofillExternalDelegateUnitTest
, ScanCreditCardMenuItem
) {
409 EXPECT_CALL(autofill_client_
, ScanCreditCard(_
));
410 EXPECT_CALL(autofill_client_
, HideAutofillPopup());
411 external_delegate_
->DidAcceptSuggestion(base::string16(),
412 POPUP_ITEM_ID_SCAN_CREDIT_CARD
,
416 TEST_F(AutofillExternalDelegateUnitTest
, ScanCreditCardPromptMetricsTest
) {
417 // Log that the scan card item was shown, although nothing was selected.
419 EXPECT_CALL(*autofill_manager_
, ShouldShowScanCreditCard(_
, _
))
420 .WillOnce(testing::Return(true));
421 base::HistogramTester histogram
;
422 IssueOnQuery(kQueryId
);
423 IssueOnSuggestionsReturned();
424 external_delegate_
->OnPopupHidden();
425 histogram
.ExpectUniqueSample("Autofill.ScanCreditCardPrompt",
426 AutofillMetrics::SCAN_CARD_ITEM_SHOWN
, 1);
428 // Log that the scan card item was selected.
430 EXPECT_CALL(*autofill_manager_
, ShouldShowScanCreditCard(_
, _
))
431 .WillOnce(testing::Return(true));
432 base::HistogramTester histogram
;
433 IssueOnQuery(kQueryId
);
434 IssueOnSuggestionsReturned();
435 external_delegate_
->DidAcceptSuggestion(base::string16(),
436 POPUP_ITEM_ID_SCAN_CREDIT_CARD
,
438 histogram
.ExpectBucketCount("Autofill.ScanCreditCardPrompt",
439 AutofillMetrics::SCAN_CARD_ITEM_SHOWN
, 1);
440 histogram
.ExpectBucketCount("Autofill.ScanCreditCardPrompt",
441 AutofillMetrics::SCAN_CARD_ITEM_SELECTED
, 1);
442 histogram
.ExpectBucketCount("Autofill.ScanCreditCardPrompt",
443 AutofillMetrics::SCAN_CARD_OTHER_ITEM_SELECTED
,
446 // Log that something else was selected.
448 EXPECT_CALL(*autofill_manager_
, ShouldShowScanCreditCard(_
, _
))
449 .WillOnce(testing::Return(true));
450 base::HistogramTester histogram
;
451 IssueOnQuery(kQueryId
);
452 IssueOnSuggestionsReturned();
453 external_delegate_
->DidAcceptSuggestion(base::string16(),
454 POPUP_ITEM_ID_CLEAR_FORM
,
456 histogram
.ExpectBucketCount("Autofill.ScanCreditCardPrompt",
457 AutofillMetrics::SCAN_CARD_ITEM_SHOWN
, 1);
458 histogram
.ExpectBucketCount("Autofill.ScanCreditCardPrompt",
459 AutofillMetrics::SCAN_CARD_ITEM_SELECTED
, 0);
460 histogram
.ExpectBucketCount("Autofill.ScanCreditCardPrompt",
461 AutofillMetrics::SCAN_CARD_OTHER_ITEM_SELECTED
,
464 // Nothing is logged when the item isn't shown.
466 EXPECT_CALL(*autofill_manager_
, ShouldShowScanCreditCard(_
, _
))
467 .WillOnce(testing::Return(false));
468 base::HistogramTester histogram
;
469 IssueOnQuery(kQueryId
);
470 IssueOnSuggestionsReturned();
471 external_delegate_
->DidAcceptSuggestion(base::string16(),
472 POPUP_ITEM_ID_CLEAR_FORM
,
474 histogram
.ExpectTotalCount("Autofill.ScanCreditCardPrompt", 0);
478 // Test that autofill manager will fill the credit card form after user scans a
480 TEST_F(AutofillExternalDelegateUnitTest
, FillCreditCardForm
) {
481 base::string16 card_number
= base::ASCIIToUTF16("test");
482 int expiration_month
= 1;
483 int expiration_year
= 3000;
487 _
, _
, _
, CreditCard(card_number
, expiration_month
, expiration_year
)));
488 external_delegate_
->OnCreditCardScanned(card_number
, expiration_month
,
492 TEST_F(AutofillExternalDelegateUnitTest
, IgnoreAutocompleteOffForAutofill
) {
495 field
.is_focusable
= true;
496 field
.should_autocomplete
= false;
497 const gfx::RectF element_bounds
;
499 external_delegate_
->OnQuery(kQueryId
, form
, field
, element_bounds
);
501 std::vector
<Suggestion
> autofill_items
;
502 autofill_items
.push_back(Suggestion());
503 autofill_items
[0].frontend_id
= POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY
;
505 // Ensure the popup tries to show itself, despite autocomplete="off".
506 EXPECT_CALL(autofill_client_
, ShowAutofillPopup(_
, _
, _
, _
));
507 EXPECT_CALL(autofill_client_
, HideAutofillPopup()).Times(0);
509 external_delegate_
->OnSuggestionsReturned(kQueryId
, autofill_items
);
512 TEST_F(AutofillExternalDelegateUnitTest
, ExternalDelegateFillFieldWithValue
) {
513 EXPECT_CALL(autofill_client_
, HideAutofillPopup());
514 base::string16
dummy_string(ASCIIToUTF16("baz foo"));
515 EXPECT_CALL(*autofill_driver_
,
516 RendererShouldFillFieldWithValue(dummy_string
));
517 external_delegate_
->DidAcceptSuggestion(dummy_string
,
518 POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY
,
522 } // namespace autofill