blob: 3932837ba9eac8cccb2f5984d7505f5d4e015172 [file] [log] [blame]
// Copyright (c) 2012 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.
#include <map>
#include <utility>
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/guid.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/signin/account_tracker_service_factory.h"
#include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h"
#include "chrome/browser/ui/autofill/autofill_dialog_i18n_input.h"
#include "chrome/browser/ui/autofill/autofill_dialog_view.h"
#include "chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h"
#include "chrome/browser/ui/autofill/mock_address_validator.h"
#include "chrome/browser/ui/autofill/mock_new_credit_card_bubble_controller.h"
#include "chrome/browser/ui/autofill/test_generated_credit_card_bubble_controller.h"
#include "chrome/browser/webdata/web_data_service_factory.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
#include "components/autofill/content/browser/wallet/full_wallet.h"
#include "components/autofill/content/browser/wallet/gaia_account.h"
#include "components/autofill/content/browser/wallet/instrument.h"
#include "components/autofill/content/browser/wallet/mock_wallet_client.h"
#include "components/autofill/content/browser/wallet/wallet_address.h"
#include "components/autofill/content/browser/wallet/wallet_service_url.h"
#include "components/autofill/content/browser/wallet/wallet_test_util.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/form_data.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/mock_render_process_host.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "grit/components_scaled_resources.h"
#include "grit/components_strings.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libaddressinput/chromium/chrome_address_validator.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_problem.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#if defined(OS_WIN)
#include "ui/base/win/scoped_ole_initializer.h"
#endif
using base::ASCIIToUTF16;
using base::UTF8ToUTF16;
namespace autofill {
namespace {
using ::i18n::addressinput::FieldProblemMap;
using testing::AtLeast;
using testing::DoAll;
using testing::Return;
using testing::SetArgPointee;
using testing::_;
const char kSourceUrl[] = "http://localbike.shop";
const char kFakeEmail[] = "user@chromium.org";
const char kEditedBillingAddress[] = "123 edited billing address";
const char* kFieldsFromPage[] =
{ "email",
"cc-name",
"cc-number",
"cc-exp-month",
"cc-exp-year",
"cc-csc",
"billing name",
"billing address-line1",
"billing address-level2",
"billing address-level1",
"billing postal-code",
"billing country",
"billing tel",
"shipping name",
"shipping address-line1",
"shipping address-level2",
"shipping address-level1",
"shipping postal-code",
"shipping country",
"shipping tel",
};
const char kSettingsOrigin[] = "Chrome settings";
const char kTestCCNumberAmex[] = "376200000000002";
const char kTestCCNumberVisa[] = "4111111111111111";
const char kTestCCNumberMaster[] = "5555555555554444";
const char kTestCCNumberDiscover[] = "6011111111111117";
const char kTestCCNumberIncomplete[] = "4111111111";
// Credit card number fails Luhn check.
const char kTestCCNumberInvalid[] = "4111111111111112";
// Copies the initial values from |inputs| into |outputs|.
void CopyInitialValues(const DetailInputs& inputs, FieldValueMap* outputs) {
for (size_t i = 0; i < inputs.size(); ++i) {
const DetailInput& input = inputs[i];
(*outputs)[input.type] = input.initial_value;
}
}
scoped_ptr<wallet::WalletItems> CompleteAndValidWalletItems() {
scoped_ptr<wallet::WalletItems> items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
items->AddAccount(wallet::GetTestGaiaAccount());
items->AddInstrument(wallet::GetTestMaskedInstrument());
items->AddAddress(wallet::GetTestShippingAddress());
return items.Pass();
}
bool HasAnyError(const ValidityMessages& messages, ServerFieldType field) {
return !messages.GetMessageOrDefault(field).text.empty();
}
bool HasUnsureError(const ValidityMessages& messages, ServerFieldType field) {
const ValidityMessage& message = messages.GetMessageOrDefault(field);
return !message.text.empty() && !message.sure;
}
class TestAutofillDialogView : public AutofillDialogView {
public:
TestAutofillDialogView()
: updates_started_(0), save_details_locally_checked_(true) {}
~TestAutofillDialogView() override {}
void Show() override {}
void Hide() override {}
void UpdatesStarted() override {
updates_started_++;
}
void UpdatesFinished() override {
updates_started_--;
EXPECT_GE(updates_started_, 0);
}
void UpdateNotificationArea() override {
EXPECT_GE(updates_started_, 1);
}
void UpdateAccountChooser() override {
EXPECT_GE(updates_started_, 1);
}
void UpdateButtonStrip() override {
EXPECT_GE(updates_started_, 1);
}
void UpdateOverlay() override {
EXPECT_GE(updates_started_, 1);
}
void UpdateDetailArea() override {
EXPECT_GE(updates_started_, 1);
}
void UpdateSection(DialogSection section) override {
section_updates_[section]++;
EXPECT_GE(updates_started_, 1);
}
void UpdateErrorBubble() override {
EXPECT_GE(updates_started_, 1);
}
void FillSection(DialogSection section,
ServerFieldType originating_type) override {}
void GetUserInput(DialogSection section, FieldValueMap* output) override {
*output = outputs_[section];
}
base::string16 GetCvc() override { return base::string16(); }
bool SaveDetailsLocally() override { return save_details_locally_checked_; }
const content::NavigationController* ShowSignIn(const GURL& url) override {
return NULL;
}
void HideSignIn() override {}
MOCK_METHOD0(ModelChanged, void());
MOCK_METHOD0(UpdateForErrors, void());
void OnSignInResize(const gfx::Size& pref_size) override {}
void ValidateSection(DialogSection) override {}
void SetUserInput(DialogSection section, const FieldValueMap& map) {
outputs_[section] = map;
}
void CheckSaveDetailsLocallyCheckbox(bool checked) {
save_details_locally_checked_ = checked;
}
void ClearSectionUpdates() {
section_updates_.clear();
}
std::map<DialogSection, size_t> section_updates() const {
return section_updates_;
}
private:
std::map<DialogSection, FieldValueMap> outputs_;
std::map<DialogSection, size_t> section_updates_;
int updates_started_;
bool save_details_locally_checked_;
DISALLOW_COPY_AND_ASSIGN(TestAutofillDialogView);
};
class TestAutofillDialogController
: public AutofillDialogControllerImpl,
public base::SupportsWeakPtr<TestAutofillDialogController> {
public:
TestAutofillDialogController(
content::WebContents* contents,
const FormData& form_structure,
const GURL& source_url,
const AutofillClient::ResultCallback& callback,
MockNewCreditCardBubbleController* mock_new_card_bubble_controller)
: AutofillDialogControllerImpl(contents,
form_structure,
source_url,
callback),
mock_wallet_client_(
Profile::FromBrowserContext(contents->GetBrowserContext())
->GetRequestContext(),
this,
source_url),
mock_new_card_bubble_controller_(mock_new_card_bubble_controller),
submit_button_delay_count_(0) {}
~TestAutofillDialogController() override {}
AutofillDialogView* CreateView() override {
return new testing::NiceMock<TestAutofillDialogView>();
}
void Init(content::BrowserContext* browser_context) {
Profile* profile = Profile::FromBrowserContext(browser_context);
test_manager_.Init(WebDataServiceFactory::GetAutofillWebDataForProfile(
profile,
ServiceAccessType::EXPLICIT_ACCESS),
user_prefs::UserPrefs::Get(browser_context),
AccountTrackerServiceFactory::GetForProfile(profile),
browser_context->IsOffTheRecord());
}
TestAutofillDialogView* GetView() {
return static_cast<TestAutofillDialogView*>(view());
}
TestPersonalDataManager* GetTestingManager() {
return &test_manager_;
}
MockAddressValidator* GetMockValidator() {
return &mock_validator_;
}
wallet::MockWalletClient* GetTestingWalletClient() {
return &mock_wallet_client_;
}
const GURL& open_tab_url() { return open_tab_url_; }
void SimulateSigninError() {
OnWalletSigninError();
}
// Skips past the 2 second wait between FinishSubmit and DoFinishSubmit.
void ForceFinishSubmit() {
DoFinishSubmit();
}
void SimulateSubmitButtonDelayBegin() {
AutofillDialogControllerImpl::SubmitButtonDelayBegin();
}
void SimulateSubmitButtonDelayEnd() {
AutofillDialogControllerImpl::SubmitButtonDelayEndForTesting();
}
using AutofillDialogControllerImpl::
ClearLastWalletItemsFetchTimestampForTesting;
// Returns the number of times that the submit button was delayed.
int get_submit_button_delay_count() const {
return submit_button_delay_count_;
}
MOCK_METHOD0(LoadRiskFingerprintData, void());
using AutofillDialogControllerImpl::AccountChooserModelForTesting;
using AutofillDialogControllerImpl::OnDidLoadRiskFingerprintData;
using AutofillDialogControllerImpl::IsEditingExistingData;
using AutofillDialogControllerImpl::IsManuallyEditingSection;
using AutofillDialogControllerImpl::IsPayingWithWallet;
using AutofillDialogControllerImpl::IsSubmitPausedOn;
using AutofillDialogControllerImpl::NOT_CHECKED;
using AutofillDialogControllerImpl::popup_input_type;
using AutofillDialogControllerImpl::SignedInState;
protected:
PersonalDataManager* GetManager() const override {
return const_cast<TestAutofillDialogController*>(this)->
GetTestingManager();
}
AddressValidator* GetValidator() override {
return &mock_validator_;
}
wallet::WalletClient* GetWalletClient() override {
return &mock_wallet_client_;
}
void OpenTabWithUrl(const GURL& url) override {
open_tab_url_ = url;
}
void ShowNewCreditCardBubble(
scoped_ptr<CreditCard> new_card,
scoped_ptr<AutofillProfile> billing_profile) override {
mock_new_card_bubble_controller_->Show(new_card.Pass(),
billing_profile.Pass());
}
// AutofillDialogControllerImpl calls this method before showing the dialog
// window.
void SubmitButtonDelayBegin() override {
// Do not delay enabling the submit button in testing.
submit_button_delay_count_++;
}
private:
TestPersonalDataManager test_manager_;
testing::NiceMock<wallet::MockWalletClient> mock_wallet_client_;
// A mock validator object to prevent network requests and track when
// validation rules are loaded or validation attempts occur.
testing::NiceMock<MockAddressValidator> mock_validator_;
GURL open_tab_url_;
MockNewCreditCardBubbleController* mock_new_card_bubble_controller_;
// The number of times that the submit button was delayed.
int submit_button_delay_count_;
DISALLOW_COPY_AND_ASSIGN(TestAutofillDialogController);
};
class AutofillDialogControllerTest : public ChromeRenderViewHostTestHarness {
protected:
AutofillDialogControllerTest(): form_structure_(NULL) {}
// testing::Test implementation:
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
Reset();
}
void TearDown() override {
if (controller_)
controller_->ViewClosed();
ChromeRenderViewHostTestHarness::TearDown();
}
void Reset() {
if (controller_)
controller_->ViewClosed();
test_generated_bubble_controller_ =
new testing::NiceMock<TestGeneratedCreditCardBubbleController>(
web_contents());
ASSERT_TRUE(test_generated_bubble_controller_->IsInstalled());
mock_new_card_bubble_controller_.reset(
new MockNewCreditCardBubbleController);
profile()->GetPrefs()->ClearPref(::prefs::kAutofillDialogSaveData);
// We have to clear the old local state before creating a new one.
scoped_local_state_.reset();
scoped_local_state_.reset(new ScopedTestingLocalState(
TestingBrowserProcess::GetGlobal()));
SetUpControllerWithFormData(DefaultFormData());
}
FormData DefaultFormData() {
FormData form_data;
for (size_t i = 0; i < arraysize(kFieldsFromPage); ++i) {
FormFieldData field;
field.autocomplete_attribute = kFieldsFromPage[i];
form_data.fields.push_back(field);
}
return form_data;
}
// Creates a new controller for |form_data|.
void ResetControllerWithFormData(const FormData& form_data) {
if (controller_)
controller_->ViewClosed();
AutofillClient::ResultCallback callback =
base::Bind(&AutofillDialogControllerTest::FinishedCallback,
base::Unretained(this));
controller_ = (new testing::NiceMock<TestAutofillDialogController>(
web_contents(),
form_data,
GURL(kSourceUrl),
callback,
mock_new_card_bubble_controller_.get()))->AsWeakPtr();
controller_->Init(profile());
}
// Creates a new controller for |form_data| and sets up some initial wallet
// data for it.
void SetUpControllerWithFormData(const FormData& form_data) {
ResetControllerWithFormData(form_data);
controller()->Show();
if (controller() &&
!profile()->GetPrefs()->GetBoolean(
::prefs::kAutofillDialogPayWithoutWallet)) {
EXPECT_CALL(*controller()->GetTestingWalletClient(),
GetWalletItems(_, _));
controller()->OnDidFetchWalletCookieValue(std::string());
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
}
}
// Fills the inputs in SECTION_CC with data.
void FillCreditCardInputs() {
FieldValueMap cc_outputs;
const DetailInputs& cc_inputs =
controller()->RequestedFieldsForSection(SECTION_CC);
for (size_t i = 0; i < cc_inputs.size(); ++i) {
cc_outputs[cc_inputs[i].type] = cc_inputs[i].type == CREDIT_CARD_NUMBER ?
ASCIIToUTF16(kTestCCNumberVisa) : ASCIIToUTF16("11");
}
controller()->GetView()->SetUserInput(SECTION_CC, cc_outputs);
}
// Fills the inputs in SECTION_CC_BILLING with valid data.
void FillCCBillingInputs() {
FieldValueMap outputs;
const DetailInputs& inputs =
controller()->RequestedFieldsForSection(SECTION_CC_BILLING);
AutofillProfile full_profile(test::GetVerifiedProfile());
CreditCard full_card(test::GetCreditCard());
for (size_t i = 0; i < inputs.size(); ++i) {
const ServerFieldType type = inputs[i].type;
outputs[type] = full_profile.GetInfo(AutofillType(type), "en-US");
if (outputs[type].empty())
outputs[type] = full_card.GetInfo(AutofillType(type), "en-US");
}
controller()->GetView()->SetUserInput(SECTION_CC_BILLING, outputs);
}
// Activates the 'Add new foo' option from the |section|'s suggestions
// dropdown and fills the |section|'s inputs with the data from the
// |data_model|. If |section| is SECTION_CC, also fills in '123' for the CVC.
void FillInputs(DialogSection section, const AutofillDataModel& data_model) {
// Select the 'Add new foo' option.
ui::MenuModel* model = GetMenuModelForSection(section);
if (model)
model->ActivatedAt(model->GetItemCount() - 2);
// Fill the inputs.
FieldValueMap outputs;
const DetailInputs& inputs =
controller()->RequestedFieldsForSection(section);
for (size_t i = 0; i < inputs.size(); ++i) {
ServerFieldType type = inputs[i].type;
base::string16 output;
if (type == CREDIT_CARD_VERIFICATION_CODE)
output = ASCIIToUTF16("123");
else
output = data_model.GetInfo(AutofillType(type), "en-US");
outputs[inputs[i].type] = output;
}
controller()->GetView()->SetUserInput(section, outputs);
}
std::vector<DialogNotification> NotificationsOfType(
DialogNotification::Type type) {
std::vector<DialogNotification> right_type;
const std::vector<DialogNotification>& notifications =
controller()->CurrentNotifications();
for (size_t i = 0; i < notifications.size(); ++i) {
if (notifications[i].type() == type)
right_type.push_back(notifications[i]);
}
return right_type;
}
void SwitchToAutofill() {
ui::MenuModel* model = controller_->MenuModelForAccountChooser();
model->ActivatedAt(model->GetItemCount() - 1);
}
void SwitchToWallet() {
controller_->MenuModelForAccountChooser()->ActivatedAt(0);
}
void SimulateSigninError() {
controller_->SimulateSigninError();
}
void UseBillingForShipping() {
controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(0);
}
base::string16 ValidateCCNumber(DialogSection section,
const std::string& cc_number,
bool should_pass) {
FieldValueMap outputs;
outputs[ADDRESS_BILLING_COUNTRY] = ASCIIToUTF16("United States");
outputs[CREDIT_CARD_NUMBER] = UTF8ToUTF16(cc_number);
ValidityMessages messages =
controller()->InputsAreValid(section, outputs);
EXPECT_EQ(should_pass, !messages.HasSureError(CREDIT_CARD_NUMBER));
return messages.GetMessageOrDefault(CREDIT_CARD_NUMBER).text;
}
void SubmitWithWalletItems(scoped_ptr<wallet::WalletItems> wallet_items) {
controller()->OnDidGetWalletItems(wallet_items.Pass());
AcceptAndLoadFakeFingerprint();
}
void AcceptAndLoadFakeFingerprint() {
controller()->OnAccept();
controller()->OnDidLoadRiskFingerprintData("a");
}
// Returns true if the given |section| contains a field of the given |type|.
bool SectionContainsField(DialogSection section, ServerFieldType type) {
const DetailInputs& inputs =
controller()->RequestedFieldsForSection(section);
for (DetailInputs::const_iterator it = inputs.begin(); it != inputs.end();
++it) {
if (it->type == type)
return true;
}
return false;
}
SuggestionsMenuModel* GetMenuModelForSection(DialogSection section) {
ui::MenuModel* model = controller()->MenuModelForSection(section);
return static_cast<SuggestionsMenuModel*>(model);
}
void SubmitAndVerifyShippingAndBillingResults() {
// Test after setting use billing for shipping.
UseBillingForShipping();
controller()->OnAccept();
ASSERT_EQ(20U, form_structure()->field_count());
EXPECT_EQ(ADDRESS_HOME_COUNTRY,
form_structure()->field(11)->Type().GetStorableType());
EXPECT_EQ(ADDRESS_BILLING, form_structure()->field(11)->Type().group());
EXPECT_EQ(ADDRESS_HOME_COUNTRY,
form_structure()->field(18)->Type().GetStorableType());
EXPECT_EQ(ADDRESS_HOME, form_structure()->field(18)->Type().group());
base::string16 billing_country = form_structure()->field(11)->value;
EXPECT_EQ(2U, billing_country.size());
base::string16 shipping_country = form_structure()->field(18)->value;
EXPECT_EQ(2U, shipping_country.size());
EXPECT_FALSE(billing_country.empty());
EXPECT_FALSE(shipping_country.empty());
EXPECT_EQ(billing_country, shipping_country);
EXPECT_EQ(CREDIT_CARD_NAME,
form_structure()->field(1)->Type().GetStorableType());
base::string16 cc_name = form_structure()->field(1)->value;
EXPECT_EQ(NAME_FULL, form_structure()->field(6)->Type().GetStorableType());
EXPECT_EQ(NAME_BILLING, form_structure()->field(6)->Type().group());
base::string16 billing_name = form_structure()->field(6)->value;
EXPECT_EQ(NAME_FULL, form_structure()->field(13)->Type().GetStorableType());
EXPECT_EQ(NAME, form_structure()->field(13)->Type().group());
base::string16 shipping_name = form_structure()->field(13)->value;
EXPECT_FALSE(cc_name.empty());
EXPECT_FALSE(billing_name.empty());
EXPECT_FALSE(shipping_name.empty());
EXPECT_EQ(cc_name, billing_name);
EXPECT_EQ(cc_name, shipping_name);
}
TestAutofillDialogController* controller() { return controller_.get(); }
const FormStructure* form_structure() { return form_structure_; }
TestGeneratedCreditCardBubbleController* test_generated_bubble_controller() {
return test_generated_bubble_controller_;
}
const MockNewCreditCardBubbleController* mock_new_card_bubble_controller() {
return mock_new_card_bubble_controller_.get();
}
private:
void FinishedCallback(AutofillClient::RequestAutocompleteResult result,
const base::string16& debug_message,
const FormStructure* form_structure) {
form_structure_ = form_structure;
}
#if defined(OS_WIN)
// http://crbug.com/227221
ui::ScopedOleInitializer ole_initializer_;
#endif
// The controller owns itself.
base::WeakPtr<TestAutofillDialogController> controller_;
// Returned when the dialog closes successfully.
const FormStructure* form_structure_;
// Used to monitor if the Autofill credit card bubble is shown. Owned by
// |web_contents()|.
TestGeneratedCreditCardBubbleController* test_generated_bubble_controller_;
// Used to record when new card bubbles would show. Created in |Reset()|.
scoped_ptr<MockNewCreditCardBubbleController>
mock_new_card_bubble_controller_;
scoped_ptr<ScopedTestingLocalState> scoped_local_state_;
};
} // namespace
TEST_F(AutofillDialogControllerTest, RefuseToShowWithNoAutocompleteAttributes) {
FormFieldData email_field;
email_field.name = ASCIIToUTF16("email");
FormFieldData cc_field;
cc_field.name = ASCIIToUTF16("cc");
FormFieldData billing_field;
billing_field.name = ASCIIToUTF16("billing name");
FormData form_data;
form_data.fields.push_back(email_field);
form_data.fields.push_back(cc_field);
form_data.fields.push_back(billing_field);
SetUpControllerWithFormData(form_data);
EXPECT_FALSE(controller());
}
TEST_F(AutofillDialogControllerTest, RefuseToShowWithNoCcField) {
FormFieldData shipping_tel;
shipping_tel.autocomplete_attribute = "shipping tel";
FormData form_data;
form_data.fields.push_back(shipping_tel);
SetUpControllerWithFormData(form_data);
EXPECT_FALSE(controller());
// Any cc- field will do.
FormFieldData cc_field;
cc_field.autocomplete_attribute = "cc-csc";
form_data.fields.push_back(cc_field);
SetUpControllerWithFormData(form_data);
EXPECT_TRUE(controller());
}
// Ensure the default ValidityMessage has the expected values.
TEST_F(AutofillDialogControllerTest, DefaultValidityMessage) {
ValidityMessages messages;
ValidityMessage message = messages.GetMessageOrDefault(UNKNOWN_TYPE);
EXPECT_FALSE(message.sure);
EXPECT_TRUE(message.text.empty());
}
// This test makes sure nothing falls over when fields are being validity-
// checked.
TEST_F(AutofillDialogControllerTest, ValidityCheck) {
for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
DialogSection section = static_cast<DialogSection>(i);
const DetailInputs& shipping_inputs =
controller()->RequestedFieldsForSection(section);
for (DetailInputs::const_iterator iter = shipping_inputs.begin();
iter != shipping_inputs.end(); ++iter) {
controller()->InputValidityMessage(section, iter->type, base::string16());
}
}
}
// Test for phone number validation.
TEST_F(AutofillDialogControllerTest, PhoneNumberValidation) {
// Construct FieldValueMap from existing data.
SwitchToAutofill();
for (size_t i = 0; i < 2; ++i) {
ServerFieldType phone = i == 0 ? PHONE_HOME_WHOLE_NUMBER :
PHONE_BILLING_WHOLE_NUMBER;
ServerFieldType address = i == 0 ? ADDRESS_HOME_COUNTRY :
ADDRESS_BILLING_COUNTRY;
DialogSection section = i == 0 ? SECTION_SHIPPING : SECTION_BILLING;
FieldValueMap outputs;
const DetailInputs& inputs =
controller()->RequestedFieldsForSection(section);
AutofillProfile full_profile(test::GetVerifiedProfile());
for (size_t j = 0; j < inputs.size(); ++j) {
const ServerFieldType type = inputs[j].type;
outputs[type] = full_profile.GetInfo(AutofillType(type), "en-US");
}
// Make sure country is United States.
outputs[address] = ASCIIToUTF16("United States");
// Existing data should have no errors.
ValidityMessages messages = controller()->InputsAreValid(section, outputs);
EXPECT_FALSE(HasAnyError(messages, phone));
// Input an empty phone number.
outputs[phone] = base::string16();
messages = controller()->InputsAreValid(section, outputs);
EXPECT_TRUE(HasUnsureError(messages, phone));
// Input an invalid phone number.
outputs[phone] = ASCIIToUTF16("ABC");
messages = controller()->InputsAreValid(section, outputs);
EXPECT_TRUE(messages.HasSureError(phone));
// Input a local phone number.
outputs[phone] = ASCIIToUTF16("2155546699");
messages = controller()->InputsAreValid(section, outputs);
EXPECT_FALSE(HasAnyError(messages, phone));
// Input an invalid local phone number.
outputs[phone] = ASCIIToUTF16("215554669");
messages = controller()->InputsAreValid(section, outputs);
EXPECT_TRUE(messages.HasSureError(phone));
// Input an international phone number.
outputs[phone] = ASCIIToUTF16("+33 892 70 12 39");
messages = controller()->InputsAreValid(section, outputs);
EXPECT_FALSE(HasAnyError(messages, phone));
// Input an invalid international phone number.
outputs[phone] = ASCIIToUTF16("+112333 892 70 12 39");
messages = controller()->InputsAreValid(section, outputs);
EXPECT_TRUE(messages.HasSureError(phone));
// Input a valid Canadian number.
outputs[phone] = ASCIIToUTF16("+1 506 887 1234");
messages = controller()->InputsAreValid(section, outputs);
EXPECT_FALSE(HasAnyError(messages, phone));
// Input a valid Canadian number without the country code.
outputs[phone] = ASCIIToUTF16("506 887 1234");
messages = controller()->InputsAreValid(section, outputs);
EXPECT_TRUE(HasAnyError(messages, phone));
// Input a valid Canadian toll-free number.
outputs[phone] = ASCIIToUTF16("310 1234");
messages = controller()->InputsAreValid(section, outputs);
EXPECT_TRUE(HasAnyError(messages, phone));
}
}
TEST_F(AutofillDialogControllerTest, ExpirationDateValidity) {
ui::ComboboxModel* exp_year_model =
controller()->ComboboxModelForAutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR);
ui::ComboboxModel* exp_month_model =
controller()->ComboboxModelForAutofillType(CREDIT_CARD_EXP_MONTH);
base::string16 default_year_value =
exp_year_model->GetItemAt(exp_year_model->GetDefaultIndex());
base::string16 default_month_value =
exp_month_model->GetItemAt(exp_month_model->GetDefaultIndex());
base::string16 other_year_value =
exp_year_model->GetItemAt(exp_year_model->GetItemCount() - 1);
base::string16 other_month_value =
exp_month_model->GetItemAt(exp_month_model->GetItemCount() - 1);
FieldValueMap outputs;
outputs[ADDRESS_BILLING_COUNTRY] = ASCIIToUTF16("United States");
outputs[CREDIT_CARD_EXP_MONTH] = default_month_value;
outputs[CREDIT_CARD_EXP_4_DIGIT_YEAR] = default_year_value;
// Expiration default values generate unsure validation errors (but not sure).
ValidityMessages messages = controller()->InputsAreValid(SECTION_CC_BILLING,
outputs);
EXPECT_TRUE(HasUnsureError(messages, CREDIT_CARD_EXP_4_DIGIT_YEAR));
EXPECT_TRUE(HasUnsureError(messages, CREDIT_CARD_EXP_MONTH));
// Expiration date with default month fails.
outputs[CREDIT_CARD_EXP_4_DIGIT_YEAR] = other_year_value;
messages = controller()->InputsAreValid(SECTION_CC_BILLING, outputs);
EXPECT_FALSE(HasUnsureError(messages, CREDIT_CARD_EXP_4_DIGIT_YEAR));
EXPECT_TRUE(HasUnsureError(messages, CREDIT_CARD_EXP_MONTH));
// Expiration date with default year fails.
outputs[CREDIT_CARD_EXP_MONTH] = other_month_value;
outputs[CREDIT_CARD_EXP_4_DIGIT_YEAR] = default_year_value;
messages = controller()->InputsAreValid(SECTION_CC_BILLING, outputs);
EXPECT_TRUE(HasUnsureError(messages, CREDIT_CARD_EXP_4_DIGIT_YEAR));
EXPECT_FALSE(HasUnsureError(messages, CREDIT_CARD_EXP_MONTH));
}
TEST_F(AutofillDialogControllerTest, BillingNameValidation) {
// Construct FieldValueMap from AutofillProfile data.
SwitchToAutofill();
FieldValueMap outputs;
outputs[ADDRESS_BILLING_COUNTRY] = ASCIIToUTF16("United States");
// Input an empty billing name.
outputs[NAME_BILLING_FULL] = base::string16();
ValidityMessages messages = controller()->InputsAreValid(SECTION_BILLING,
outputs);
EXPECT_TRUE(HasUnsureError(messages, NAME_BILLING_FULL));
// Input a non-empty billing name.
outputs[NAME_BILLING_FULL] = ASCIIToUTF16("Bob");
messages = controller()->InputsAreValid(SECTION_BILLING, outputs);
EXPECT_FALSE(HasAnyError(messages, NAME_BILLING_FULL));
// Switch to Wallet which only considers names with with at least two names to
// be valid.
SwitchToWallet();
// Setup some wallet state.
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
controller()->OnDidGetWalletItems(wallet_items.Pass());
// Input an empty billing name. Data source should not change this behavior.
outputs[NAME_BILLING_FULL] = base::string16();
messages = controller()->InputsAreValid(SECTION_CC_BILLING, outputs);
EXPECT_TRUE(HasUnsureError(messages, NAME_BILLING_FULL));
// Input a one name billing name. Wallet does not currently support this.
outputs[NAME_BILLING_FULL] = ASCIIToUTF16("Bob");
messages = controller()->InputsAreValid(SECTION_CC_BILLING, outputs);
EXPECT_TRUE(messages.HasSureError(NAME_BILLING_FULL));
// Input a two name billing name.
outputs[NAME_BILLING_FULL] = ASCIIToUTF16("Bob Barker");
messages = controller()->InputsAreValid(SECTION_CC_BILLING, outputs);
EXPECT_FALSE(HasAnyError(messages, NAME_BILLING_FULL));
// Input a more than two name billing name.
outputs[NAME_BILLING_FULL] = ASCIIToUTF16("John Jacob Jingleheimer Schmidt"),
messages = controller()->InputsAreValid(SECTION_CC_BILLING, outputs);
EXPECT_FALSE(HasAnyError(messages, NAME_BILLING_FULL));
// Input a billing name with lots of crazy whitespace.
outputs[NAME_BILLING_FULL] =
ASCIIToUTF16(" \\n\\r John \\n Jacob Jingleheimer \\t Schmidt "),
messages = controller()->InputsAreValid(SECTION_CC_BILLING, outputs);
EXPECT_FALSE(HasAnyError(messages, NAME_BILLING_FULL));
}
TEST_F(AutofillDialogControllerTest, CreditCardNumberValidation) {
// Construct FieldValueMap from AutofillProfile data.
SwitchToAutofill();
// Should accept AMEX, Visa, Master and Discover.
ValidateCCNumber(SECTION_CC, kTestCCNumberVisa, true);
ValidateCCNumber(SECTION_CC, kTestCCNumberMaster, true);
ValidateCCNumber(SECTION_CC, kTestCCNumberDiscover, true);
ValidateCCNumber(SECTION_CC, kTestCCNumberAmex, true);
ValidateCCNumber(SECTION_CC, kTestCCNumberIncomplete, false);
ValidateCCNumber(SECTION_CC, kTestCCNumberInvalid, false);
// Switch to Wallet which will not accept AMEX.
SwitchToWallet();
// Setup some wallet state on a merchant for which Wallet doesn't
// support AMEX.
controller()->OnDidGetWalletItems(
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED));
// Should accept Visa, Master and Discover, but not AMEX.
ValidateCCNumber(SECTION_CC_BILLING, kTestCCNumberVisa, true);
ValidateCCNumber(SECTION_CC_BILLING, kTestCCNumberMaster, true);
ValidateCCNumber(SECTION_CC_BILLING, kTestCCNumberDiscover, true);
EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_AUTOFILL_CREDIT_CARD_NOT_SUPPORTED_BY_WALLET_FOR_MERCHANT),
ValidateCCNumber(SECTION_CC_BILLING, kTestCCNumberAmex, false));
EXPECT_EQ(
l10n_util::GetStringUTF16(
IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_NUMBER),
ValidateCCNumber(SECTION_CC_BILLING, kTestCCNumberIncomplete, false));
EXPECT_EQ(
l10n_util::GetStringUTF16(
IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_NUMBER),
ValidateCCNumber(SECTION_CC_BILLING, kTestCCNumberInvalid, false));
// Setup some wallet state on a merchant for which Wallet supports AMEX.
controller()->OnDidGetWalletItems(
wallet::GetTestWalletItems(wallet::AMEX_ALLOWED));
// Should accept Visa, Master, Discover, and AMEX.
ValidateCCNumber(SECTION_CC_BILLING, kTestCCNumberVisa, true);
ValidateCCNumber(SECTION_CC_BILLING, kTestCCNumberMaster, true);
ValidateCCNumber(SECTION_CC_BILLING, kTestCCNumberDiscover, true);
ValidateCCNumber(SECTION_CC_BILLING, kTestCCNumberAmex, true);
ValidateCCNumber(SECTION_CC_BILLING, kTestCCNumberIncomplete, false);
ValidateCCNumber(SECTION_CC_BILLING, kTestCCNumberInvalid, false);
}
TEST_F(AutofillDialogControllerTest, AutofillProfiles) {
SwitchToAutofill();
ui::MenuModel* shipping_model =
controller()->MenuModelForSection(SECTION_SHIPPING);
// Since the PersonalDataManager is empty, this should only have the
// "use billing", "add new" and "manage" menu items.
ASSERT_TRUE(shipping_model);
EXPECT_EQ(3, shipping_model->GetItemCount());
// On the other hand, the other models should be NULL when there's no
// suggestion.
EXPECT_FALSE(controller()->MenuModelForSection(SECTION_CC));
EXPECT_FALSE(controller()->MenuModelForSection(SECTION_BILLING));
EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(3);
// Empty profiles are ignored.
AutofillProfile empty_profile(base::GenerateGUID(), kSettingsOrigin);
empty_profile.SetRawInfo(NAME_FULL, ASCIIToUTF16("John Doe"));
controller()->GetTestingManager()->AddTestingProfile(&empty_profile);
shipping_model = controller()->MenuModelForSection(SECTION_SHIPPING);
ASSERT_TRUE(shipping_model);
EXPECT_EQ(3, shipping_model->GetItemCount());
// An otherwise full but unverified profile should be ignored.
AutofillProfile full_profile(test::GetFullProfile());
full_profile.set_origin("https://www.example.com");
full_profile.SetRawInfo(ADDRESS_HOME_LINE2, base::string16());
controller()->GetTestingManager()->AddTestingProfile(&full_profile);
shipping_model = controller()->MenuModelForSection(SECTION_SHIPPING);
ASSERT_TRUE(shipping_model);
EXPECT_EQ(3, shipping_model->GetItemCount());
// A full, verified profile should be picked up.
AutofillProfile verified_profile(test::GetVerifiedProfile());
verified_profile.SetRawInfo(ADDRESS_HOME_LINE2, base::string16());
controller()->GetTestingManager()->AddTestingProfile(&verified_profile);
shipping_model = controller()->MenuModelForSection(SECTION_SHIPPING);
ASSERT_TRUE(shipping_model);
EXPECT_EQ(4, shipping_model->GetItemCount());
}
// Checks that a valid profile is selected by default, but if invalid is
// popped into edit mode.
TEST_F(AutofillDialogControllerTest, AutofillProfilesPopInvalidIntoEdit) {
SwitchToAutofill();
SuggestionsMenuModel* shipping_model =
GetMenuModelForSection(SECTION_SHIPPING);
EXPECT_EQ(3, shipping_model->GetItemCount());
// "Same as billing" is selected.
EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_BILLING));
AutofillProfile verified_profile(test::GetVerifiedProfile());
controller()->GetTestingManager()->AddTestingProfile(&verified_profile);
EXPECT_EQ(4, shipping_model->GetItemCount());
EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING));
// Now make up a problem and make sure the profile isn't in the list.
Reset();
SwitchToAutofill();
FieldProblemMap problems;
problems.insert(std::make_pair(::i18n::addressinput::POSTAL_CODE,
::i18n::addressinput::MISMATCHING_VALUE));
EXPECT_CALL(*controller()->GetMockValidator(),
ValidateAddress(CountryCodeMatcher("US"), _, _)).
WillRepeatedly(DoAll(SetArgPointee<2>(problems),
Return(AddressValidator::SUCCESS)));
controller()->GetTestingManager()->AddTestingProfile(&verified_profile);
shipping_model = GetMenuModelForSection(SECTION_SHIPPING);
EXPECT_EQ(4, shipping_model->GetItemCount());
EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_BILLING));
}
// Makes sure suggestion profiles are re-validated when validation rules load.
TEST_F(AutofillDialogControllerTest, AutofillProfilesRevalidateAfterRulesLoad) {
SwitchToAutofill();
SuggestionsMenuModel* shipping_model =
GetMenuModelForSection(SECTION_SHIPPING);
EXPECT_EQ(3, shipping_model->GetItemCount());
// "Same as billing" is selected.
EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_BILLING));
AutofillProfile verified_profile(test::GetVerifiedProfile());
controller()->GetTestingManager()->AddTestingProfile(&verified_profile);
EXPECT_EQ(4, shipping_model->GetItemCount());
EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
EXPECT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING));
FieldProblemMap problems;
problems.insert(std::make_pair(::i18n::addressinput::POSTAL_CODE,
::i18n::addressinput::MISMATCHING_VALUE));
EXPECT_CALL(*controller()->GetMockValidator(),
ValidateAddress(CountryCodeMatcher("US"), _, _)).
WillRepeatedly(DoAll(SetArgPointee<2>(problems),
Return(AddressValidator::SUCCESS)));
controller()->OnAddressValidationRulesLoaded("US", true);
EXPECT_EQ(4, shipping_model->GetItemCount());
EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_SHIPPING));
EXPECT_TRUE(controller()->IsManuallyEditingSection(SECTION_BILLING));
}
// Makes sure that the choice of which Autofill profile to use for each section
// is sticky.
TEST_F(AutofillDialogControllerTest, AutofillProfileDefaults) {
SwitchToAutofill();
AutofillProfile profile(test::GetVerifiedProfile());
AutofillProfile profile2(test::GetVerifiedProfile2());
controller()->GetTestingManager()->AddTestingProfile(&profile);
controller()->GetTestingManager()->AddTestingProfile(&profile2);
// Until a selection has been made, the default shipping suggestion is the
// first one (after "use billing").
SuggestionsMenuModel* shipping_model =
GetMenuModelForSection(SECTION_SHIPPING);
EXPECT_EQ(1, shipping_model->checked_item());
for (int i = 2; i >= 0; --i) {
shipping_model = GetMenuModelForSection(SECTION_SHIPPING);
shipping_model->ExecuteCommand(i, 0);
FillCreditCardInputs();
controller()->OnAccept();
Reset();
controller()->GetTestingManager()->AddTestingProfile(&profile);
controller()->GetTestingManager()->AddTestingProfile(&profile2);
shipping_model = GetMenuModelForSection(SECTION_SHIPPING);
EXPECT_EQ(i, shipping_model->checked_item());
}
// Try again, but don't add the default profile to the PDM. The dialog
// should fall back to the first profile.
shipping_model->ExecuteCommand(2, 0);
FillCreditCardInputs();
controller()->OnAccept();
Reset();
controller()->GetTestingManager()->AddTestingProfile(&profile);
shipping_model = GetMenuModelForSection(SECTION_SHIPPING);
EXPECT_EQ(1, shipping_model->checked_item());
}
// Makes sure that a newly added Autofill profile becomes set as the default
// choice for the next run.
TEST_F(AutofillDialogControllerTest, NewAutofillProfileIsDefault) {
SwitchToAutofill();
AutofillProfile profile(test::GetVerifiedProfile());
CreditCard credit_card(test::GetVerifiedCreditCard());
controller()->GetTestingManager()->AddTestingProfile(&profile);
controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
// Until a selection has been made, the default suggestion is the first one.
// For the shipping section, this follows the "use billing" suggestion.
EXPECT_EQ(0, GetMenuModelForSection(SECTION_CC)->checked_item());
EXPECT_EQ(1, GetMenuModelForSection(SECTION_SHIPPING)->checked_item());
// Fill in the shipping and credit card sections with new data.
AutofillProfile new_profile(test::GetVerifiedProfile2());
CreditCard new_credit_card(test::GetVerifiedCreditCard2());
FillInputs(SECTION_SHIPPING, new_profile);
FillInputs(SECTION_CC, new_credit_card);
controller()->GetView()->CheckSaveDetailsLocallyCheckbox(true);
controller()->OnAccept();
// Update the |new_profile| and |new_credit_card|'s guids to the saved ones.
new_profile.set_guid(
controller()->GetTestingManager()->imported_profile().guid());
new_credit_card.set_guid(
controller()->GetTestingManager()->imported_credit_card().guid());
// Reload the dialog. The newly added address and credit card should now be
// set as the defaults.
Reset();
controller()->GetTestingManager()->AddTestingProfile(&profile);
controller()->GetTestingManager()->AddTestingProfile(&new_profile);
controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
controller()->GetTestingManager()->AddTestingCreditCard(&new_credit_card);
// Until a selection has been made, the default suggestion is the first one.
// For the shipping section, this follows the "use billing" suggestion.
EXPECT_EQ(1, GetMenuModelForSection(SECTION_CC)->checked_item());
EXPECT_EQ(2, GetMenuModelForSection(SECTION_SHIPPING)->checked_item());
}
TEST_F(AutofillDialogControllerTest, AutofillProfileVariants) {
SwitchToAutofill();
EXPECT_CALL(*controller()->GetView(), ModelChanged());
ui::MenuModel* shipping_model =
controller()->MenuModelForSection(SECTION_SHIPPING);
ASSERT_TRUE(!!shipping_model);
EXPECT_EQ(3, shipping_model->GetItemCount());
// Set up some variant data.
AutofillProfile full_profile(test::GetVerifiedProfile());
std::vector<base::string16> names;
names.push_back(ASCIIToUTF16("John Doe"));
names.push_back(ASCIIToUTF16("Jane Doe"));
full_profile.SetRawMultiInfo(NAME_FULL, names);
std::vector<base::string16> emails;
emails.push_back(ASCIIToUTF16(kFakeEmail));
emails.push_back(ASCIIToUTF16("admin@example.com"));
full_profile.SetRawMultiInfo(EMAIL_ADDRESS, emails);
// Non-default variants are ignored by the dialog.
controller()->GetTestingManager()->AddTestingProfile(&full_profile);
EXPECT_EQ(4, shipping_model->GetItemCount());
}
TEST_F(AutofillDialogControllerTest, SuggestValidEmail) {
SwitchToAutofill();
AutofillProfile profile(test::GetVerifiedProfile());
const base::string16 kValidEmail = ASCIIToUTF16(kFakeEmail);
profile.SetRawInfo(EMAIL_ADDRESS, kValidEmail);
controller()->GetTestingManager()->AddTestingProfile(&profile);
// "add", "manage", and 1 suggestion.
EXPECT_EQ(
3, controller()->MenuModelForSection(SECTION_BILLING)->GetItemCount());
// "add", "manage", 1 suggestion, and "same as billing".
EXPECT_EQ(
4, controller()->MenuModelForSection(SECTION_SHIPPING)->GetItemCount());
}
TEST_F(AutofillDialogControllerTest, DoNotSuggestInvalidEmail) {
SwitchToAutofill();
AutofillProfile profile(test::GetVerifiedProfile());
profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16(".!#$%&'*+/=?^_`-@-.."));
controller()->GetTestingManager()->AddTestingProfile(&profile);
EXPECT_FALSE(!!controller()->MenuModelForSection(SECTION_BILLING));
// "add", "manage", 1 suggestion, and "same as billing".
EXPECT_EQ(
4, controller()->MenuModelForSection(SECTION_SHIPPING)->GetItemCount());
}
TEST_F(AutofillDialogControllerTest, SuggestValidAddress) {
SwitchToAutofill();
AutofillProfile full_profile(test::GetVerifiedProfile());
full_profile.set_origin(kSettingsOrigin);
controller()->GetTestingManager()->AddTestingProfile(&full_profile);
// "add", "manage", and 1 suggestion.
EXPECT_EQ(
3, controller()->MenuModelForSection(SECTION_BILLING)->GetItemCount());
}
TEST_F(AutofillDialogControllerTest, DoNotSuggestInvalidAddress) {
SwitchToAutofill();
AutofillProfile full_profile(test::GetVerifiedProfile());
full_profile.set_origin(kSettingsOrigin);
full_profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("C"));
controller()->GetTestingManager()->AddTestingProfile(&full_profile);
}
TEST_F(AutofillDialogControllerTest, DoNotSuggestIncompleteAddress) {
SwitchToAutofill();
AutofillProfile profile(test::GetVerifiedProfile());
profile.SetRawInfo(ADDRESS_HOME_STATE, base::string16());
controller()->GetTestingManager()->AddTestingProfile(&profile);
// Same as shipping, manage, add new.
EXPECT_EQ(3,
controller()->MenuModelForSection(SECTION_SHIPPING)->GetItemCount());
EXPECT_FALSE(!!controller()->MenuModelForSection(SECTION_BILLING));
}
TEST_F(AutofillDialogControllerTest, DoSuggestShippingAddressWithoutEmail) {
SwitchToAutofill();
AutofillProfile profile(test::GetVerifiedProfile());
profile.SetRawInfo(EMAIL_ADDRESS, base::string16());
controller()->GetTestingManager()->AddTestingProfile(&profile);
// Same as shipping, manage, add new, profile with missing email.
EXPECT_EQ(4,
controller()->MenuModelForSection(SECTION_SHIPPING)->GetItemCount());
// Billing addresses require email.
EXPECT_FALSE(!!controller()->MenuModelForSection(SECTION_BILLING));
}
TEST_F(AutofillDialogControllerTest, AutofillCreditCards) {
SwitchToAutofill();
// Since the PersonalDataManager is empty, this should only have the
// default menu items.
EXPECT_FALSE(controller()->MenuModelForSection(SECTION_CC));
EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(3);
// Empty cards are ignored.
CreditCard empty_card(base::GenerateGUID(), kSettingsOrigin);
empty_card.SetRawInfo(CREDIT_CARD_NAME, ASCIIToUTF16("John Doe"));
controller()->GetTestingManager()->AddTestingCreditCard(&empty_card);
EXPECT_FALSE(controller()->MenuModelForSection(SECTION_CC));
// An otherwise full but unverified card should be ignored.
CreditCard full_card(test::GetCreditCard());
full_card.set_origin("https://www.example.com");
controller()->GetTestingManager()->AddTestingCreditCard(&full_card);
EXPECT_FALSE(controller()->MenuModelForSection(SECTION_CC));
// A full, verified card should be picked up.
CreditCard verified_card(test::GetCreditCard());
verified_card.set_origin(kSettingsOrigin);
controller()->GetTestingManager()->AddTestingCreditCard(&verified_card);
ui::MenuModel* credit_card_model =
controller()->MenuModelForSection(SECTION_CC);
ASSERT_TRUE(credit_card_model);
EXPECT_EQ(3, credit_card_model->GetItemCount());
}
// Test selecting a shipping address different from billing as address.
TEST_F(AutofillDialogControllerTest, DontUseBillingAsShipping) {
SwitchToAutofill();
AutofillProfile full_profile(test::GetVerifiedProfile());
AutofillProfile full_profile2(test::GetVerifiedProfile2());
CreditCard credit_card(test::GetVerifiedCreditCard());
controller()->GetTestingManager()->AddTestingProfile(&full_profile);
controller()->GetTestingManager()->AddTestingProfile(&full_profile2);
controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
ui::MenuModel* shipping_model =
controller()->MenuModelForSection(SECTION_SHIPPING);
shipping_model->ActivatedAt(2);
controller()->OnAccept();
ASSERT_EQ(20U, form_structure()->field_count());
EXPECT_EQ(ADDRESS_HOME_STATE,
form_structure()->field(9)->Type().GetStorableType());
EXPECT_EQ(ADDRESS_BILLING, form_structure()->field(9)->Type().group());
EXPECT_EQ(ADDRESS_HOME_STATE,
form_structure()->field(16)->Type().GetStorableType());
EXPECT_EQ(ADDRESS_HOME, form_structure()->field(16)->Type().group());
base::string16 billing_state = form_structure()->field(9)->value;
base::string16 shipping_state = form_structure()->field(16)->value;
EXPECT_FALSE(billing_state.empty());
EXPECT_FALSE(shipping_state.empty());
EXPECT_NE(billing_state, shipping_state);
EXPECT_EQ(CREDIT_CARD_NAME,
form_structure()->field(1)->Type().GetStorableType());
base::string16 cc_name = form_structure()->field(1)->value;
EXPECT_EQ(NAME_FULL, form_structure()->field(6)->Type().GetStorableType());
EXPECT_EQ(NAME_BILLING, form_structure()->field(6)->Type().group());
base::string16 billing_name = form_structure()->field(6)->value;
EXPECT_EQ(NAME_FULL, form_structure()->field(13)->Type().GetStorableType());
EXPECT_EQ(NAME, form_structure()->field(13)->Type().group());
base::string16 shipping_name = form_structure()->field(13)->value;
EXPECT_FALSE(cc_name.empty());
EXPECT_FALSE(billing_name.empty());
EXPECT_FALSE(shipping_name.empty());
// Billing name should always be the same as cardholder name.
EXPECT_EQ(cc_name, billing_name);
EXPECT_NE(cc_name, shipping_name);
}
// Test selecting UseBillingForShipping.
TEST_F(AutofillDialogControllerTest, UseBillingAsShipping) {
SwitchToAutofill();
AutofillProfile full_profile(test::GetVerifiedProfile());
controller()->GetTestingManager()->AddTestingProfile(&full_profile);
AutofillProfile full_profile2(test::GetVerifiedProfile2());
controller()->GetTestingManager()->AddTestingProfile(&full_profile2);
CreditCard credit_card(test::GetVerifiedCreditCard());
controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
ASSERT_FALSE(controller()->IsManuallyEditingSection(SECTION_CC));
ASSERT_FALSE(controller()->IsManuallyEditingSection(SECTION_BILLING));
SubmitAndVerifyShippingAndBillingResults();
}
TEST_F(AutofillDialogControllerTest, UseBillingAsShippingManualInput) {
SwitchToAutofill();
ASSERT_TRUE(controller()->IsManuallyEditingSection(SECTION_CC));
ASSERT_TRUE(controller()->IsManuallyEditingSection(SECTION_BILLING));
CreditCard credit_card(test::GetVerifiedCreditCard());
FillInputs(SECTION_CC, credit_card);
AutofillProfile full_profile(test::GetVerifiedProfile());
FillInputs(SECTION_BILLING, full_profile);
SubmitAndVerifyShippingAndBillingResults();
}
// Tests that shipping and billing telephone fields are supported, and filled
// in by their respective profiles. http://crbug.com/244515
TEST_F(AutofillDialogControllerTest, BillingVsShippingPhoneNumber) {
FormFieldData shipping_tel;
shipping_tel.autocomplete_attribute = "shipping tel";
FormFieldData billing_tel;
billing_tel.autocomplete_attribute = "billing tel";
FormFieldData cc_field;
cc_field.autocomplete_attribute = "cc-csc";
FormData form_data;
form_data.fields.push_back(shipping_tel);
form_data.fields.push_back(billing_tel);
form_data.fields.push_back(cc_field);
SetUpControllerWithFormData(form_data);
SwitchToAutofill();
// The profile that will be chosen for the shipping section.
AutofillProfile shipping_profile(test::GetVerifiedProfile());
// The profile that will be chosen for the billing section.
AutofillProfile billing_profile(test::GetVerifiedProfile2());
CreditCard credit_card(test::GetVerifiedCreditCard());
controller()->GetTestingManager()->AddTestingProfile(&shipping_profile);
controller()->GetTestingManager()->AddTestingProfile(&billing_profile);
controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
ui::MenuModel* billing_model =
controller()->MenuModelForSection(SECTION_BILLING);
billing_model->ActivatedAt(1);
controller()->OnAccept();
ASSERT_EQ(3U, form_structure()->field_count());
EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER,
form_structure()->field(0)->Type().GetStorableType());
EXPECT_EQ(PHONE_HOME, form_structure()->field(0)->Type().group());
EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER,
form_structure()->field(1)->Type().GetStorableType());
EXPECT_EQ(PHONE_BILLING, form_structure()->field(1)->Type().group());
EXPECT_EQ(shipping_profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER),
form_structure()->field(0)->value);
EXPECT_EQ(billing_profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER),
form_structure()->field(1)->value);
EXPECT_NE(form_structure()->field(1)->value,
form_structure()->field(0)->value);
}
// Similar to the above, but tests that street-address (i.e. all lines of the
// street address) is successfully filled for both shipping and billing
// sections.
TEST_F(AutofillDialogControllerTest, BillingVsShippingStreetAddress) {
FormFieldData shipping_address;
shipping_address.autocomplete_attribute = "shipping street-address";
FormFieldData billing_address;
billing_address.autocomplete_attribute = "billing street-address";
FormFieldData shipping_address_textarea;
shipping_address_textarea.autocomplete_attribute = "shipping street-address";
shipping_address_textarea.form_control_type = "textarea";
FormFieldData billing_address_textarea;
billing_address_textarea.autocomplete_attribute = "billing street-address";
billing_address_textarea.form_control_type = "textarea";
FormFieldData cc_field;
cc_field.autocomplete_attribute = "cc-csc";
FormData form_data;
form_data.fields.push_back(shipping_address);
form_data.fields.push_back(billing_address);
form_data.fields.push_back(shipping_address_textarea);
form_data.fields.push_back(billing_address_textarea);
form_data.fields.push_back(cc_field);
SetUpControllerWithFormData(form_data);
SwitchToAutofill();
// The profile that will be chosen for the shipping section.
AutofillProfile shipping_profile(test::GetVerifiedProfile());
// The profile that will be chosen for the billing section.
AutofillProfile billing_profile(test::GetVerifiedProfile2());
CreditCard credit_card(test::GetVerifiedCreditCard());
controller()->GetTestingManager()->AddTestingProfile(&shipping_profile);
controller()->GetTestingManager()->AddTestingProfile(&billing_profile);
controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
ui::MenuModel* billing_model =
controller()->MenuModelForSection(SECTION_BILLING);
billing_model->ActivatedAt(1);
controller()->OnAccept();
ASSERT_EQ(5U, form_structure()->field_count());
EXPECT_EQ(ADDRESS_HOME_STREET_ADDRESS,
form_structure()->field(0)->Type().GetStorableType());
EXPECT_EQ(ADDRESS_HOME, form_structure()->field(0)->Type().group());
EXPECT_EQ(ADDRESS_HOME_STREET_ADDRESS,
form_structure()->field(1)->Type().GetStorableType());
EXPECT_EQ(ADDRESS_BILLING, form_structure()->field(1)->Type().group());
// Inexact matching; single-line inputs get the address data concatenated but
// separated by commas.
EXPECT_TRUE(StartsWith(form_structure()->field(0)->value,
shipping_profile.GetRawInfo(ADDRESS_HOME_LINE1),
true));
EXPECT_TRUE(EndsWith(form_structure()->field(0)->value,
shipping_profile.GetRawInfo(ADDRESS_HOME_LINE2),
true));
EXPECT_TRUE(StartsWith(form_structure()->field(1)->value,
billing_profile.GetRawInfo(ADDRESS_HOME_LINE1),
true));
EXPECT_TRUE(EndsWith(form_structure()->field(1)->value,
billing_profile.GetRawInfo(ADDRESS_HOME_LINE2),
true));
// The textareas should be an exact match.
EXPECT_EQ(shipping_profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS),
form_structure()->field(2)->value);
EXPECT_EQ(billing_profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS),
form_structure()->field(3)->value);
EXPECT_NE(form_structure()->field(1)->value,
form_structure()->field(0)->value);
EXPECT_NE(form_structure()->field(3)->value,
form_structure()->field(2)->value);
}
// Test asking for different pieces of the name.
TEST_F(AutofillDialogControllerTest, NamePieces) {
const char* const attributes[] = {
"shipping name",
"billing name",
"billing given-name",
"billing family-name",
"billing additional-name",
"cc-csc"
};
FormData form_data;
for (size_t i = 0; i < arraysize(attributes); ++i) {
FormFieldData field;
field.autocomplete_attribute.assign(attributes[i]);
form_data.fields.push_back(field);
}
SetUpControllerWithFormData(form_data);
SwitchToAutofill();
// Billing.
AutofillProfile test_profile(test::GetVerifiedProfile());
test_profile.SetInfo(AutofillType(NAME_FULL),
ASCIIToUTF16("Fabian Jackson von Nacho"),
"en-US");
controller()->GetTestingManager()->AddTestingProfile(&test_profile);
// Credit card.
CreditCard credit_card(test::GetVerifiedCreditCard());
controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
// Make shipping name different from billing.
AutofillProfile test_profile2(test::GetVerifiedProfile2());
test_profile2.SetInfo(AutofillType(NAME_FULL),
ASCIIToUTF16("Don Ford"),
"en-US");
controller()->GetTestingManager()->AddTestingProfile(&test_profile2);
ui::MenuModel* shipping_model =
controller()->MenuModelForSection(SECTION_SHIPPING);
shipping_model->ActivatedAt(2);
controller()->OnAccept();
EXPECT_EQ(NAME_FULL, form_structure()->field(0)->Type().GetStorableType());
EXPECT_EQ(ASCIIToUTF16("Don Ford"),
form_structure()->field(0)->value);
EXPECT_EQ(NAME_FULL, form_structure()->field(1)->Type().GetStorableType());
EXPECT_EQ(ASCIIToUTF16("Fabian Jackson von Nacho"),
form_structure()->field(1)->value);
EXPECT_EQ(NAME_FIRST, form_structure()->field(2)->Type().GetStorableType());
EXPECT_EQ(ASCIIToUTF16("Fabian"),
form_structure()->field(2)->value);
EXPECT_EQ(NAME_LAST, form_structure()->field(3)->Type().GetStorableType());
EXPECT_EQ(ASCIIToUTF16("von Nacho"),
form_structure()->field(3)->value);
EXPECT_EQ(NAME_MIDDLE, form_structure()->field(4)->Type().GetStorableType());
EXPECT_EQ(ASCIIToUTF16("Jackson"),
form_structure()->field(4)->value);
}
TEST_F(AutofillDialogControllerTest, AcceptLegalDocuments) {
for (size_t i = 0; i < 2; ++i) {
SCOPED_TRACE(testing::Message() << "Case " << i);
EXPECT_CALL(*controller()->GetTestingWalletClient(),
AcceptLegalDocuments(_, _));
EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
EXPECT_CALL(*controller(), LoadRiskFingerprintData());
EXPECT_TRUE(controller()->LegalDocumentLinks().empty());
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
EXPECT_TRUE(controller()->LegalDocumentLinks().empty());
scoped_ptr<wallet::WalletItems> wallet_items =
CompleteAndValidWalletItems();
wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
EXPECT_FALSE(controller()->LegalDocumentLinks().empty());
controller()->OnAccept();
controller()->OnDidAcceptLegalDocuments();
controller()->OnDidLoadRiskFingerprintData("a");
// Now try it all over again with the location disclosure already accepted.
// Nothing should change.
Reset();
base::ListValue preexisting_list;
preexisting_list.AppendString(kFakeEmail);
g_browser_process->local_state()->Set(
::prefs::kAutofillDialogWalletLocationAcceptance,
preexisting_list);
}
}
TEST_F(AutofillDialogControllerTest, RejectLegalDocuments) {
for (size_t i = 0; i < 2; ++i) {
SCOPED_TRACE(testing::Message() << "Case " << i);
EXPECT_CALL(*controller()->GetTestingWalletClient(),
AcceptLegalDocuments(_, _)).Times(0);
scoped_ptr<wallet::WalletItems> wallet_items =
CompleteAndValidWalletItems();
wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
EXPECT_FALSE(controller()->LegalDocumentLinks().empty());
controller()->OnCancel();
// Now try it all over again with the location disclosure already accepted.
// Nothing should change.
Reset();
base::ListValue preexisting_list;
preexisting_list.AppendString(kFakeEmail);
g_browser_process->local_state()->Set(
::prefs::kAutofillDialogWalletLocationAcceptance,
preexisting_list);
}
}
TEST_F(AutofillDialogControllerTest, AcceptLocationDisclosure) {
// Check that accepting the dialog registers the user's name in the list
// of users who have accepted the geolocation terms.
EXPECT_TRUE(g_browser_process->local_state()->GetList(
::prefs::kAutofillDialogWalletLocationAcceptance)->empty());
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
EXPECT_FALSE(controller()->LegalDocumentsText().empty());
EXPECT_TRUE(controller()->LegalDocumentLinks().empty());
controller()->OnAccept();
const base::ListValue* list = g_browser_process->local_state()->GetList(
::prefs::kAutofillDialogWalletLocationAcceptance);
ASSERT_EQ(1U, list->GetSize());
std::string accepted_username;
EXPECT_TRUE(list->GetString(0, &accepted_username));
EXPECT_EQ(kFakeEmail, accepted_username);
// Now check it still works if that list starts off with some other username
// in it.
Reset();
list = g_browser_process->local_state()->GetList(
::prefs::kAutofillDialogWalletLocationAcceptance);
ASSERT_TRUE(list->empty());
std::string kOtherUsername("spouse@example.com");
base::ListValue preexisting_list;
preexisting_list.AppendString(kOtherUsername);
g_browser_process->local_state()->Set(
::prefs::kAutofillDialogWalletLocationAcceptance,
preexisting_list);
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
EXPECT_FALSE(controller()->LegalDocumentsText().empty());
EXPECT_TRUE(controller()->LegalDocumentLinks().empty());
controller()->OnAccept();
list = g_browser_process->local_state()->GetList(
::prefs::kAutofillDialogWalletLocationAcceptance);
ASSERT_EQ(2U, list->GetSize());
EXPECT_NE(list->end(), list->Find(base::StringValue(kFakeEmail)));
EXPECT_NE(list->end(), list->Find(base::StringValue(kOtherUsername)));
// Now check the list doesn't change if the user cancels out of the dialog.
Reset();
list = g_browser_process->local_state()->GetList(
::prefs::kAutofillDialogWalletLocationAcceptance);
ASSERT_TRUE(list->empty());
g_browser_process->local_state()->Set(
::prefs::kAutofillDialogWalletLocationAcceptance,
preexisting_list);
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
EXPECT_FALSE(controller()->LegalDocumentsText().empty());
EXPECT_TRUE(controller()->LegalDocumentLinks().empty());
controller()->OnCancel();
list = g_browser_process->local_state()->GetList(
::prefs::kAutofillDialogWalletLocationAcceptance);
ASSERT_EQ(1U, list->GetSize());
EXPECT_NE(list->end(), list->Find(base::StringValue(kOtherUsername)));
EXPECT_EQ(list->end(), list->Find(base::StringValue(kFakeEmail)));
}
TEST_F(AutofillDialogControllerTest, LegalDocumentOverflow) {
for (size_t number_of_docs = 2; number_of_docs < 11; ++number_of_docs) {
scoped_ptr<wallet::WalletItems> wallet_items =
CompleteAndValidWalletItems();
for (size_t i = 0; i < number_of_docs; ++i)
wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
Reset();
controller()->OnDidGetWalletItems(wallet_items.Pass());
// The dialog is only equipped to handle 2-6 legal documents. More than
// 6 errors out.
if (number_of_docs <= 6U) {
EXPECT_FALSE(controller()->LegalDocumentsText().empty());
} else {
EXPECT_TRUE(controller()->LegalDocumentsText().empty());
EXPECT_EQ(1U, NotificationsOfType(
DialogNotification::WALLET_ERROR).size());
}
}
controller()->OnCancel();
}
// Makes sure the default object IDs are respected.
TEST_F(AutofillDialogControllerTest, WalletDefaultItems) {
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
wallet_items->AddAddress(wallet::GetTestShippingAddress());
wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
controller()->OnDidGetWalletItems(wallet_items.Pass());
// "add", "manage", and 4 suggestions.
EXPECT_EQ(6,
controller()->MenuModelForSection(SECTION_CC_BILLING)->GetItemCount());
EXPECT_TRUE(controller()->MenuModelForSection(SECTION_CC_BILLING)->
IsItemCheckedAt(2));
ASSERT_FALSE(controller()->IsEditingExistingData(SECTION_CC_BILLING));
// "use billing", "add", "manage", and 5 suggestions.
EXPECT_EQ(8,
controller()->MenuModelForSection(SECTION_SHIPPING)->GetItemCount());
EXPECT_TRUE(controller()->MenuModelForSection(SECTION_SHIPPING)->
IsItemCheckedAt(4));
ASSERT_FALSE(controller()->IsEditingExistingData(SECTION_SHIPPING));
}
// Tests that invalid and AMEX default instruments are ignored.
TEST_F(AutofillDialogControllerTest, SelectInstrument) {
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
// Tests if default instrument is invalid, then, the first valid instrument is
// selected instead of the default instrument.
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
wallet_items->AddInstrument(wallet::GetTestMaskedInstrumentInvalid());
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
// 4 suggestions and "add", "manage".
EXPECT_EQ(6,
controller()->MenuModelForSection(SECTION_CC_BILLING)->GetItemCount());
EXPECT_TRUE(controller()->MenuModelForSection(SECTION_CC_BILLING)->
IsItemCheckedAt(0));
// Tests if default instrument is AMEX but Wallet doesn't support
// AMEX on this merchant, then the first valid instrument is
// selected instead of the default instrument.
wallet_items = wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
wallet_items->AddInstrument(
wallet::GetTestMaskedInstrumentAmex(wallet::AMEX_DISALLOWED));
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
// 4 suggestions and "add", "manage".
EXPECT_EQ(6,
controller()->MenuModelForSection(SECTION_CC_BILLING)->GetItemCount());
EXPECT_TRUE(controller()->MenuModelForSection(SECTION_CC_BILLING)->
IsItemCheckedAt(0));
// Tests if default instrument is AMEX and it is allowed on this merchant,
// then it is selected.
wallet_items = wallet::GetTestWalletItems(wallet::AMEX_ALLOWED);
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
wallet_items->AddInstrument(
wallet::GetTestMaskedInstrumentAmex(wallet::AMEX_ALLOWED));
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
// 4 suggestions and "add", "manage".
EXPECT_EQ(6,
controller()->MenuModelForSection(SECTION_CC_BILLING)->GetItemCount());
EXPECT_TRUE(controller()->MenuModelForSection(SECTION_CC_BILLING)->
IsItemCheckedAt(2));
// Tests if only have AMEX and invalid instrument, then "add" is selected.
wallet_items = wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrumentInvalid());
wallet_items->AddInstrument(
wallet::GetTestMaskedInstrumentAmex(wallet::AMEX_DISALLOWED));
controller()->OnDidGetWalletItems(wallet_items.Pass());
// 2 suggestions and "add", "manage".
EXPECT_EQ(4,
controller()->MenuModelForSection(SECTION_CC_BILLING)->GetItemCount());
// "add"
EXPECT_TRUE(controller()->MenuModelForSection(SECTION_CC_BILLING)->
IsItemCheckedAt(2));
}
TEST_F(AutofillDialogControllerTest, SaveAddress) {
EXPECT_CALL(*controller()->GetView(), ModelChanged());
EXPECT_CALL(*controller()->GetTestingWalletClient(),
SaveToWalletMock(testing::IsNull(),
testing::NotNull(),
testing::IsNull(),
testing::IsNull()));
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
// If there is no shipping address in wallet, it will default to
// "same-as-billing" instead of "add-new-item". "same-as-billing" is covered
// by the following tests. The penultimate item in the menu is "add-new-item".
ui::MenuModel* shipping_model =
controller()->MenuModelForSection(SECTION_SHIPPING);
shipping_model->ActivatedAt(shipping_model->GetItemCount() - 2);
AutofillProfile test_profile(test::GetVerifiedProfile());
FillInputs(SECTION_SHIPPING, test_profile);
AcceptAndLoadFakeFingerprint();
}
TEST_F(AutofillDialogControllerTest, SaveInstrument) {
EXPECT_CALL(*controller()->GetView(), ModelChanged());
EXPECT_CALL(*controller()->GetTestingWalletClient(),
SaveToWalletMock(testing::NotNull(),
testing::IsNull(),
testing::IsNull(),
testing::IsNull()));
FillCCBillingInputs();
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddAddress(wallet::GetTestShippingAddress());
SubmitWithWalletItems(wallet_items.Pass());
}
TEST_F(AutofillDialogControllerTest, SaveInstrumentWithInvalidInstruments) {
EXPECT_CALL(*controller()->GetView(), ModelChanged());
EXPECT_CALL(*controller()->GetTestingWalletClient(),
SaveToWalletMock(testing::NotNull(),
testing::IsNull(),
testing::IsNull(),
testing::IsNull()));
FillCCBillingInputs();
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddAddress(wallet::GetTestShippingAddress());
wallet_items->AddInstrument(wallet::GetTestMaskedInstrumentInvalid());
SubmitWithWalletItems(wallet_items.Pass());
}
TEST_F(AutofillDialogControllerTest, SaveInstrumentAndAddress) {
EXPECT_CALL(*controller()->GetTestingWalletClient(),
SaveToWalletMock(testing::NotNull(),
testing::NotNull(),
testing::IsNull(),
testing::IsNull()));
FillCCBillingInputs();
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
SubmitWithWalletItems(wallet_items.Pass());
}
MATCHER(IsUpdatingExistingData, "updating existing Wallet data") {
return !arg->object_id().empty();
}
MATCHER(UsesLocalBillingAddress, "uses the local billing address") {
return arg->street_address()[0] == ASCIIToUTF16(kEditedBillingAddress);
}
// Tests that when using billing address for shipping, and there is no exact
// matched shipping address, then a shipping address should be added.
TEST_F(AutofillDialogControllerTest, BillingForShipping) {
EXPECT_CALL(*controller()->GetTestingWalletClient(),
SaveToWalletMock(testing::IsNull(),
testing::NotNull(),
testing::IsNull(),
testing::IsNull()));
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
// Select "Same as billing" in the address menu.
UseBillingForShipping();
AcceptAndLoadFakeFingerprint();
}
// Tests that when using billing address for shipping, and there is an exact
// matched shipping address, then a shipping address should not be added.
TEST_F(AutofillDialogControllerTest, BillingForShippingHasMatch) {
EXPECT_CALL(*controller()->GetTestingWalletClient(),
SaveToWalletMock(_, _, _, _)).Times(0);
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
scoped_ptr<wallet::WalletItems::MaskedInstrument> instrument =
wallet::GetTestMaskedInstrument();
// Copy billing address as shipping address, and assign an id to it.
scoped_ptr<wallet::Address> shipping_address(
new wallet::Address(instrument->address()));
shipping_address->set_object_id("shipping_address_id");
wallet_items->AddAddress(shipping_address.Pass());
wallet_items->AddInstrument(instrument.Pass());
wallet_items->AddAddress(wallet::GetTestShippingAddress());
controller()->OnDidGetWalletItems(wallet_items.Pass());
// Select "Same as billing" in the address menu.
UseBillingForShipping();
AcceptAndLoadFakeFingerprint();
}
// Test that the local view contents is used when saving a new instrument and
// the user has selected "Same as billing".
TEST_F(AutofillDialogControllerTest, SaveInstrumentSameAsBilling) {
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
ui::MenuModel* model = controller()->MenuModelForSection(SECTION_CC_BILLING);
model->ActivatedAt(model->GetItemCount() - 2);
FieldValueMap outputs;
const DetailInputs& inputs =
controller()->RequestedFieldsForSection(SECTION_CC_BILLING);
AutofillProfile full_profile(test::GetVerifiedProfile());
CreditCard full_card(test::GetCreditCard());
for (size_t i = 0; i < inputs.size(); ++i) {
const ServerFieldType type = inputs[i].type;
if (type == ADDRESS_BILLING_STREET_ADDRESS)
outputs[type] = ASCIIToUTF16(kEditedBillingAddress);
else
outputs[type] = full_profile.GetInfo(AutofillType(type), "en-US");
if (outputs[type].empty())
outputs[type] = full_card.GetInfo(AutofillType(type), "en-US");
}
controller()->GetView()->SetUserInput(SECTION_CC_BILLING, outputs);
controller()->OnAccept();
EXPECT_CALL(*controller()->GetTestingWalletClient(),
SaveToWalletMock(testing::NotNull(),
UsesLocalBillingAddress(),
testing::IsNull(),
testing::IsNull()));
AcceptAndLoadFakeFingerprint();
}
TEST_F(AutofillDialogControllerTest, CancelNoSave) {
EXPECT_CALL(*controller()->GetTestingWalletClient(),
SaveToWalletMock(_, _, _, _)).Times(0);
EXPECT_CALL(*controller()->GetView(), ModelChanged());
controller()->OnDidGetWalletItems(
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED));
controller()->OnCancel();
}
// Checks that clicking the Manage menu item opens a new tab with a different
// URL for Wallet and Autofill.
TEST_F(AutofillDialogControllerTest, ManageItem) {
AutofillProfile full_profile(test::GetVerifiedProfile());
full_profile.set_origin(kSettingsOrigin);
full_profile.SetRawInfo(ADDRESS_HOME_LINE2, base::string16());
controller()->GetTestingManager()->AddTestingProfile(&full_profile);
SwitchToAutofill();
SuggestionsMenuModel* shipping = GetMenuModelForSection(SECTION_SHIPPING);
shipping->ExecuteCommand(shipping->GetItemCount() - 1, 0);
GURL autofill_manage_url = controller()->open_tab_url();
EXPECT_EQ("chrome", autofill_manage_url.scheme());
SwitchToWallet();
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
controller()->SuggestionItemSelected(shipping, shipping->GetItemCount() - 1);
GURL wallet_manage_addresses_url = controller()->open_tab_url();
EXPECT_EQ("https", wallet_manage_addresses_url.scheme());
SuggestionsMenuModel* billing = GetMenuModelForSection(SECTION_CC_BILLING);
controller()->SuggestionItemSelected(billing, billing->GetItemCount() - 1);
GURL wallet_manage_instruments_url = controller()->open_tab_url();
EXPECT_EQ("https", wallet_manage_instruments_url.scheme());
EXPECT_NE(autofill_manage_url, wallet_manage_instruments_url);
EXPECT_NE(wallet_manage_instruments_url, wallet_manage_addresses_url);
}
// Tests that adding an autofill profile and then submitting works.
TEST_F(AutofillDialogControllerTest, AddAutofillProfile) {
SwitchToAutofill();
EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(2);
AutofillProfile full_profile(test::GetVerifiedProfile());
CreditCard credit_card(test::GetVerifiedCreditCard());
controller()->GetTestingManager()->AddTestingProfile(&full_profile);
controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
ui::MenuModel* model = controller()->MenuModelForSection(SECTION_BILLING);
// Activate the "Add billing address" menu item.
model->ActivatedAt(model->GetItemCount() - 2);
// Fill in the inputs from the profile.
FieldValueMap outputs;
const DetailInputs& inputs =
controller()->RequestedFieldsForSection(SECTION_BILLING);
AutofillProfile full_profile2(test::GetVerifiedProfile2());
for (size_t i = 0; i < inputs.size(); ++i) {
const ServerFieldType type = inputs[i].type;
outputs[type] = full_profile2.GetInfo(AutofillType(type), "en-US");
}
controller()->GetView()->SetUserInput(SECTION_BILLING, outputs);
controller()->OnAccept();
const AutofillProfile& added_profile =
controller()->GetTestingManager()->imported_profile();
const DetailInputs& shipping_inputs =
controller()->RequestedFieldsForSection(SECTION_SHIPPING);
for (size_t i = 0; i < shipping_inputs.size(); ++i) {
const ServerFieldType type = shipping_inputs[i].type;
EXPECT_EQ(full_profile2.GetInfo(AutofillType(type), "en-US"),
added_profile.GetInfo(AutofillType(type), "en-US"));
}
}
TEST_F(AutofillDialogControllerTest, VerifyCvv) {
EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
EXPECT_CALL(*controller()->GetTestingWalletClient(),
AuthenticateInstrument(_, _));
SubmitWithWalletItems(CompleteAndValidWalletItems());
EXPECT_TRUE(NotificationsOfType(DialogNotification::REQUIRED_ACTION).empty());
EXPECT_TRUE(controller()->SectionIsActive(SECTION_SHIPPING));
EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC_BILLING));
EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
SuggestionState suggestion_state =
controller()->SuggestionStateForSection(SECTION_CC_BILLING);
EXPECT_TRUE(suggestion_state.extra_text.empty());
controller()->OnDidGetFullWallet(
wallet::GetTestFullWalletWithRequiredActions(
std::vector<wallet::RequiredAction>(1, wallet::VERIFY_CVV)));
ASSERT_TRUE(controller()->IsSubmitPausedOn(wallet::VERIFY_CVV));
EXPECT_FALSE(
NotificationsOfType(DialogNotification::REQUIRED_ACTION).empty());
EXPECT_FALSE(controller()->SectionIsActive(SECTION_SHIPPING));
EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC_BILLING));
suggestion_state =
controller()->SuggestionStateForSection(SECTION_CC_BILLING);
EXPECT_FALSE(suggestion_state.extra_text.empty());
EXPECT_FALSE(controller()->MenuModelForSection(SECTION_CC_BILLING));
EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
controller()->OnAccept();
EXPECT_FALSE(controller()->GetDialogOverlay().image.IsEmpty());
}
TEST_F(AutofillDialogControllerTest, ErrorDuringSubmit) {
EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
SubmitWithWalletItems(CompleteAndValidWalletItems());
EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
controller()->OnWalletError(wallet::WalletClient::UNKNOWN_ERROR);
EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
}
TEST_F(AutofillDialogControllerTest, ErrorDuringVerifyCvv) {
EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
SubmitWithWalletItems(CompleteAndValidWalletItems());
controller()->OnDidGetFullWallet(
wallet::GetTestFullWalletWithRequiredActions(
std::vector<wallet::RequiredAction>(1, wallet::VERIFY_CVV)));
ASSERT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
ASSERT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
controller()->OnWalletError(wallet::WalletClient::UNKNOWN_ERROR);
EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL));
}
// Simulates receiving an INVALID_FORM_FIELD required action while processing a
// |WalletClientDelegate::OnDid{Save,Update}*()| call. This can happen if Online
// Wallet's server validation differs from Chrome's local validation.
TEST_F(AutofillDialogControllerTest, WalletServerSideValidation) {
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
controller()->OnAccept();
std::vector<wallet::RequiredAction> required_actions;
required_actions.push_back(wallet::INVALID_FORM_FIELD);
std::vector<wallet::FormFieldError> form_errors;
form_errors.push_back(
wallet::FormFieldError(wallet::FormFieldError::INVALID_POSTAL_CODE,
wallet::FormFieldError::SHIPPING_ADDRESS));
EXPECT_CALL(*controller()->GetView(), UpdateForErrors());
controller()->OnDidSaveToWallet(std::string(),
std::string(),
required_actions,
form_errors);
}
// Simulates receiving unrecoverable Wallet server validation errors.
TEST_F(AutofillDialogControllerTest, WalletServerSideValidationUnrecoverable) {
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
controller()->OnAccept();
std::vector<wallet::RequiredAction> required_actions;
required_actions.push_back(wallet::INVALID_FORM_FIELD);
std::vector<wallet::FormFieldError> form_errors;
form_errors.push_back(
wallet::FormFieldError(wallet::FormFieldError::UNKNOWN_ERROR,
wallet::FormFieldError::UNKNOWN_LOCATION));
controller()->OnDidSaveToWallet(std::string(),
std::string(),
required_actions,
form_errors);
EXPECT_EQ(1U, NotificationsOfType(
DialogNotification::REQUIRED_ACTION).size());
}
// Test Wallet banners are show in the right situations. These banners promote
// saving details into Wallet (i.e. "[x] Save details to Wallet").
TEST_F(AutofillDialogControllerTest, WalletBanners) {
// Simulate non-signed-in case.
SetUpControllerWithFormData(DefaultFormData());
GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
controller()->OnPassiveSigninFailure(error);
EXPECT_EQ(0U, NotificationsOfType(
DialogNotification::WALLET_USAGE_CONFIRMATION).size());
// Sign in a user with a completed account.
SetUpControllerWithFormData(DefaultFormData());
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
// Full account; should show "Details from Wallet" message.
EXPECT_EQ(1U, NotificationsOfType(
DialogNotification::WALLET_USAGE_CONFIRMATION).size());
SwitchToAutofill();
EXPECT_EQ(1U, NotificationsOfType(
DialogNotification::WALLET_USAGE_CONFIRMATION).size());
// Start over and sign in a user with an incomplete account.
SetUpControllerWithFormData(DefaultFormData());
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
// Partial account.
EXPECT_EQ(1U, NotificationsOfType(
DialogNotification::WALLET_USAGE_CONFIRMATION).size());
SwitchToAutofill();
EXPECT_EQ(1U, NotificationsOfType(
DialogNotification::WALLET_USAGE_CONFIRMATION).size());
// A Wallet error should kill any Wallet promos.
controller()->OnWalletError(wallet::WalletClient::UNKNOWN_ERROR);
EXPECT_EQ(1U, NotificationsOfType(
DialogNotification::WALLET_ERROR).size());
EXPECT_EQ(0U, NotificationsOfType(
DialogNotification::WALLET_USAGE_CONFIRMATION).size());
}
TEST_F(AutofillDialogControllerTest, ViewCancelDoesntSetPref) {
ASSERT_FALSE(profile()->GetPrefs()->HasPrefPath(
::prefs::kAutofillDialogPayWithoutWallet));
SwitchToAutofill();
controller()->OnCancel();
controller()->ViewClosed();
EXPECT_FALSE(profile()->GetPrefs()->HasPrefPath(
::prefs::kAutofillDialogPayWithoutWallet));
}
TEST_F(AutofillDialogControllerTest, SubmitWithSigninErrorDoesntSetPref) {
ASSERT_FALSE(profile()->GetPrefs()->HasPrefPath(
::prefs::kAutofillDialogPayWithoutWallet));
SimulateSigninError();
FillCreditCardInputs();
controller()->OnAccept();
EXPECT_FALSE(profile()->GetPrefs()->HasPrefPath(
::prefs::kAutofillDialogPayWithoutWallet));
}
// Tests that there's an overlay shown while waiting for full wallet items.
TEST_F(AutofillDialogControllerTest, WalletFirstRun) {
EXPECT_TRUE(controller()->GetDialogOverlay().image.IsEmpty());
SubmitWithWalletItems(CompleteAndValidWalletItems());
EXPECT_FALSE(controller()->GetDialogOverlay().image.IsEmpty());
controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
EXPECT_FALSE(controller()->GetDialogOverlay().image.IsEmpty());
EXPECT_FALSE(form_structure());
// Don't make the test wait for 2 seconds.
controller()->ForceFinishSubmit();
EXPECT_TRUE(form_structure());
}
TEST_F(AutofillDialogControllerTest, ViewSubmitSetsPref) {
ASSERT_FALSE(profile()->GetPrefs()->HasPrefPath(
::prefs::kAutofillDialogPayWithoutWallet));
SwitchToAutofill();
FillCreditCardInputs();
controller()->OnAccept();
EXPECT_TRUE(profile()->GetPrefs()->HasPrefPath(
::prefs::kAutofillDialogPayWithoutWallet));
EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
::prefs::kAutofillDialogPayWithoutWallet));
// Try again with a signin error (just leaves the pref alone).
SetUpControllerWithFormData(DefaultFormData());
// Setting up the controller again should not change the pref.
EXPECT_TRUE(profile()->GetPrefs()->HasPrefPath(
::prefs::kAutofillDialogPayWithoutWallet));
EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
::prefs::kAutofillDialogPayWithoutWallet));
SimulateSigninError();
FillCreditCardInputs();
controller()->OnAccept();
EXPECT_TRUE(profile()->GetPrefs()->HasPrefPath(
::prefs::kAutofillDialogPayWithoutWallet));
EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
::prefs::kAutofillDialogPayWithoutWallet));
// Successfully choosing wallet does set the pref.
// Note that OnDidGetWalletItems sets the account chooser to wallet mode.
SetUpControllerWithFormData(DefaultFormData());
controller()->OnDidFetchWalletCookieValue(std::string());
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
controller()->OnAccept();
controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
controller()->ForceFinishSubmit();
EXPECT_TRUE(profile()->GetPrefs()->HasPrefPath(
::prefs::kAutofillDialogPayWithoutWallet));
EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
::prefs::kAutofillDialogPayWithoutWallet));
}
TEST_F(AutofillDialogControllerTest, HideWalletEmail) {
SwitchToAutofill();
// Email field should be showing when using Autofill.
EXPECT_TRUE(controller()->SectionIsActive(SECTION_BILLING));
EXPECT_FALSE(controller()->SectionIsActive(SECTION_CC_BILLING));
EXPECT_TRUE(SectionContainsField(SECTION_BILLING, EMAIL_ADDRESS));
SwitchToWallet();
// Reset the wallet state.
controller()->OnDidGetWalletItems(scoped_ptr<wallet::WalletItems>());
// Setup some wallet state, submit, and get a full wallet to end the flow.
scoped_ptr<wallet::WalletItems> wallet_items = CompleteAndValidWalletItems();
// Filling |form_structure()| depends on the current username and wallet items
// being fetched. Until both of these have occurred, the user should not be
// able to click Submit if using Wallet. The username fetch happened earlier.
EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
controller()->OnDidGetWalletItems(wallet_items.Pass());
EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
// Email field should be absent when using Wallet.
EXPECT_FALSE(controller()->SectionIsActive(SECTION_BILLING));
EXPECT_TRUE(controller()->SectionIsActive(SECTION_CC_BILLING));
EXPECT_FALSE(SectionContainsField(SECTION_CC_BILLING, EMAIL_ADDRESS));
controller()->OnAccept();
controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
controller()->ForceFinishSubmit();
ASSERT_TRUE(form_structure());
size_t i = 0;
for (; i < form_structure()->field_count(); ++i) {
if (form_structure()->field(i)->Type().GetStorableType() == EMAIL_ADDRESS) {
EXPECT_EQ(ASCIIToUTF16(kFakeEmail), form_structure()->field(i)->value);
break;
}
}
EXPECT_LT(i, form_structure()->field_count());
}
// Test if autofill types of returned form structure are correct for billing
// entries.
TEST_F(AutofillDialogControllerTest, AutofillTypes) {
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
controller()->OnAccept();
controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
controller()->ForceFinishSubmit();
ASSERT_TRUE(form_structure());
ASSERT_EQ(20U, form_structure()->field_count());
EXPECT_EQ(EMAIL_ADDRESS,
form_structure()->field(0)->Type().GetStorableType());
EXPECT_EQ(CREDIT_CARD_NUMBER,
form_structure()->field(2)->Type().GetStorableType());
EXPECT_EQ(ADDRESS_HOME_STATE,
form_structure()->field(9)->Type().GetStorableType());
EXPECT_EQ(ADDRESS_BILLING, form_structure()->field(9)->Type().group());
EXPECT_EQ(ADDRESS_HOME_STATE,
form_structure()->field(16)->Type().GetStorableType());
EXPECT_EQ(ADDRESS_HOME, form_structure()->field(16)->Type().group());
}
TEST_F(AutofillDialogControllerTest, SaveDetailsInChrome) {
SwitchToAutofill();
EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(4);
AutofillProfile full_profile(test::GetVerifiedProfile());
controller()->GetTestingManager()->AddTestingProfile(&full_profile);
CreditCard card(test::GetVerifiedCreditCard());
controller()->GetTestingManager()->AddTestingCreditCard(&card);
EXPECT_FALSE(controller()->ShouldOfferToSaveInChrome());
controller()->MenuModelForSection(SECTION_BILLING)->ActivatedAt(0);
EXPECT_FALSE(controller()->ShouldOfferToSaveInChrome());
controller()->MenuModelForSection(SECTION_BILLING)->ActivatedAt(1);
EXPECT_TRUE(controller()->ShouldOfferToSaveInChrome());
profile()->GetPrefs()->SetBoolean(prefs::kAutofillEnabled, false);
EXPECT_FALSE(controller()->ShouldOfferToSaveInChrome());
profile()->GetPrefs()->SetBoolean(prefs::kAutofillEnabled, true);
controller()->MenuModelForSection(SECTION_BILLING)->ActivatedAt(1);
EXPECT_TRUE(controller()->ShouldOfferToSaveInChrome());
profile()->ForceIncognito(true);
EXPECT_FALSE(controller()->ShouldOfferToSaveInChrome());
}
TEST_F(AutofillDialogControllerTest, DisabledAutofill) {
SwitchToAutofill();
ASSERT_TRUE(profile()->GetPrefs()->GetBoolean(prefs::kAutofillEnabled));
AutofillProfile verified_profile(test::GetVerifiedProfile());
controller()->GetTestingManager()->AddTestingProfile(&verified_profile);
CreditCard credit_card(test::GetVerifiedCreditCard());
controller()->GetTestingManager()->AddTestingCreditCard(&credit_card);
// Verify suggestions menus should be showing when Autofill is enabled.
EXPECT_TRUE(controller()->MenuModelForSection(SECTION_CC));
EXPECT_TRUE(controller()->MenuModelForSection(SECTION_BILLING));
EXPECT_EQ(
4, controller()->MenuModelForSection(SECTION_SHIPPING)->GetItemCount());
EXPECT_CALL(*controller()->GetView(), ModelChanged());
profile()->GetPrefs()->SetBoolean(prefs::kAutofillEnabled, false);
// Verify billing and credit card suggestions menus are hidden when Autofill
// is disabled.
EXPECT_FALSE(controller()->MenuModelForSection(SECTION_CC));
EXPECT_FALSE(controller()->MenuModelForSection(SECTION_BILLING));
// And that the shipping suggestions menu has less selections.
EXPECT_EQ(
2, controller()->MenuModelForSection(SECTION_SHIPPING)->GetItemCount());
// Additionally, editing fields should not show Autofill popups.
ASSERT_NO_FATAL_FAILURE(controller()->UserEditedOrActivatedInput(
SECTION_BILLING,
NAME_BILLING_FULL,
gfx::NativeView(),
gfx::Rect(),
verified_profile.GetInfo(AutofillType(NAME_FULL), "en-US").substr(0, 1),
true));
EXPECT_EQ(UNKNOWN_TYPE, controller()->popup_input_type());
}
// Tests that user is prompted when using instrument with minimal address.
TEST_F(AutofillDialogControllerTest, UpgradeMinimalAddress) {
// A minimal address being selected should trigger error validation in the
// view. Called once for each incomplete suggestion.
EXPECT_CALL(*controller()->GetView(), UpdateForErrors());
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrumentWithIdAndAddress(
"id", wallet::GetTestMinimalAddress()));
scoped_ptr<wallet::Address> address(wallet::GetTestShippingAddress());
address->set_is_complete_address(false);
wallet_items->AddAddress(address.Pass());
controller()->OnDidGetWalletItems(wallet_items.Pass());
// Assert that dialog's SECTION_CC_BILLING section is in edit mode.
ASSERT_TRUE(controller()->IsEditingExistingData(SECTION_CC_BILLING));
// Shipping section should be in edit mode because of
// is_minimal_shipping_address.
ASSERT_TRUE(controller()->IsEditingExistingData(SECTION_SHIPPING));
}
TEST_F(AutofillDialogControllerTest, RiskNeverLoadsWithPendingLegalDocuments) {
EXPECT_CALL(*controller(), LoadRiskFingerprintData()).Times(0);
scoped_ptr<wallet::WalletItems> wallet_items = CompleteAndValidWalletItems();
wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
controller()->OnAccept();
}
TEST_F(AutofillDialogControllerTest, RiskLoadsAfterAcceptingLegalDocuments) {
EXPECT_CALL(*controller(), LoadRiskFingerprintData()).Times(0);
scoped_ptr<wallet::WalletItems> wallet_items = CompleteAndValidWalletItems();
wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
wallet_items->AddLegalDocument(wallet::GetTestLegalDocument());
controller()->OnDidGetWalletItems(wallet_items.Pass());
testing::Mock::VerifyAndClear(controller());
EXPECT_CALL(*controller(), LoadRiskFingerprintData());
controller()->OnAccept();
// Simulate a risk load and verify |GetRiskData()| matches the encoded value.
controller()->OnDidAcceptLegalDocuments();
controller()->OnDidLoadRiskFingerprintData("a");
EXPECT_EQ("a", controller()->GetRiskData());
}
TEST_F(AutofillDialogControllerTest, NoManageMenuItemForNewWalletUsers) {
// Make sure the menu model item is created for a returning Wallet user.
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
wallet_items->AddAddress(wallet::GetTestShippingAddress());
controller()->OnDidGetWalletItems(wallet_items.Pass());
EXPECT_TRUE(controller()->MenuModelForSection(SECTION_CC_BILLING));
// "Same as billing", "123 address", "Add address...", and "Manage addresses".
EXPECT_EQ(
4, controller()->MenuModelForSection(SECTION_SHIPPING)->GetItemCount());
// Make sure the menu model item is not created for new Wallet users.
base::DictionaryValue dict;
scoped_ptr<base::ListValue> required_actions(new base::ListValue);
required_actions->AppendString("setup_wallet");
dict.Set("required_action", required_actions.release());
controller()->OnDidGetWalletItems(
wallet::WalletItems::CreateWalletItems(dict).Pass());
EXPECT_FALSE(controller()->MenuModelForSection(SECTION_CC_BILLING));
// "Same as billing" and "Add address...".
EXPECT_EQ(
2, controller()->MenuModelForSection(SECTION_SHIPPING)->GetItemCount());
}
TEST_F(AutofillDialogControllerTest, ShippingSectionCanBeHidden) {
FormFieldData email_field;
email_field.autocomplete_attribute = "email";
FormFieldData cc_field;
cc_field.autocomplete_attribute = "cc-number";
FormFieldData billing_field;
billing_field.autocomplete_attribute = "billing address-level1";
FormData form_data;
form_data.fields.push_back(email_field);
form_data.fields.push_back(cc_field);
form_data.fields.push_back(billing_field);
AutofillProfile full_profile(test::GetVerifiedProfile());
controller()->GetTestingManager()->AddTestingProfile(&full_profile);
SetUpControllerWithFormData(form_data);
SwitchToAutofill();
EXPECT_FALSE(controller()->SectionIsActive(SECTION_SHIPPING));
FillCreditCardInputs();
controller()->OnAccept();
EXPECT_TRUE(form_structure());
}
TEST_F(AutofillDialogControllerTest, ShippingSectionCanBeHiddenForWallet) {
FormFieldData email_field;
email_field.autocomplete_attribute = "email";
FormFieldData cc_field;
cc_field.autocomplete_attribute = "cc-number";
FormFieldData billing_field;
billing_field.autocomplete_attribute = "billing address-level1";
FormData form_data;
form_data.fields.push_back(email_field);
form_data.fields.push_back(cc_field);
form_data.fields.push_back(billing_field);
SetUpControllerWithFormData(form_data);
EXPECT_FALSE(controller()->SectionIsActive(SECTION_SHIPPING));
EXPECT_FALSE(controller()->IsShippingAddressRequired());
EXPECT_CALL(*controller()->GetTestingWalletClient(), GetFullWallet(_));
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
SubmitWithWalletItems(wallet_items.Pass());
controller()->OnDidGetFullWallet(wallet::GetTestFullWalletInstrumentOnly());
controller()->ForceFinishSubmit();
EXPECT_TRUE(form_structure());
}
TEST_F(AutofillDialogControllerTest, NotProdNotification) {
// To make IsPayingWithWallet() true.
controller()->OnDidGetWalletItems(
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED));
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
ASSERT_EQ(
"",
command_line->GetSwitchValueASCII(switches::kWalletServiceUseSandbox));
command_line->AppendSwitchASCII(switches::kWalletServiceUseSandbox, "1");
EXPECT_EQ(1U,
NotificationsOfType(DialogNotification::DEVELOPER_WARNING).size());
}
TEST_F(AutofillDialogControllerTest, NoNotProdNotification) {
// To make IsPayingWithWallet() true.
controller()->OnDidGetWalletItems(
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED));
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
ASSERT_EQ(
"",
command_line->GetSwitchValueASCII(switches::kWalletServiceUseSandbox));
command_line->AppendSwitchASCII(switches::kWalletServiceUseSandbox, "0");
EXPECT_EQ(0U,
NotificationsOfType(DialogNotification::DEVELOPER_WARNING).size());
}
// Ensure Wallet instruments marked expired by the server are shown as invalid.
TEST_F(AutofillDialogControllerTest, WalletExpiredCard) {
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrumentExpired());
controller()->OnDidGetWalletItems(wallet_items.Pass());
EXPECT_TRUE(controller()->IsEditingExistingData(SECTION_CC_BILLING));
const DetailInputs& inputs =
controller()->RequestedFieldsForSection(SECTION_CC_BILLING);
FieldValueMap outputs;
CopyInitialValues(inputs, &outputs);
// The local inputs are invalid because the server said so. They'll
// stay invalid until they differ from the remotely fetched model.
ValidityMessages messages = controller()->InputsAreValid(SECTION_CC_BILLING,
outputs);
EXPECT_TRUE(messages.HasSureError(CREDIT_CARD_EXP_MONTH));
EXPECT_TRUE(messages.HasSureError(CREDIT_CARD_EXP_4_DIGIT_YEAR));
// Make the local input year differ from the instrument.
CopyInitialValues(inputs, &outputs);
outputs[CREDIT_CARD_EXP_4_DIGIT_YEAR] = ASCIIToUTF16("3002");
messages = controller()->InputsAreValid(SECTION_CC_BILLING, outputs);
EXPECT_FALSE(HasAnyError(messages, CREDIT_CARD_EXP_MONTH));
EXPECT_FALSE(HasAnyError(messages, CREDIT_CARD_EXP_4_DIGIT_YEAR));
// Make the local input month differ from the instrument.
CopyInitialValues(inputs, &outputs);
outputs[CREDIT_CARD_EXP_MONTH] = ASCIIToUTF16("06");
messages = controller()->InputsAreValid(SECTION_CC_BILLING, outputs);
EXPECT_FALSE(HasAnyError(messages, CREDIT_CARD_EXP_MONTH));
EXPECT_FALSE(HasAnyError(messages, CREDIT_CARD_EXP_4_DIGIT_YEAR));
}
TEST_F(AutofillDialogControllerTest, ChooseAnotherInstrumentOrAddress) {
SubmitWithWalletItems(CompleteAndValidWalletItems());
EXPECT_EQ(0U, NotificationsOfType(
DialogNotification::REQUIRED_ACTION).size());
EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems(_, _));
controller()->OnDidGetFullWallet(
wallet::GetTestFullWalletWithRequiredActions(
std::vector<wallet::RequiredAction>(
1, wallet::CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS)));
EXPECT_EQ(1U, NotificationsOfType(
DialogNotification::REQUIRED_ACTION).size());
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
controller()->OnAccept();
EXPECT_EQ(0U, NotificationsOfType(
DialogNotification::REQUIRED_ACTION).size());
}
TEST_F(AutofillDialogControllerTest, NewCardBubbleShown) {
SwitchToAutofill();
FillCreditCardInputs();
controller()->OnAccept();
controller()->ViewClosed();
EXPECT_EQ(1, mock_new_card_bubble_controller()->bubbles_shown());
EXPECT_EQ(0, test_generated_bubble_controller()->bubbles_shown());
}
TEST_F(AutofillDialogControllerTest, GeneratedCardBubbleShown) {
SubmitWithWalletItems(CompleteAndValidWalletItems());
controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
controller()->ForceFinishSubmit();
controller()->ViewClosed();
EXPECT_EQ(0, mock_new_card_bubble_controller()->bubbles_shown());
EXPECT_EQ(1, test_generated_bubble_controller()->bubbles_shown());
}
// Verify that new Wallet data is fetched when the user switches away from the
// tab hosting the Autofill dialog and back. Also verify that the user's
// selection is preserved across this re-fetch.
TEST_F(AutofillDialogControllerTest, ReloadWalletItemsOnActivation) {
// Initialize some Wallet data.
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
wallet_items->AddAddress(wallet::GetTestShippingAddress());
controller()->OnDidGetWalletItems(wallet_items.Pass());
// Initially, the default entries should be selected.
ui::MenuModel* cc_billing_model =
controller()->MenuModelForSection(SECTION_CC_BILLING);
ui::MenuModel* shipping_model =
controller()->MenuModelForSection(SECTION_SHIPPING);
// "add", "manage", and 2 suggestions.
ASSERT_EQ(4, cc_billing_model->GetItemCount());
EXPECT_TRUE(cc_billing_model->IsItemCheckedAt(0));
// "use billing", "add", "manage", and 2 suggestions.
ASSERT_EQ(5, shipping_model->GetItemCount());
EXPECT_TRUE(shipping_model->IsItemCheckedAt(2));
// Select entries other than the defaults.
cc_billing_model->ActivatedAt(1);
shipping_model->ActivatedAt(1);
// 2 suggestions, "add", and "manage".
ASSERT_EQ(4, cc_billing_model->GetItemCount());
EXPECT_TRUE(cc_billing_model->IsItemCheckedAt(1));
// "use billing", 2 suggestions, "add", "manage".
ASSERT_EQ(5, shipping_model->GetItemCount());
EXPECT_TRUE(shipping_model-> IsItemCheckedAt(1));
// Simulate switching away from the tab and back. This should issue a request
// for wallet items.
controller()->ClearLastWalletItemsFetchTimestampForTesting();
EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems(_, _));
controller()->TabActivated();
// Simulate a response that includes different items.
wallet_items = wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrumentExpired());
wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
controller()->OnDidGetWalletItems(wallet_items.Pass());
// The previously selected entries should still be selected.
// 3 suggestions, "add", and "manage".
ASSERT_EQ(5, cc_billing_model->GetItemCount());
EXPECT_TRUE(cc_billing_model->IsItemCheckedAt(2));
// "use billing", 1 suggestion, "add", and "manage".
ASSERT_EQ(4, shipping_model->GetItemCount());
EXPECT_TRUE(shipping_model->IsItemCheckedAt(1));
}
// Verify that if the default values change when re-fetching Wallet data, these
// new default values are selected in the dialog.
TEST_F(AutofillDialogControllerTest,
ReloadWalletItemsOnActivationWithNewDefaults) {
// Initialize some Wallet data.
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddInstrument(wallet::GetTestMaskedInstrument());
wallet_items->AddInstrument(wallet::GetTestNonDefaultMaskedInstrument());
wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
wallet_items->AddAddress(wallet::GetTestShippingAddress());
controller()->OnDidGetWalletItems(wallet_items.Pass());
// Initially, the default entries should be selected.
ui::MenuModel* cc_billing_model =
controller()->MenuModelForSection(SECTION_CC_BILLING);
ui::MenuModel* shipping_model =
controller()->MenuModelForSection(SECTION_SHIPPING);
// 2 suggestions, "add", and "manage".
ASSERT_EQ(4, cc_billing_model->GetItemCount());
EXPECT_TRUE(cc_billing_model->IsItemCheckedAt(0));
// "use billing", 2 suggestions, "add", and "manage".
ASSERT_EQ(5, shipping_model->GetItemCount());
EXPECT_TRUE(shipping_model->IsItemCheckedAt(2));
// Simulate switching away from the tab and back. This should issue a request
// for wallet items.
controller()->ClearLastWalletItemsFetchTimestampForTesting();
EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems(_, _));
controller()->TabActivated();
// Simulate a response that includes different default values.
wallet_items =
wallet::GetTestWalletItemsWithDefaultIds("new_default_instrument_id",
"new_default_address_id",
wallet::AMEX_DISALLOWED);
scoped_ptr<wallet::Address> other_address = wallet::GetTestShippingAddress();
other_address->set_object_id("other_address_id");
scoped_ptr<wallet::Address> new_default_address =
wallet::GetTestNonDefaultShippingAddress();
new_default_address->set_object_id("new_default_address_id");
wallet_items->AddInstrument(
wallet::GetTestMaskedInstrumentWithId("other_instrument_id"));
wallet_items->AddInstrument(
wallet::GetTestMaskedInstrumentWithId("new_default_instrument_id"));
wallet_items->AddAddress(new_default_address.Pass());
wallet_items->AddAddress(other_address.Pass());
controller()->OnDidGetWalletItems(wallet_items.Pass());
// The new default entries should be selected.
// 2 suggestions, "add", and "manage".
ASSERT_EQ(4, cc_billing_model->GetItemCount());
EXPECT_TRUE(cc_billing_model->IsItemCheckedAt(1));
// "use billing", 2 suggestions, "add", and "manage".
ASSERT_EQ(5, shipping_model->GetItemCount());
EXPECT_TRUE(shipping_model->IsItemCheckedAt(1));
}
TEST_F(AutofillDialogControllerTest, ReloadWithEmptyWalletItems) {
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
controller()->MenuModelForSection(SECTION_CC_BILLING)->ActivatedAt(1);
controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(1);
controller()->ClearLastWalletItemsFetchTimestampForTesting();
EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems(_, _));
controller()->TabActivated();
controller()->OnDidGetWalletItems(
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED));
EXPECT_FALSE(controller()->MenuModelForSection(SECTION_CC_BILLING));
EXPECT_EQ(
3, controller()->MenuModelForSection(SECTION_SHIPPING)->GetItemCount());
}
TEST_F(AutofillDialogControllerTest, SaveInChromeByDefault) {
EXPECT_TRUE(controller()->ShouldSaveInChrome());
SwitchToAutofill();
FillCreditCardInputs();
controller()->OnAccept();
EXPECT_TRUE(controller()->ShouldSaveInChrome());
}
TEST_F(AutofillDialogControllerTest,
SaveInChromePreferenceNotRememberedOnCancel) {
EXPECT_TRUE(controller()->ShouldSaveInChrome());
SwitchToAutofill();
controller()->GetView()->CheckSaveDetailsLocallyCheckbox(false);
controller()->OnCancel();
EXPECT_TRUE(controller()->ShouldSaveInChrome());
}
TEST_F(AutofillDialogControllerTest,
SaveInChromePreferenceRememberedOnSuccess) {
EXPECT_TRUE(controller()->ShouldSaveInChrome());
SwitchToAutofill();
FillCreditCardInputs();
controller()->GetView()->CheckSaveDetailsLocallyCheckbox(false);
controller()->OnAccept();
EXPECT_FALSE(controller()->ShouldSaveInChrome());
}
TEST_F(AutofillDialogControllerTest,
SubmitButtonIsDisabled_SpinnerFinishesBeforeDelay) {
// Reset Wallet state.
controller()->OnDidGetWalletItems(scoped_ptr<wallet::WalletItems>());
EXPECT_EQ(1, controller()->get_submit_button_delay_count());
// Begin the submit button delay.
controller()->SimulateSubmitButtonDelayBegin();
EXPECT_TRUE(controller()->ShouldShowSpinner());
EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
// Stop the spinner.
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
EXPECT_FALSE(controller()->ShouldShowSpinner());
EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
// End the submit button delay.
controller()->SimulateSubmitButtonDelayEnd();
EXPECT_FALSE(controller()->ShouldShowSpinner());
EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
}
TEST_F(AutofillDialogControllerTest,
SubmitButtonIsDisabled_SpinnerFinishesAfterDelay) {
// Reset Wallet state.
controller()->OnDidGetWalletItems(scoped_ptr<wallet::WalletItems>());
EXPECT_EQ(1, controller()->get_submit_button_delay_count());
// Begin the submit button delay.
controller()->SimulateSubmitButtonDelayBegin();
EXPECT_TRUE(controller()->ShouldShowSpinner());
EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
// End the submit button delay.
controller()->SimulateSubmitButtonDelayEnd();
EXPECT_TRUE(controller()->ShouldShowSpinner());
EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
// Stop the spinner.
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
EXPECT_FALSE(controller()->ShouldShowSpinner());
EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
}
TEST_F(AutofillDialogControllerTest, SubmitButtonIsDisabled_NoSpinner) {
SwitchToAutofill();
EXPECT_EQ(1, controller()->get_submit_button_delay_count());
// Begin the submit button delay.
controller()->SimulateSubmitButtonDelayBegin();
EXPECT_FALSE(controller()->ShouldShowSpinner());
EXPECT_FALSE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
// End the submit button delay.
controller()->SimulateSubmitButtonDelayEnd();
EXPECT_FALSE(controller()->ShouldShowSpinner());
EXPECT_TRUE(controller()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
}
TEST_F(AutofillDialogControllerTest, IconsForFields_NoCreditCard) {
FieldValueMap values;
values[EMAIL_ADDRESS] = ASCIIToUTF16(kFakeEmail);
FieldIconMap icons = controller()->IconsForFields(values);
EXPECT_TRUE(icons.empty());
}
TEST_F(AutofillDialogControllerTest, IconsForFields_CreditCardNumberOnly) {
FieldValueMap values;
values[EMAIL_ADDRESS] = ASCIIToUTF16(kFakeEmail);
values[CREDIT_CARD_NUMBER] = ASCIIToUTF16(kTestCCNumberVisa);
FieldIconMap icons = controller()->IconsForFields(values);
EXPECT_EQ(1UL, icons.size());
EXPECT_EQ(1UL, icons.count(CREDIT_CARD_NUMBER));
}
TEST_F(AutofillDialogControllerTest, IconsForFields_CvcOnly) {
FieldValueMap values;
values[EMAIL_ADDRESS] = ASCIIToUTF16(kFakeEmail);
values[CREDIT_CARD_VERIFICATION_CODE] = ASCIIToUTF16("123");
FieldIconMap icons = controller()->IconsForFields(values);
EXPECT_EQ(1UL, icons.size());
EXPECT_EQ(1UL, icons.count(CREDIT_CARD_VERIFICATION_CODE));
}
TEST_F(AutofillDialogControllerTest, IconsForFields_BothCreditCardAndCvc) {
FieldValueMap values;
values[EMAIL_ADDRESS] = ASCIIToUTF16(kFakeEmail);
values[CREDIT_CARD_NUMBER] = ASCIIToUTF16(kTestCCNumberVisa);
values[CREDIT_CARD_VERIFICATION_CODE] = ASCIIToUTF16("123");
FieldIconMap icons = controller()->IconsForFields(values);
EXPECT_EQ(2UL, icons.size());
EXPECT_EQ(1UL, icons.count(CREDIT_CARD_VERIFICATION_CODE));
EXPECT_EQ(1UL, icons.count(CREDIT_CARD_NUMBER));
}
TEST_F(AutofillDialogControllerTest, FieldControlsIcons) {
EXPECT_TRUE(controller()->FieldControlsIcons(CREDIT_CARD_NUMBER));
EXPECT_FALSE(controller()->FieldControlsIcons(CREDIT_CARD_VERIFICATION_CODE));
EXPECT_FALSE(controller()->FieldControlsIcons(EMAIL_ADDRESS));
}
TEST_F(AutofillDialogControllerTest, SaveCreditCardIncludesName_NoBilling) {
SwitchToAutofill();
CreditCard test_credit_card(test::GetVerifiedCreditCard());
FillInputs(SECTION_CC, test_credit_card);
AutofillProfile test_profile(test::GetVerifiedProfile());
FillInputs(SECTION_BILLING, test_profile);
UseBillingForShipping();
controller()->GetView()->CheckSaveDetailsLocallyCheckbox(true);
controller()->OnAccept();
TestPersonalDataManager* test_pdm = controller()->GetTestingManager();
const CreditCard& imported_card = test_pdm->imported_credit_card();
EXPECT_EQ(test_profile.GetInfo(AutofillType(NAME_FULL), "en-US"),
imported_card.GetRawInfo(CREDIT_CARD_NAME));
}
TEST_F(AutofillDialogControllerTest, SaveCreditCardIncludesName_WithBilling) {
SwitchToAutofill();
TestPersonalDataManager* test_pdm = controller()->GetTestingManager();
AutofillProfile test_profile(test::GetVerifiedProfile());
EXPECT_CALL(*controller()->GetView(), ModelChanged());
test_pdm->AddTestingProfile(&test_profile);
ASSERT_TRUE(controller()->MenuModelForSection(SECTION_BILLING));
CreditCard test_credit_card(test::GetVerifiedCreditCard());
FillInputs(SECTION_CC, test_credit_card);
controller()->GetView()->CheckSaveDetailsLocallyCheckbox(true);
controller()->OnAccept();
const CreditCard& imported_card = test_pdm->imported_credit_card();
EXPECT_EQ(test_profile.GetInfo(AutofillType(NAME_FULL), "en-US"),
imported_card.GetRawInfo(CREDIT_CARD_NAME));
controller()->ViewClosed();
}
TEST_F(AutofillDialogControllerTest, InputEditability) {
// Empty wallet items: all fields are editable.
scoped_ptr<wallet::WalletItems> items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
controller()->OnDidGetWalletItems(items.Pass());
DialogSection sections[] = { SECTION_CC_BILLING, SECTION_SHIPPING };
for (size_t i = 0; i < arraysize(sections); ++i) {
const DetailInputs& inputs =
controller()->RequestedFieldsForSection(sections[i]);
for (size_t j = 0; j < inputs.size(); ++j) {
EXPECT_TRUE(controller()->InputIsEditable(inputs[j], sections[i]));
}
}
// Expired instrument: CC number + CVV are not editable.
items = wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
scoped_ptr<wallet::WalletItems::MaskedInstrument> expired_instrument =
wallet::GetTestMaskedInstrumentExpired();
items->AddInstrument(expired_instrument.Pass());
controller()->OnDidGetWalletItems(items.Pass());
EXPECT_TRUE(controller()->IsEditingExistingData(SECTION_CC_BILLING));
FieldValueMap outputs;
CopyInitialValues(
controller()->RequestedFieldsForSection(SECTION_CC_BILLING),
&outputs);
controller()->GetView()->SetUserInput(SECTION_CC_BILLING, outputs);
for (size_t i = 0; i < arraysize(sections); ++i) {
const DetailInputs& inputs =
controller()->RequestedFieldsForSection(sections[i]);
for (size_t j = 0; j < inputs.size(); ++j) {
if (inputs[j].type == CREDIT_CARD_NUMBER ||
inputs[j].type == CREDIT_CARD_VERIFICATION_CODE) {
EXPECT_FALSE(controller()->InputIsEditable(inputs[j], sections[i]));
} else {
EXPECT_TRUE(controller()->InputIsEditable(inputs[j], sections[i]));
}
}
}
// User changes the billing address; same story.
outputs[ADDRESS_BILLING_ZIP] = ASCIIToUTF16("77025");
controller()->GetView()->SetUserInput(SECTION_CC_BILLING, outputs);
for (size_t i = 0; i < arraysize(sections); ++i) {
const DetailInputs& inputs =
controller()->RequestedFieldsForSection(sections[i]);
for (size_t j = 0; j < inputs.size(); ++j) {
if (inputs[j].type == CREDIT_CARD_NUMBER ||
inputs[j].type == CREDIT_CARD_VERIFICATION_CODE) {
EXPECT_FALSE(controller()->InputIsEditable(inputs[j], sections[i]));
} else {
EXPECT_TRUE(controller()->InputIsEditable(inputs[j], sections[i]));
}
}
}
// User changes a detail of the CC itself (expiration date), CVV is now
// editable (and mandatory).
outputs[CREDIT_CARD_EXP_MONTH] = ASCIIToUTF16("06");
controller()->GetView()->SetUserInput(SECTION_CC_BILLING, outputs);
for (size_t i = 0; i < arraysize(sections); ++i) {
const DetailInputs& inputs =
controller()->RequestedFieldsForSection(sections[i]);
for (size_t j = 0; j < inputs.size(); ++j) {
if (inputs[j].type == CREDIT_CARD_NUMBER)
EXPECT_FALSE(controller()->InputIsEditable(inputs[j], sections[i]));
else
EXPECT_TRUE(controller()->InputIsEditable(inputs[j], sections[i]));
}
}
}
// When the default country is something besides US, wallet is not selected
// and the account chooser shouldn't be visible.
TEST_F(AutofillDialogControllerTest, HideWalletInOtherCountries) {
// Addresses from different countries.
AutofillProfile us_profile(base::GenerateGUID(), kSettingsOrigin),
es_profile(base::GenerateGUID(), kSettingsOrigin),
es_profile2(base::GenerateGUID(), kSettingsOrigin);
us_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
es_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("ES"));
es_profile2.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("ES"));
// If US is indicated (via timezone), show Wallet.
ResetControllerWithFormData(DefaultFormData());
controller()->GetTestingManager()->set_timezone_country_code("US");
controller()->Show();
EXPECT_TRUE(
controller()->AccountChooserModelForTesting()->WalletIsSelected());
controller()->OnDidFetchWalletCookieValue(std::string());
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
EXPECT_TRUE(controller()->ShouldShowAccountChooser());
EXPECT_TRUE(
controller()->AccountChooserModelForTesting()->WalletIsSelected());
// If US is not indicated, don't show Wallet.
ResetControllerWithFormData(DefaultFormData());
controller()->GetTestingManager()->set_timezone_country_code("ES");
controller()->Show();
controller()->OnDidFetchWalletCookieValue(std::string());
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
EXPECT_FALSE(controller()->ShouldShowAccountChooser());
// If US is indicated (via a profile), show Wallet.
ResetControllerWithFormData(DefaultFormData());
controller()->GetTestingManager()->set_timezone_country_code("ES");
controller()->GetTestingManager()->AddTestingProfile(&us_profile);
controller()->Show();
controller()->OnDidFetchWalletCookieValue(std::string());
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
EXPECT_TRUE(controller()->ShouldShowAccountChooser());
EXPECT_TRUE(
controller()->AccountChooserModelForTesting()->WalletIsSelected());
// Make sure the profile doesn't just override the timezone.
ResetControllerWithFormData(DefaultFormData());
controller()->GetTestingManager()->set_timezone_country_code("US");
controller()->GetTestingManager()->AddTestingProfile(&es_profile);
controller()->Show();
controller()->OnDidFetchWalletCookieValue(std::string());
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
EXPECT_TRUE(controller()->ShouldShowAccountChooser());
EXPECT_TRUE(
controller()->AccountChooserModelForTesting()->WalletIsSelected());
// Only takes one US address to enable Wallet.
ResetControllerWithFormData(DefaultFormData());
controller()->GetTestingManager()->set_timezone_country_code("FR");
controller()->GetTestingManager()->AddTestingProfile(&es_profile);
controller()->GetTestingManager()->AddTestingProfile(&es_profile2);
controller()->GetTestingManager()->AddTestingProfile(&us_profile);
controller()->Show();
controller()->OnDidFetchWalletCookieValue(std::string());
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
EXPECT_TRUE(controller()->ShouldShowAccountChooser());
EXPECT_TRUE(
controller()->AccountChooserModelForTesting()->WalletIsSelected());
}
TEST_F(AutofillDialogControllerTest, DontGetWalletTillNecessary) {
// When starting on local data mode, the dialog will provide a "Use Google
// Wallet" link.
profile()->GetPrefs()->SetBoolean(
::prefs::kAutofillDialogPayWithoutWallet, true);
ResetControllerWithFormData(DefaultFormData());
controller()->Show();
base::string16 use_wallet_text = controller()->SignInLinkText();
EXPECT_EQ(TestAutofillDialogController::NOT_CHECKED,
controller()->SignedInState());
// When clicked, this link will ask for wallet items. If there's a signin
// failure, the link will switch to "Sign in to use Google Wallet".
EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems(_, _));
controller()->SignInLinkClicked();
EXPECT_NE(TestAutofillDialogController::NOT_CHECKED,
controller()->SignedInState());
controller()->OnDidFetchWalletCookieValue(std::string());
controller()->OnDidGetWalletItems(CompleteAndValidWalletItems());
controller()->OnPassiveSigninFailure(GoogleServiceAuthError(
GoogleServiceAuthError::CONNECTION_FAILED));
EXPECT_NE(use_wallet_text, controller()->SignInLinkText());
}
TEST_F(AutofillDialogControllerTest, MultiAccountSwitch) {
std::vector<std::string> users;
users.push_back("user_1@example.com");
users.push_back("user_2@example.com");
controller()->OnDidGetWalletItems(
wallet::GetTestWalletItemsWithUsers(users, 0));
// Items should be: Account 1, account 2, add account, disable wallet.
EXPECT_EQ(4, controller()->MenuModelForAccountChooser()->GetItemCount());
EXPECT_EQ(0U, controller()->GetTestingWalletClient()->user_index());
// GetWalletItems should be called when the user switches accounts.
EXPECT_CALL(*controller()->GetTestingWalletClient(), GetWalletItems(_, _));
controller()->MenuModelForAccountChooser()->ActivatedAt(1);
// The wallet client should be updated to the new user index.
EXPECT_EQ(1U, controller()->GetTestingWalletClient()->user_index());
}
TEST_F(AutofillDialogControllerTest, PassiveAuthFailure) {
controller()->OnDidGetWalletItems(
wallet::GetTestWalletItemsWithRequiredAction(
wallet::PASSIVE_GAIA_AUTH));
EXPECT_TRUE(controller()->ShouldShowSpinner());
controller()->OnPassiveSigninFailure(GoogleServiceAuthError(
GoogleServiceAuthError::NONE));
EXPECT_FALSE(controller()->ShouldShowSpinner());
}
TEST_F(AutofillDialogControllerTest, WalletShippingSameAsBilling) {
// Assert initial state.
ASSERT_FALSE(profile()->GetPrefs()->HasPrefPath(
::prefs::kAutofillDialogWalletShippingSameAsBilling));
// Verify that false pref defaults to wallet defaults.
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
wallet_items->AddAddress(wallet::GetTestShippingAddress());
controller()->OnDidGetWalletItems(wallet_items.Pass());
ASSERT_FALSE(profile()->GetPrefs()->GetBoolean(
::prefs::kAutofillDialogWalletShippingSameAsBilling));
EXPECT_EQ(2, GetMenuModelForSection(SECTION_SHIPPING)->checked_item());
// Set "Same as Billing" for the shipping address and verify it sets the pref
// and selects the appropriate menu item.
UseBillingForShipping();
ASSERT_EQ(0, GetMenuModelForSection(SECTION_SHIPPING)->checked_item());
controller()->ForceFinishSubmit();
ASSERT_TRUE(profile()->GetPrefs()->GetBoolean(
::prefs::kAutofillDialogWalletShippingSameAsBilling));
// Getting new wallet info shouldn't disrupt the preference and menu should be
// set accordingly.
Reset();
wallet_items = wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddAddress(wallet::GetTestNonDefaultShippingAddress());
wallet_items->AddAddress(wallet::GetTestShippingAddress());
controller()->OnDidGetWalletItems(wallet_items.Pass());
EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
::prefs::kAutofillDialogWalletShippingSameAsBilling));
EXPECT_EQ(0, GetMenuModelForSection(SECTION_SHIPPING)->checked_item());
// Choose a different address and ensure pref gets set to false.
controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(1);
controller()->ForceFinishSubmit();
EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
::prefs::kAutofillDialogWalletShippingSameAsBilling));
}
// Verifies that a call to the IconsForFields() method before the card type is
// known returns a placeholder image that is at least as large as the icons for
// all of the supported major credit card issuers.
TEST_F(AutofillDialogControllerTest, IconReservedForCreditCardField) {
FieldValueMap inputs;
inputs[CREDIT_CARD_NUMBER] = base::string16();
FieldIconMap icons = controller()->IconsForFields(inputs);
EXPECT_EQ(1U, icons.size());
ASSERT_EQ(1U, icons.count(CREDIT_CARD_NUMBER));
gfx::Image placeholder_icon = icons[CREDIT_CARD_NUMBER];
// Verify that the placeholder icon is at least as large as the icons for the
// supported credit card issuers.
const int kSupportedCardIdrs[] = {
IDR_AUTOFILL_CC_AMEX,
IDR_AUTOFILL_CC_DISCOVER,
IDR_AUTOFILL_CC_GENERIC,
IDR_AUTOFILL_CC_MASTERCARD,
IDR_AUTOFILL_CC_VISA,
};
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
for (size_t i = 0; i < arraysize(kSupportedCardIdrs); ++i) {
SCOPED_TRACE(base::IntToString(i));
gfx::Image supported_card_icon = rb.GetImageNamed(kSupportedCardIdrs[i]);
EXPECT_GE(placeholder_icon.Width(), supported_card_icon.Width());
EXPECT_GE(placeholder_icon.Height(), supported_card_icon.Height());
}
}
TEST_F(AutofillDialogControllerTest, CountryChangeUpdatesSection) {
TestAutofillDialogView* view = controller()->GetView();
view->ClearSectionUpdates();
controller()->UserEditedOrActivatedInput(SECTION_SHIPPING,
ADDRESS_HOME_COUNTRY,
gfx::NativeView(),
gfx::Rect(),
ASCIIToUTF16("Belarus"),
true);
std::map<DialogSection, size_t> updates = view->section_updates();
EXPECT_EQ(1U, updates[SECTION_SHIPPING]);
EXPECT_EQ(1U, updates.size());
view->ClearSectionUpdates();
controller()->UserEditedOrActivatedInput(SECTION_CC_BILLING,
ADDRESS_BILLING_COUNTRY,
gfx::NativeView(),
gfx::Rect(),
ASCIIToUTF16("France"),
true);
updates = view->section_updates();
EXPECT_EQ(1U, updates[SECTION_CC_BILLING]);
EXPECT_EQ(1U, updates.size());
SwitchToAutofill();
view->ClearSectionUpdates();
controller()->UserEditedOrActivatedInput(SECTION_BILLING,
ADDRESS_BILLING_COUNTRY,
gfx::NativeView(),
gfx::Rect(),
ASCIIToUTF16("Italy"),
true);
updates = view->section_updates();
EXPECT_EQ(1U, updates[SECTION_BILLING]);
EXPECT_EQ(1U, updates.size());
}
TEST_F(AutofillDialogControllerTest, CorrectCountryFromInputs) {
EXPECT_CALL(*controller()->GetMockValidator(),
ValidateAddress(CountryCodeMatcher("DE"), _, _));
FieldValueMap billing_inputs;
billing_inputs[ADDRESS_BILLING_COUNTRY] = ASCIIToUTF16("Germany");
controller()->InputsAreValid(SECTION_BILLING, billing_inputs);
EXPECT_CALL(*controller()->GetMockValidator(),
ValidateAddress(CountryCodeMatcher("FR"), _, _));
FieldValueMap shipping_inputs;
shipping_inputs[ADDRESS_HOME_COUNTRY] = ASCIIToUTF16("France");
controller()->InputsAreValid(SECTION_SHIPPING, shipping_inputs);
}
TEST_F(AutofillDialogControllerTest, ValidationRulesLoadedOnCountryChange) {
ResetControllerWithFormData(DefaultFormData());
EXPECT_CALL(*controller()->GetMockValidator(),
LoadRules("US")).Times(AtLeast(1));
controller()->Show();
EXPECT_CALL(*controller()->GetMockValidator(), LoadRules("FR"));
controller()->UserEditedOrActivatedInput(SECTION_BILLING,
ADDRESS_BILLING_COUNTRY,
gfx::NativeView(),
gfx::Rect(),
ASCIIToUTF16("France"),
true);
}
TEST_F(AutofillDialogControllerTest, UsValidationRulesLoadedForJpOnlyProfile) {
ResetControllerWithFormData(DefaultFormData());
AutofillProfile jp_profile(base::GenerateGUID(), kSettingsOrigin);
jp_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("JP"));
controller()->GetTestingManager()->AddTestingProfile(&jp_profile);
EXPECT_CALL(*controller()->GetMockValidator(), LoadRules("US"));
EXPECT_CALL(*controller()->GetMockValidator(),
LoadRules("JP")).Times(AtLeast(1));
controller()->Show();
}
TEST_F(AutofillDialogControllerTest, InvalidWhenRulesNotReady) {
// Select "Add new shipping address...".
controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(1);
// If the rules haven't loaded yet, validation errors should show on submit.
EXPECT_CALL(*controller()->GetMockValidator(),
ValidateAddress(CountryCodeMatcher("US"), _, _)).
WillRepeatedly(Return(AddressValidator::RULES_NOT_READY));
FieldValueMap inputs;
inputs[ADDRESS_HOME_ZIP] = ASCIIToUTF16("1234");
inputs[ADDRESS_HOME_COUNTRY] = ASCIIToUTF16("United States");
ValidityMessages messages =
controller()->InputsAreValid(SECTION_SHIPPING, inputs);
EXPECT_FALSE(messages.GetMessageOrDefault(ADDRESS_HOME_ZIP).text.empty());
EXPECT_FALSE(messages.HasSureError(ADDRESS_HOME_ZIP));
// Country should never show an error message as it's always valid.
EXPECT_TRUE(messages.GetMessageOrDefault(ADDRESS_HOME_COUNTRY).text.empty());
}
TEST_F(AutofillDialogControllerTest, ValidButUnverifiedWhenRulesFail) {
SwitchToAutofill();
// Add suggestions so the credit card and billing sections aren't showing
// their manual inputs (to isolate to just shipping).
AutofillProfile verified_profile(test::GetVerifiedProfile());
controller()->GetTestingManager()->AddTestingProfile(&verified_profile);
CreditCard verified_card(test::GetVerifiedCreditCard());
controller()->GetTestingManager()->AddTestingCreditCard(&verified_card);
// Select "Add new shipping address...".
controller()->MenuModelForSection(SECTION_SHIPPING)->ActivatedAt(2);
// If the rules are unavailable, validation errors should not show.
EXPECT_CALL(*controller()->GetMockValidator(),
ValidateAddress(CountryCodeMatcher("US"), _, _)).
WillRepeatedly(Return(AddressValidator::RULES_UNAVAILABLE));
FieldValueMap outputs;
AutofillProfile full_profile(test::GetFullProfile());
const DetailInputs& inputs =
controller()->RequestedFieldsForSection(SECTION_SHIPPING);
for (size_t i = 0; i < inputs.size(); ++i) {
const ServerFieldType type = inputs[i].type;
outputs[type] = full_profile.GetInfo(AutofillType(type), "en-US");
}
controller()->GetView()->SetUserInput(SECTION_SHIPPING, outputs);
controller()->GetView()->CheckSaveDetailsLocallyCheckbox(true);
controller()->OnAccept();
// Profiles saved while rules are unavailable shouldn't be verified.
const AutofillProfile& imported_profile =
controller()->GetTestingManager()->imported_profile();
ASSERT_EQ(imported_profile.GetInfo(AutofillType(NAME_FULL), "en-US"),
full_profile.GetInfo(AutofillType(NAME_FULL), "en-US"));
EXPECT_EQ(imported_profile.origin(), GURL(kSourceUrl).GetOrigin().spec());
EXPECT_FALSE(imported_profile.IsVerified());
}
TEST_F(AutofillDialogControllerTest, LimitedCountryChoices) {
ui::ComboboxModel* shipping_country_model =
controller()->ComboboxModelForAutofillType(ADDRESS_HOME_COUNTRY);
const int default_number_of_countries =
shipping_country_model->GetItemCount();
// We show a lot of countries by default, but the exact number doesn't matter.
EXPECT_GT(default_number_of_countries, 50);
// Create a form data that simulates:
// <select autocomplete="billing country">
// <option value="AU">Down Under</option>
// <option value="">fR</option> <!-- Case doesn't matter -->
// <option value="GRMNY">Germany</option>
// </select>
// Only country codes are respected, whether they're in value or the option's
// text content. Thus the first two options should be recognized.
FormData form_data;
FormFieldData field;
field.autocomplete_attribute = "billing country";
field.option_contents.push_back(ASCIIToUTF16("Down Under"));
field.option_values.push_back(ASCIIToUTF16("AU"));
field.option_contents.push_back(ASCIIToUTF16("Fr"));
field.option_values.push_back(ASCIIToUTF16(""));
field.option_contents.push_back(ASCIIToUTF16("Germany"));
field.option_values.push_back(ASCIIToUTF16("GRMNY"));
FormFieldData cc_field;
cc_field.autocomplete_attribute = "cc-csc";
form_data.fields.push_back(field);
form_data.fields.push_back(cc_field);
ResetControllerWithFormData(form_data);
controller()->Show();
// Shipping model shouldn't have changed.
shipping_country_model =
controller()->ComboboxModelForAutofillType(ADDRESS_HOME_COUNTRY);
EXPECT_EQ(default_number_of_countries,
shipping_country_model->GetItemCount());
// Billing model now only has two items.
ui::ComboboxModel* billing_country_model =
controller()->ComboboxModelForAutofillType(ADDRESS_BILLING_COUNTRY);
ASSERT_EQ(2, billing_country_model->GetItemCount());
EXPECT_EQ(billing_country_model->GetItemAt(0), ASCIIToUTF16("Australia"));
EXPECT_EQ(billing_country_model->GetItemAt(1), ASCIIToUTF16("France"));
// Make sure it also applies to profile suggestions.
AutofillProfile us_profile(test::GetVerifiedProfile());
us_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
controller()->GetTestingManager()->AddTestingProfile(&us_profile);
// Don't show a suggestion if the only one that exists is disabled.
EXPECT_FALSE(
controller()->SuggestionStateForSection(SECTION_BILLING).visible);
// Add a profile with an acceptable country; suggestion should be shown.
ResetControllerWithFormData(form_data);
controller()->Show();
AutofillProfile au_profile(test::GetVerifiedProfile2());
au_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("AU"));
controller()->GetTestingManager()->AddTestingProfile(&us_profile);
controller()->GetTestingManager()->AddTestingProfile(&au_profile);
ui::MenuModel* model = controller()->MenuModelForSection(SECTION_BILLING);
ASSERT_TRUE(model);
EXPECT_EQ(4, model->GetItemCount());
EXPECT_FALSE(model->IsEnabledAt(0));
EXPECT_TRUE(model->IsEnabledAt(1));
// Add <input type="text" autocomplete="billing country"></input>
// This should open up selection of all countries again.
FormFieldData field2;
field2.autocomplete_attribute = "billing country";
form_data.fields.push_back(field2);
ResetControllerWithFormData(form_data);
controller()->Show();
billing_country_model =
controller()->ComboboxModelForAutofillType(ADDRESS_BILLING_COUNTRY);
EXPECT_EQ(default_number_of_countries,
billing_country_model->GetItemCount());
}
TEST_F(AutofillDialogControllerTest, WalletUnsupportedCountries) {
// Create a form data that simulates:
// <select autocomplete="billing country">
// <option value="IQ">Iraq</option>
// <option value="MX">Mexico</option>
// </select>
// i.e. contains a mix of supported and unsupported countries.
FormData form_data;
FormFieldData field;
field.autocomplete_attribute = "shipping country";
field.option_contents.push_back(ASCIIToUTF16("Iraq"));
field.option_values.push_back(ASCIIToUTF16("IQ"));
field.option_contents.push_back(ASCIIToUTF16("Mexico"));
field.option_values.push_back(ASCIIToUTF16("MX"));
FormFieldData cc_field;
cc_field.autocomplete_attribute = "cc-csc";
form_data.fields.push_back(field);
form_data.fields.push_back(cc_field);
ResetControllerWithFormData(form_data);
controller()->Show();
ui::ComboboxModel* shipping_country_model =
controller()->ComboboxModelForAutofillType(ADDRESS_HOME_COUNTRY);
ASSERT_EQ(2, shipping_country_model->GetItemCount());
EXPECT_EQ(shipping_country_model->GetItemAt(0), ASCIIToUTF16("Iraq"));
EXPECT_EQ(shipping_country_model->GetItemAt(1), ASCIIToUTF16("Mexico"));
// Switch to Wallet, add limitations.
SetUpControllerWithFormData(form_data);
SwitchToWallet();
scoped_ptr<wallet::WalletItems> wallet_items =
wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddAllowedShippingCountry("MX");
wallet_items->AddAllowedShippingCountry("GB");
controller()->OnDidGetWalletItems(wallet_items.Pass());
// Only the intersection is available.
EXPECT_TRUE(controller()->IsPayingWithWallet());
shipping_country_model =
controller()->ComboboxModelForAutofillType(ADDRESS_HOME_COUNTRY);
ASSERT_EQ(1, shipping_country_model->GetItemCount());
EXPECT_EQ(shipping_country_model->GetItemAt(0), ASCIIToUTF16("Mexico"));
// Empty intersection; Wallet's automatically disabled.
wallet_items = wallet::GetTestWalletItems(wallet::AMEX_DISALLOWED);
wallet_items->AddAllowedShippingCountry("CA");
wallet_items->AddAllowedShippingCountry("GB");
controller()->OnDidGetWalletItems(wallet_items.Pass());
EXPECT_FALSE(controller()->IsPayingWithWallet());
// Since it's disabled, we revert to accepting all the countries.
shipping_country_model =
controller()->ComboboxModelForAutofillType(ADDRESS_HOME_COUNTRY);
ASSERT_EQ(2, shipping_country_model->GetItemCount());
EXPECT_EQ(shipping_country_model->GetItemAt(0), ASCIIToUTF16("Iraq"));
EXPECT_EQ(shipping_country_model->GetItemAt(1), ASCIIToUTF16("Mexico"));
}
// http://crbug.com/388018
TEST_F(AutofillDialogControllerTest, NoCountryChoices) {
// Create a form data that simulates:
// <select autocomplete="billing country">
// <option value="ATL">Atlantis</option>
// <option value="ELD">Eldorado</option>
// </select>
// i.e. contains a list of no valid countries.
FormData form_data;
FormFieldData field;
field.autocomplete_attribute = "billing country";
field.option_contents.push_back(ASCIIToUTF16("Atlantis"));
field.option_values.push_back(ASCIIToUTF16("ATL"));
field.option_contents.push_back(ASCIIToUTF16("Eldorado"));
field.option_values.push_back(ASCIIToUTF16("ELD"));
FormFieldData cc_field;
cc_field.autocomplete_attribute = "cc-csc";
form_data.fields.push_back(field);
form_data.fields.push_back(cc_field);
ResetControllerWithFormData(form_data);
controller()->Show();
// Controller aborts and self destructs.
EXPECT_EQ(0, controller());
}
TEST_F(AutofillDialogControllerTest, LimitedCcChoices) {
SwitchToAutofill();
// Typically, MC and Visa are both valid.
ValidateCCNumber(SECTION_CC, kTestCCNumberMaster, true);
ValidateCCNumber(SECTION_CC, kTestCCNumberVisa, true);
FormData form_data;
FormFieldData field;
field.autocomplete_attribute = "billing cc-type";
field.option_contents.push_back(ASCIIToUTF16("Visa"));
field.option_values.push_back(ASCIIToUTF16("V"));
field.option_contents.push_back(ASCIIToUTF16("Amex"));
field.option_values.push_back(ASCIIToUTF16("AX"));
form_data.fields.push_back(field);
ResetControllerWithFormData(form_data);
controller()->Show();
// MC is not valid because it's missing from FormData.
EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_AUTOFILL_DIALOG_VALIDATION_UNACCEPTED_MASTERCARD),
ValidateCCNumber(SECTION_CC, kTestCCNumberMaster, false));
ValidateCCNumber(SECTION_CC, kTestCCNumberVisa, true);
CreditCard visa_card(test::GetVerifiedCreditCard());
CreditCard amex_card(test::GetVerifiedCreditCard2());
CreditCard master_card(base::GenerateGUID(), "chrome settings");
test::SetCreditCardInfo(
&master_card, "Mr Foo", "5105105105105100", "07", "2099");
controller()->GetTestingManager()->AddTestingCreditCard(&visa_card);
controller()->GetTestingManager()->AddTestingCreditCard(&amex_card);
controller()->GetTestingManager()->AddTestingCreditCard(&master_card);
// The stored MC is disabled in the dropdown.
ui::MenuModel* model = controller()->MenuModelForSection(SECTION_CC);
ASSERT_TRUE(model);
ASSERT_EQ(5, model->GetItemCount());
EXPECT_TRUE(model->IsEnabledAt(0));
EXPECT_TRUE(model->IsEnabledAt(1));
EXPECT_FALSE(model->IsEnabledAt(2));
EXPECT_TRUE(model->IsEnabledAt(3));
EXPECT_TRUE(model->IsEnabledAt(4));
// No MC; Wallet is disabled.
SetUpControllerWithFormData(form_data);
EXPECT_FALSE(controller()->IsPayingWithWallet());
// In Autofill mode, Discover is disallowed because it's not in FormData.
ValidateCCNumber(SECTION_CC, kTestCCNumberDiscover, false);
field.option_contents.push_back(ASCIIToUTF16("Mastercard"));
field.option_values.push_back(ASCIIToUTF16("Mastercard"));
form_data.fields[0] = field;
// Add MC to FormData; Wallet is enabled.
SetUpControllerWithFormData(form_data);
EXPECT_TRUE(controller()->IsPayingWithWallet());
// Even though Discover isn't in FormData, it's allowed because Wallet always
// generates a MC Virtual card.
ValidateCCNumber(SECTION_CC_BILLING, kTestCCNumberDiscover, true);
}
TEST_F(AutofillDialogControllerTest, SuggestCountrylessProfiles) {
SwitchToAutofill();
FieldValueMap outputs;
outputs[ADDRESS_HOME_COUNTRY] = ASCIIToUTF16("US");
controller()->GetView()->SetUserInput(SECTION_SHIPPING, outputs);
AutofillProfile profile(test::GetVerifiedProfile());
profile.SetRawInfo(NAME_FULL, ASCIIToUTF16("The Man Without a Country"));
profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::string16());
controller()->GetTestingManager()->AddTestingProfile(&profile);
controller()->UserEditedOrActivatedInput(
SECTION_SHIPPING,
NAME_FULL,
gfx::NativeView(),
gfx::Rect(),
profile.GetRawInfo(NAME_FULL).substr(0, 1),
true);
EXPECT_EQ(NAME_FULL, controller()->popup_input_type());
}
TEST_F(AutofillDialogControllerTest, SwitchFromWalletWithFirstName) {
controller()->MenuModelForSection(SECTION_CC_BILLING)->ActivatedAt(2);
FieldValueMap outputs;
outputs[NAME_FULL] = ASCIIToUTF16("madonna");
controller()->GetView()->SetUserInput(SECTION_CC_BILLING, outputs);
ASSERT_NO_FATAL_FAILURE(SwitchToAutofill());
}
// Regression test for http://crbug.com/382777
TEST_F(AutofillDialogControllerTest, WalletBillingCountry) {
FormFieldData cc_field;
cc_field.autocomplete_attribute = "cc-number";
FormFieldData billing_country, billing_country_name, shipping_country,
shipping_country_name;
billing_country.autocomplete_attribute = "billing country";
billing_country_name.autocomplete_attribute = "billing country-name";
shipping_country.autocomplete_attribute = "shipping country";
shipping_country_name.autocomplete_attribute = "shipping country-name";
FormData form_data;
form_data.fields.push_back(cc_field);
form_data.fields.push_back(billing_country);
form_data.fields.push_back(billing_country_name);
form_data.fields.push_back(shipping_country);
form_data.fields.push_back(shipping_country_name);
SetUpControllerWithFormData(form_data);
AcceptAndLoadFakeFingerprint();
controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
controller()->ForceFinishSubmit();
ASSERT_EQ(5U, form_structure()->field_count());
EXPECT_EQ(ADDRESS_HOME_COUNTRY,
form_structure()->field(1)->Type().GetStorableType());
EXPECT_EQ(ASCIIToUTF16("US"), form_structure()->field(1)->value);
EXPECT_EQ(ADDRESS_HOME_COUNTRY,
form_structure()->field(2)->Type().GetStorableType());
EXPECT_EQ(ASCIIToUTF16("United States"), form_structure()->field(2)->value);
EXPECT_EQ(ADDRESS_HOME_COUNTRY,
form_structure()->field(3)->Type().GetStorableType());
EXPECT_EQ(ASCIIToUTF16("US"), form_structure()->field(3)->value);
EXPECT_EQ(ADDRESS_HOME_COUNTRY,
form_structure()->field(4)->Type().GetStorableType());
EXPECT_EQ(ASCIIToUTF16("United States"), form_structure()->field(4)->value);
}
} // namespace autofill