Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(74)

Unified Diff: ios/chrome/browser/autofill/autofill_controller_unittest.mm

Issue 2580363002: Upstream Chrome on iOS source code [1/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ios/chrome/browser/autofill/autofill_controller_unittest.mm
diff --git a/ios/chrome/browser/autofill/autofill_controller_unittest.mm b/ios/chrome/browser/autofill/autofill_controller_unittest.mm
new file mode 100644
index 0000000000000000000000000000000000000000..5942a05b0dc1d313d5880b4c6a17115bb673db8b
--- /dev/null
+++ b/ios/chrome/browser/autofill/autofill_controller_unittest.mm
@@ -0,0 +1,587 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/autofill/autofill_controller.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/guid.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/histogram_tester.h"
+#import "base/test/ios/wait_util.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/ios/browser/autofill_driver_ios.h"
+#import "components/autofill/ios/browser/form_suggestion.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "components/infobars/core/infobar.h"
+#include "components/infobars/core/infobar_manager.h"
+#include "components/keyed_service/core/service_access_type.h"
+#import "ios/chrome/browser/autofill/autofill_agent.h"
+#import "ios/chrome/browser/autofill/form_input_accessory_view_controller.h"
+#import "ios/chrome/browser/autofill/form_suggestion_controller.h"
+#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#include "ios/chrome/browser/infobars/infobar_manager_impl.h"
+#import "ios/chrome/browser/ui/autofill/autofill_client_ios.h"
+#import "ios/chrome/browser/web/chrome_web_test.h"
+#include "ios/chrome/browser/web_data_service_factory.h"
+#import "ios/web/public/web_state/web_state.h"
+#import "testing/gtest_mac.h"
+#include "ui/base/test/ios/ui_view_test_utils.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// Real FormSuggestionController is wrapped to register the addition of
+// suggestions.
+@interface TestSuggestionController : FormSuggestionController
+
+@property(nonatomic, copy) NSArray* suggestions;
+@property(nonatomic, assign) BOOL suggestionRetrievalComplete;
+
+@end
+
+@implementation TestSuggestionController
+
+@synthesize suggestions = _suggestions;
+@synthesize suggestionRetrievalComplete = _suggestionRetrievalComplete;
+
+- (void)retrieveSuggestionsForFormNamed:(const std::string&)formName
+ fieldName:(const std::string&)fieldName
+ type:(const std::string&)type
+ webState:(web::WebState*)webState {
+ self.suggestionRetrievalComplete = NO;
+ [super retrieveSuggestionsForFormNamed:formName
+ fieldName:fieldName
+ type:type
+ webState:webState];
+}
+
+- (void)updateKeyboardWithSuggestions:(NSArray*)suggestions {
+ self.suggestions = suggestions;
+ self.suggestionRetrievalComplete = YES;
+}
+
+- (void)onNoSuggestionsAvailable {
+ self.suggestionRetrievalComplete = YES;
+};
+
+@end
+
+namespace autofill {
+
+namespace {
+
+// The profile-type form used by tests.
+NSString* const kProfileFormHtml =
+ @"<form action='/submit' method='post'>"
+ "Name <input type='text' name='name'>"
+ "Address <input type='text' name='address'>"
+ "City <input type='text' name='city'>"
+ "State <input type='text' name='state'>"
+ "Zip <input type='text' name='zip'>"
+ "<input type='submit' id='submit' value='Submit'>"
+ "</form>";
+
+// A minimal form with a name.
+NSString* const kMinimalFormWithNameHtml = @"<form id='form1'>"
+ "<input name='name'>"
+ "<input name='address'>"
+ "<input name='city'>"
+ "</form>";
+
+// The key/value-type form used by tests.
+NSString* const kKeyValueFormHtml =
+ @"<form action='/submit' method='post'>"
+ "Greeting <input type='text' name='greeting'>"
+ "Dummy field <input type='text' name='dummy'>"
+ "<input type='submit' id='submit' value='Submit'>"
+ "</form>";
+
+// The credit card-type form used by tests.
+NSString* const kCreditCardFormHtml =
+ @"<form action='/submit' method='post'>"
+ "Name on card: <input type='text' name='name'>"
+ "Credit card number: <input type='text' name='CCNo'>"
+ "Expiry Month: <input type='text' name='CCExpiresMonth'>"
+ "Expiry Year: <input type='text' name='CCExpiresYear'>"
+ "<input type='submit' id='submit' value='Submit'>"
+ "</form>";
+
+// Experiment preference key.
+NSString* const kAutofillVisible = @"AutofillVisible";
+
+// FAIL if a field with the supplied |name| and |fieldType| is not present on
+// the |form|.
+void CheckField(const FormStructure& form,
+ ServerFieldType fieldType,
+ const char* name) {
+ for (const AutofillField* field : form) {
+ if (field->heuristic_type() == fieldType) {
+ EXPECT_EQ(base::UTF8ToUTF16(name), field->unique_name());
+ return;
+ }
+ }
+ FAIL() << "Missing field " << name;
+}
+
+// WebDataServiceConsumer for receving vectors of strings and making them
+// available to tests.
+class TestConsumer : public WebDataServiceConsumer {
+ public:
+ void OnWebDataServiceRequestDone(
+ WebDataServiceBase::Handle handle,
+ std::unique_ptr<WDTypedResult> result) override {
+ DCHECK_EQ(result->GetType(), AUTOFILL_VALUE_RESULT);
+ result_ = static_cast<WDResult<std::vector<base::string16>>*>(result.get())
+ ->GetValue();
+ }
+ std::vector<base::string16> result_;
+};
+
+// Text fixture to test autofill.
+class AutofillControllerTest : public ChromeWebTest {
+ public:
+ AutofillControllerTest() = default;
+ ~AutofillControllerTest() override {}
+
+ protected:
+ void SetUp() override;
+ void TearDown() override;
+ void SetUpForSuggestions(NSString* data);
+
+ // Adds key value data to the Personal Data Manager.
+ void SetUpKeyValueData();
+
+ // Blocks until suggestion retrieval has completed.
+ void WaitForSuggestionRetrieval();
+
+ // Fails if the specified metric was not registered the given number of times.
+ void ExpectMetric(const std::string& histogram_name, int sum);
+
+ // Fails if the specified user happiness metric was not registered.
+ void ExpectHappinessMetric(AutofillMetrics::UserHappinessMetric metric);
+
+ TestSuggestionController* suggestion_controller() {
+ return suggestion_controller_;
+ }
+
+ private:
+ // Weak pointer to AutofillAgent, owned by the AutofillController.
+ __weak AutofillAgent* autofill_agent_;
+
+ // Histogram tester for these tests.
+ std::unique_ptr<base::HistogramTester> histogram_tester_;
+
+ // Retrieves suggestions according to form events.
+ TestSuggestionController* suggestion_controller_;
+
+ // Retrieves accessory views according to form events.
+ FormInputAccessoryViewController* accessory_controller_;
+
+ // Manages autofill for a single page.
+ AutofillController* autofill_controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutofillControllerTest);
+};
+
+void AutofillControllerTest::SetUp() {
+ ChromeWebTest::SetUp();
+
+ // Profile import requires a PersonalDataManager which itself needs the
+ // WebDataService; this is not initialized on a TestChromeBrowserState by
+ // default.
+ chrome_browser_state_->CreateWebDataService();
+ // Enable autofill experiment.
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults setBool:YES forKey:kAutofillVisible];
+
+ AutofillAgent* agent =
+ [[AutofillAgent alloc] initWithBrowserState:chrome_browser_state_.get()
+ webState:web_state()];
+ autofill_agent_ = agent;
+ InfoBarManagerImpl::CreateForWebState(web_state());
+ autofill_controller_ = [[AutofillController alloc]
+ initWithBrowserState:chrome_browser_state_.get()
+ webState:web_state()
+ autofillAgent:autofill_agent_
+ passwordGenerationManager:nullptr
+ downloadEnabled:NO];
+ suggestion_controller_ = [[TestSuggestionController alloc]
+ initWithWebState:web_state()
+ providers:@[ [autofill_controller_ suggestionProvider] ]];
+ accessory_controller_ = [[FormInputAccessoryViewController alloc]
+ initWithWebState:web_state()
+ providers:@[ [suggestion_controller_ accessoryViewProvider] ]];
+ histogram_tester_.reset(new base::HistogramTester());
+}
+
+void AutofillControllerTest::TearDown() {
+ [autofill_controller_ detachFromWebState];
+ [suggestion_controller_ detachFromWebState];
+
+ ChromeWebTest::TearDown();
+}
+
+void AutofillControllerTest::WaitForSuggestionRetrieval() {
+ // Wait for the message queue to ensure that JS events fired in the tests
+ // trigger TestSuggestionController's retrieveSuggestionsForFormNamed: method
+ // and set suggestionRetrievalComplete to NO.
+ WaitForBackgroundTasks();
+
+ // Now we can wait for suggestionRetrievalComplete to be set to YES.
+ WaitForCondition(^bool {
+ return [suggestion_controller() suggestionRetrievalComplete];
+ });
+}
+
+void AutofillControllerTest::ExpectMetric(const std::string& histogram_name,
+ int sum) {
+ histogram_tester_->ExpectBucketCount(histogram_name, sum, 1);
+}
+
+void AutofillControllerTest::ExpectHappinessMetric(
+ AutofillMetrics::UserHappinessMetric metric) {
+ histogram_tester_->ExpectBucketCount("Autofill.UserHappiness", metric, 1);
+}
+
+// Checks that viewing an HTML page containing a form results in the form being
+// registered as a FormStructure by the AutofillManager.
+TEST_F(AutofillControllerTest, ReadForm) {
+ AutofillManager* autofill_manager =
+ AutofillDriverIOS::FromWebState(web_state())->autofill_manager();
+ EXPECT_TRUE(autofill_manager->GetFormStructures().empty())
+ << "Forms are registered at beginning";
+ LoadHtml(kProfileFormHtml);
+ const std::vector<std::unique_ptr<FormStructure>>& forms =
+ autofill_manager->GetFormStructures();
+ ASSERT_EQ(1U, forms.size());
+ CheckField(*forms[0], NAME_FULL, "name_1");
+ CheckField(*forms[0], ADDRESS_HOME_LINE1, "address_1");
+ CheckField(*forms[0], ADDRESS_HOME_CITY, "city_1");
+ CheckField(*forms[0], ADDRESS_HOME_STATE, "state_1");
+ CheckField(*forms[0], ADDRESS_HOME_ZIP, "zip_1");
+ ExpectMetric("Autofill.IsEnabled.PageLoad", 1);
+ ExpectHappinessMetric(AutofillMetrics::FORMS_LOADED);
+};
+
+// Checks that viewing an HTML page containing a form with an 'id' results in
+// the form being registered as a FormStructure by the AutofillManager, and the
+// name is correctly set.
+TEST_F(AutofillControllerTest, ReadFormName) {
+ AutofillManager* autofill_manager =
+ AutofillDriverIOS::FromWebState(web_state())->autofill_manager();
+ LoadHtml(kMinimalFormWithNameHtml);
+ const std::vector<std::unique_ptr<FormStructure>>& forms =
+ autofill_manager->GetFormStructures();
+ ASSERT_EQ(1U, forms.size());
+ EXPECT_EQ(base::UTF8ToUTF16("form1"), forms[0]->ToFormData().name);
+};
+
+// Checks that an HTML page containing a profile-type form which is submitted
+// with scripts (simulating user form submission) results in a profile being
+// successfully imported into the PersonalDataManager.
+TEST_F(AutofillControllerTest, ProfileImport) {
+ AutofillManager* autofill_manager =
+ AutofillDriverIOS::FromWebState(web_state())->autofill_manager();
+ PersonalDataManager* personal_data_manager =
+ autofill_manager->client()->GetPersonalDataManager();
+ // Check there are no registered profiles already.
+ EXPECT_EQ(0U, personal_data_manager->GetProfiles().size());
+ LoadHtml(kProfileFormHtml);
+ ExecuteJavaScript(@"document.forms[0].name.value = 'Homer Simpson'");
+ ExecuteJavaScript(@"document.forms[0].address.value = '123 Main Street'");
+ ExecuteJavaScript(@"document.forms[0].city.value = 'Springfield'");
+ ExecuteJavaScript(@"document.forms[0].state.value = 'IL'");
+ ExecuteJavaScript(@"document.forms[0].zip.value = '55123'");
+ ExecuteJavaScript(@"submit.click()");
+ WaitForCondition(^bool {
+ return personal_data_manager->GetProfiles().size();
+ });
+ const std::vector<AutofillProfile*>& profiles =
+ personal_data_manager->GetProfiles();
+ if (profiles.size() != 1)
+ FAIL() << "Not exactly one profile found after attempted import";
+ const AutofillProfile& profile = *profiles[0];
+ EXPECT_EQ(base::UTF8ToUTF16("Homer Simpson"),
+ profile.GetInfo(AutofillType(NAME_FULL), "en-US"));
+ EXPECT_EQ(base::UTF8ToUTF16("123 Main Street"),
+ profile.GetInfo(AutofillType(ADDRESS_HOME_LINE1), "en-US"));
+ EXPECT_EQ(base::UTF8ToUTF16("Springfield"),
+ profile.GetInfo(AutofillType(ADDRESS_HOME_CITY), "en-US"));
+ EXPECT_EQ(base::UTF8ToUTF16("IL"),
+ profile.GetInfo(AutofillType(ADDRESS_HOME_STATE), "en-US"));
+ EXPECT_EQ(base::UTF8ToUTF16("55123"),
+ profile.GetInfo(AutofillType(ADDRESS_HOME_ZIP), "en-US"));
+};
+
+void AutofillControllerTest::SetUpForSuggestions(NSString* data) {
+ AutofillManager* autofill_manager =
+ AutofillDriverIOS::FromWebState(web_state())->autofill_manager();
+ PersonalDataManager* personal_data_manager =
+ autofill_manager->client()->GetPersonalDataManager();
+ AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+ profile.SetRawInfo(NAME_FULL, base::UTF8ToUTF16("Homer Simpson"));
+ profile.SetRawInfo(ADDRESS_HOME_LINE1, base::UTF8ToUTF16("123 Main Street"));
+ profile.SetRawInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16("Springfield"));
+ profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("IL"));
+ profile.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("55123"));
+ EXPECT_EQ(0U, personal_data_manager->GetProfiles().size());
+ personal_data_manager->SaveImportedProfile(profile);
+ EXPECT_EQ(1U, personal_data_manager->GetProfiles().size());
+ LoadHtml(data);
+}
+
+// Checks that focusing on a text element of a profile-type form will result in
+// suggestions being sent to the AutofillAgent, once data has been loaded into a
+// test data manager.
+TEST_F(AutofillControllerTest, ProfileSuggestions) {
+ SetUpForSuggestions(kProfileFormHtml);
+ WaitForBackgroundTasks();
+ ui::test::uiview_utils::ForceViewRendering(web_state()->GetView());
+ ExecuteJavaScript(@"document.forms[0].name.focus()");
+ WaitForSuggestionRetrieval();
+ ExpectMetric("Autofill.AddressSuggestionsCount", 1);
+ ExpectHappinessMetric(AutofillMetrics::SUGGESTIONS_SHOWN);
+ EXPECT_EQ(1U, [suggestion_controller() suggestions].count);
+ FormSuggestion* suggestion = [suggestion_controller() suggestions][0];
+ EXPECT_NSEQ(@"Homer Simpson", suggestion.value);
+};
+
+// Tests that the system is able to offer suggestions for an anonymous form when
+// there is another anonymous form on the page.
+TEST_F(AutofillControllerTest, ProfileSuggestionsTwoAnonymousForms) {
+ SetUpForSuggestions(
+ [NSString stringWithFormat:@"%@%@", kProfileFormHtml, kProfileFormHtml]);
+ WaitForBackgroundTasks();
+ ui::test::uiview_utils::ForceViewRendering(web_state()->GetView());
+ ExecuteJavaScript(@"document.forms[0].name.focus()");
+ WaitForSuggestionRetrieval();
+ ExpectMetric("Autofill.AddressSuggestionsCount", 1);
+ ExpectHappinessMetric(AutofillMetrics::SUGGESTIONS_SHOWN);
+ EXPECT_EQ(1U, [suggestion_controller() suggestions].count);
+ FormSuggestion* suggestion = [suggestion_controller() suggestions][0];
+ EXPECT_NSEQ(@"Homer Simpson", suggestion.value);
+};
+
+// Checks that focusing on a select element in a profile-type form will result
+// in suggestions being sent to the AutofillAgent, once data has been loaded
+// into a test data manager.
+TEST_F(AutofillControllerTest, ProfileSuggestionsFromSelectField) {
+ SetUpForSuggestions(kProfileFormHtml);
+ WaitForBackgroundTasks();
+ ui::test::uiview_utils::ForceViewRendering(web_state()->GetView());
+ ExecuteJavaScript(@"document.forms[0].state.focus()");
+ WaitForSuggestionRetrieval();
+ ExpectMetric("Autofill.AddressSuggestionsCount", 1);
+ ExpectHappinessMetric(AutofillMetrics::SUGGESTIONS_SHOWN);
+ EXPECT_EQ(1U, [suggestion_controller() suggestions].count);
+ FormSuggestion* suggestion = [suggestion_controller() suggestions][0];
+ EXPECT_NSEQ(@"IL", suggestion.value);
+};
+
+// Checks that multiple profiles will offer a matching number of suggestions.
+TEST_F(AutofillControllerTest, MultipleProfileSuggestions) {
+ AutofillManager* autofill_manager =
+ AutofillDriverIOS::FromWebState(web_state())->autofill_manager();
+ PersonalDataManager* personal_data_manager =
+ autofill_manager->client()->GetPersonalDataManager();
+ AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+ profile.SetRawInfo(NAME_FULL, base::UTF8ToUTF16("Homer Simpson"));
+ profile.SetRawInfo(ADDRESS_HOME_LINE1, base::UTF8ToUTF16("123 Main Street"));
+ profile.SetRawInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16("Springfield"));
+ profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("IL"));
+ profile.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("55123"));
+ EXPECT_EQ(0U, personal_data_manager->GetProfiles().size());
+ personal_data_manager->SaveImportedProfile(profile);
+ EXPECT_EQ(1U, personal_data_manager->GetProfiles().size());
+ AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com/");
+ profile2.SetRawInfo(NAME_FULL, base::UTF8ToUTF16("Larry Page"));
+ profile2.SetRawInfo(ADDRESS_HOME_LINE1,
+ base::UTF8ToUTF16("1600 Amphitheatre Parkway"));
+ profile2.SetRawInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16("Mountain View"));
+ profile2.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("CA"));
+ profile2.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("94043"));
+ personal_data_manager->SaveImportedProfile(profile2);
+ EXPECT_EQ(2U, personal_data_manager->GetProfiles().size());
+ LoadHtml(kProfileFormHtml);
+ WaitForBackgroundTasks();
+ ui::test::uiview_utils::ForceViewRendering(web_state()->GetView());
+ ExecuteJavaScript(@"document.forms[0].name.focus()");
+ WaitForSuggestionRetrieval();
+ ExpectMetric("Autofill.AddressSuggestionsCount", 2);
+ ExpectHappinessMetric(AutofillMetrics::SUGGESTIONS_SHOWN);
+ EXPECT_EQ(2U, [suggestion_controller() suggestions].count);
+}
+
+// Check that an HTML page containing a key/value type form which is submitted
+// with scripts (simulating user form submission) results in data being
+// successfully registered.
+TEST_F(AutofillControllerTest, KeyValueImport) {
+ LoadHtml(kKeyValueFormHtml);
+ ExecuteJavaScript(@"document.forms[0].greeting.value = 'Hello'");
+ scoped_refptr<AutofillWebDataService> web_data_service =
+ ios::WebDataServiceFactory::GetAutofillWebDataForBrowserState(
+ chrome_browser_state_.get(), ServiceAccessType::EXPLICIT_ACCESS);
+ __block TestConsumer consumer;
+ const int limit = 1;
+ web_data_service->GetFormValuesForElementName(
+ base::UTF8ToUTF16("greeting"), base::string16(), limit, &consumer);
+ WaitForBackgroundTasks();
+ // No value should be returned before anything is loaded via form submission.
+ ASSERT_EQ(0U, consumer.result_.size());
+ ExecuteJavaScript(@"submit.click()");
+ WaitForCondition(^bool {
+ web_data_service->GetFormValuesForElementName(
+ base::UTF8ToUTF16("greeting"), base::string16(), limit, &consumer);
+ return consumer.result_.size();
+ });
+ WaitForBackgroundTasks();
+ // One result should be returned, matching the filled value.
+ ASSERT_EQ(1U, consumer.result_.size());
+ EXPECT_EQ(base::UTF8ToUTF16("Hello"), consumer.result_[0]);
+};
+
+void AutofillControllerTest::SetUpKeyValueData() {
+ scoped_refptr<AutofillWebDataService> web_data_service =
+ ios::WebDataServiceFactory::GetAutofillWebDataForBrowserState(
+ chrome_browser_state_.get(), ServiceAccessType::EXPLICIT_ACCESS);
+ // Load value into database.
+ std::vector<FormFieldData> values;
+ FormFieldData fieldData;
+ fieldData.name = base::UTF8ToUTF16("greeting");
+ fieldData.value = base::UTF8ToUTF16("Bonjour");
+ values.push_back(fieldData);
+ web_data_service->AddFormFields(values);
+}
+
+// Checks that focusing on an element of a key/value type form then typing the
+// first letter of a suggestion will result in suggestions being sent to the
+// AutofillAgent, once data has been loaded into a test data manager.
+TEST_F(AutofillControllerTest, KeyValueSuggestions) {
+ SetUpKeyValueData();
+ // Load test page and focus element.
+ LoadHtml(kKeyValueFormHtml);
+ WaitForBackgroundTasks();
+ ExecuteJavaScript(@"document.forms[0].greeting.value='B'");
+ ExecuteJavaScript(@"document.forms[0].greeting.focus()");
+ WaitForSuggestionRetrieval();
+ EXPECT_EQ(1U, [suggestion_controller() suggestions].count);
+ FormSuggestion* suggestion = [suggestion_controller() suggestions][0];
+ EXPECT_NSEQ(@"Bonjour", suggestion.value);
+};
+
+// Checks that typing events (simulated in script) result in suggestions. Note
+// that the field is not explictly focused before typing starts; this can happen
+// in practice and should not result in a crash or incorrect behavior.
+TEST_F(AutofillControllerTest, KeyValueTypedSuggestions) {
+ SetUpKeyValueData();
+ LoadHtml(kKeyValueFormHtml);
+ WaitForBackgroundTasks();
+ ExecuteJavaScript(@"document.forms[0].greeting.select()");
+ ExecuteJavaScript(@"event = document.createEvent('TextEvent');");
+ ExecuteJavaScript(
+ @"event.initTextEvent('textInput', true, true, window, 'B');");
+ ExecuteJavaScript(@"document.forms[0].greeting.dispatchEvent(event);");
+ WaitForSuggestionRetrieval();
+ EXPECT_EQ(1U, [suggestion_controller() suggestions].count);
+ FormSuggestion* suggestion = [suggestion_controller() suggestions][0];
+ EXPECT_NSEQ(@"Bonjour", suggestion.value);
+}
+
+// Checks that focusing on and typing on one field, then changing focus before
+// typing again, result in suggestions.
+TEST_F(AutofillControllerTest, KeyValueFocusChange) {
+ SetUpKeyValueData();
+ LoadHtml(kKeyValueFormHtml);
+
+ // Focus the dummy field and confirm no suggestions are presented.
+ ExecuteJavaScript(@"document.forms[0].dummy.focus()");
+ WaitForSuggestionRetrieval();
+ EXPECT_EQ(0U, [suggestion_controller() suggestions].count);
+
+ // Enter 'B' in the dummy field and confirm no suggestions are presented.
+ ExecuteJavaScript(@"event = document.createEvent('TextEvent');");
+ ExecuteJavaScript(
+ @"event.initTextEvent('textInput', true, true, window, 'B');");
+ ExecuteJavaScript(@"document.forms[0].dummy.dispatchEvent(event);");
+ WaitForSuggestionRetrieval();
+ EXPECT_EQ(0U, [suggestion_controller() suggestions].count);
+
+ // Enter 'B' in the greeting field and confirm that one suggestion ("Bonjour")
+ // is presented.
+ ExecuteJavaScript(@"document.forms[0].greeting.select()");
+ ExecuteJavaScript(@"event = document.createEvent('TextEvent');");
+ ExecuteJavaScript(
+ @"event.initTextEvent('textInput', true, true, window, 'B');");
+ ExecuteJavaScript(@"document.forms[0].greeting.dispatchEvent(event);");
+ WaitForSuggestionRetrieval();
+ EXPECT_EQ(1U, [suggestion_controller() suggestions].count);
+ FormSuggestion* suggestion = [suggestion_controller() suggestions][0];
+ EXPECT_NSEQ(@"Bonjour", suggestion.value);
+}
+
+// Checks that focusing on an element of a key/value type form without typing
+// won't result in suggestions being sent to the AutofillAgent, once data has
+// been loaded into a test data manager.
+TEST_F(AutofillControllerTest, NoKeyValueSuggestionsWithoutTyping) {
+ SetUpKeyValueData();
+ // Load test page and focus element.
+ LoadHtml(kKeyValueFormHtml);
+ ExecuteJavaScript(@"document.forms[0].greeting.focus()");
+ WaitForSuggestionRetrieval();
+ EXPECT_EQ(0U, [suggestion_controller() suggestions].count);
+}
+
+// Checks that an HTML page containing a credit card-type form which is
+// submitted with scripts (simulating user form submission) results in a credit
+// card being successfully imported into the PersonalDataManager.
+TEST_F(AutofillControllerTest, CreditCardImport) {
+ InfoBarManagerImpl::CreateForWebState(web_state());
+ AutofillManager* autofill_manager =
+ AutofillDriverIOS::FromWebState(web_state())->autofill_manager();
+ PersonalDataManager* personal_data_manager =
+ autofill_manager->client()->GetPersonalDataManager();
+ // Check there are no registered profiles already.
+ EXPECT_EQ(0U, personal_data_manager->GetCreditCards().size());
+ LoadHtml(kCreditCardFormHtml);
+ ExecuteJavaScript(@"document.forms[0].name.value = 'Superman'");
+ ExecuteJavaScript(@"document.forms[0].CCNo.value = '4000-4444-4444-4444'");
+ ExecuteJavaScript(@"document.forms[0].CCExpiresMonth.value = '11'");
+ ExecuteJavaScript(@"document.forms[0].CCExpiresYear.value = '2999'");
+ ExecuteJavaScript(@"submit.click()");
+ infobars::InfoBarManager* infobar_manager =
+ InfoBarManagerImpl::FromWebState(web_state());
+ base::test::ios::WaitUntilCondition(^bool() {
+ return infobar_manager->infobar_count();
+ });
+ ExpectMetric("Autofill.CreditCardInfoBar.Local",
+ AutofillMetrics::INFOBAR_SHOWN);
+ ASSERT_EQ(1U, infobar_manager->infobar_count());
+ infobars::InfoBarDelegate* infobar =
+ infobar_manager->infobar_at(0)->delegate();
+ ConfirmInfoBarDelegate* confirm_infobar = infobar->AsConfirmInfoBarDelegate();
+ confirm_infobar->Accept();
+ const std::vector<CreditCard*>& credit_cards =
+ personal_data_manager->GetCreditCards();
+ ASSERT_EQ(1U, credit_cards.size());
+ const CreditCard& credit_card = *credit_cards[0];
+ EXPECT_EQ(base::UTF8ToUTF16("Superman"),
+ credit_card.GetInfo(AutofillType(CREDIT_CARD_NAME_FULL), "en-US"));
+ EXPECT_EQ(base::UTF8ToUTF16("4000444444444444"),
+ credit_card.GetInfo(AutofillType(CREDIT_CARD_NUMBER), "en-US"));
+ EXPECT_EQ(base::UTF8ToUTF16("11"),
+ credit_card.GetInfo(AutofillType(CREDIT_CARD_EXP_MONTH), "en-US"));
+ EXPECT_EQ(
+ base::UTF8ToUTF16("2999"),
+ credit_card.GetInfo(AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), "en-US"));
+};
+
+} // namespace
+
+} // namespace autofill
« no previous file with comments | « ios/chrome/browser/autofill/autofill_controller_js_unittest.mm ('k') | ios/chrome/browser/autofill/form_input_egtest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698