blob: d18c7e8bf72e93078ba15af82815ee7246f05a95 [file] [log] [blame]
// Copyright 2019 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 "components/autofill_assistant/browser/actions/collect_user_data_action.h"
#include <utility>
#include "base/guid.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
#include "components/autofill_assistant/browser/mock_personal_data_manager.h"
#include "components/autofill_assistant/browser/mock_website_login_fetcher.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace {
const char kFakeUrl[] = "https://www.example.com";
const char kFakeUsername[] = "user@example.com";
const char kFakePassword[] = "example_password";
const char kMemoryLocation[] = "billing";
} // namespace
namespace autofill_assistant {
namespace {
void SetDateTimeProto(DateTimeProto* proto,
int year,
int month,
int day,
int hour,
int minute,
int second) {
proto->mutable_date()->set_year(year);
proto->mutable_date()->set_month(month);
proto->mutable_date()->set_day(day);
proto->mutable_time()->set_hour(hour);
proto->mutable_time()->set_minute(minute);
proto->mutable_time()->set_second(second);
}
MATCHER_P(EqualsProto, message, "") {
std::string expected_serialized, actual_serialized;
message.SerializeToString(&expected_serialized);
arg.SerializeToString(&actual_serialized);
return expected_serialized == actual_serialized;
}
using ::base::test::RunOnceCallback;
using ::testing::_;
using ::testing::Eq;
using ::testing::Invoke;
using ::testing::Property;
using ::testing::Return;
using ::testing::SizeIs;
void SetRequiredTermsFields(CollectUserDataProto* data,
bool request_terms_and_conditions = false) {
data->set_thirdparty_privacy_notice_text("privacy");
if (request_terms_and_conditions) {
data->set_accept_terms_and_conditions_text("terms and conditions");
data->set_terms_require_review_text("terms review");
}
data->set_request_terms_and_conditions(request_terms_and_conditions);
}
class CollectUserDataActionTest : public content::RenderViewHostTestHarness {
public:
void SetUp() override {
RenderViewHostTestHarness::SetUp();
ON_CALL(mock_action_delegate_, GetClientMemory)
.WillByDefault(Return(&client_memory_));
ON_CALL(mock_action_delegate_, GetPersonalDataManager)
.WillByDefault(Return(&mock_personal_data_manager_));
ON_CALL(mock_action_delegate_, GetWebsiteLoginFetcher)
.WillByDefault(Return(&mock_website_login_fetcher_));
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke([](std::unique_ptr<CollectUserDataOptions>
collect_user_data_options,
std::unique_ptr<UserData> user_data) {
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
ON_CALL(mock_website_login_fetcher_, OnGetLoginsForUrl(_, _))
.WillByDefault(
RunOnceCallback<1>(std::vector<WebsiteLoginFetcher::Login>{
WebsiteLoginFetcher::Login(GURL(kFakeUrl), kFakeUsername)}));
ON_CALL(mock_website_login_fetcher_, OnGetPasswordForLogin(_, _))
.WillByDefault(RunOnceCallback<1>(true, kFakePassword));
content::WebContentsTester::For(web_contents())
->SetLastCommittedURL(GURL(kFakeUrl));
ON_CALL(mock_action_delegate_, GetWebContents())
.WillByDefault(Return(web_contents()));
}
protected:
base::MockCallback<Action::ProcessActionCallback> callback_;
MockPersonalDataManager mock_personal_data_manager_;
MockWebsiteLoginFetcher mock_website_login_fetcher_;
MockActionDelegate mock_action_delegate_;
ClientMemory client_memory_;
};
TEST_F(CollectUserDataActionTest, FailsForMissingPrivacyText) {
ActionProto action_proto;
action_proto.mutable_collect_user_data();
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, SucceedsForPrivacyTextPresent) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
collect_user_data_proto->set_thirdparty_privacy_notice_text("privacy");
collect_user_data_proto->set_request_terms_and_conditions(false);
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
user_data->terms_and_conditions = ACCEPTED;
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
EXPECT_CALL(
callback_,
Run(Pointee(AllOf(
Property(&ProcessedActionProto::status, ACTION_APPLIED),
Property(
&ProcessedActionProto::collect_user_data_result,
Property(
&CollectUserDataResultProto::is_terms_and_conditions_accepted,
true))))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, FailsForMissingTermsAcceptTextIfRequired) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
collect_user_data_proto->set_thirdparty_privacy_notice_text("privacy");
collect_user_data_proto->set_request_terms_and_conditions(true);
collect_user_data_proto->set_terms_require_review_text("terms review");
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, FailsForMissingTermsReviewTextIfRequired) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
collect_user_data_proto->set_thirdparty_privacy_notice_text("privacy");
collect_user_data_proto->set_request_terms_and_conditions(true);
collect_user_data_proto->set_accept_terms_and_conditions_text(
"terms and conditions");
collect_user_data_proto->set_show_terms_as_checkbox(false);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, SucceedsForCheckboxIfReviewTextMissing) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
collect_user_data_proto->set_thirdparty_privacy_notice_text("privacy");
collect_user_data_proto->set_request_terms_and_conditions(true);
collect_user_data_proto->set_accept_terms_and_conditions_text(
"terms and conditions");
collect_user_data_proto->set_show_terms_as_checkbox(true);
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
user_data->terms_and_conditions = ACCEPTED;
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
EXPECT_CALL(
callback_,
Run(Pointee(AllOf(
Property(&ProcessedActionProto::status, ACTION_APPLIED),
Property(
&ProcessedActionProto::collect_user_data_result,
Property(
&CollectUserDataResultProto::is_terms_and_conditions_accepted,
true))))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, SucceedsForAllTermsTextPresent) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
collect_user_data_proto->set_thirdparty_privacy_notice_text("privacy");
collect_user_data_proto->set_request_terms_and_conditions(true);
collect_user_data_proto->set_accept_terms_and_conditions_text(
"terms and conditions");
collect_user_data_proto->set_show_terms_as_checkbox(false);
collect_user_data_proto->set_terms_require_review_text("terms review");
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
user_data->terms_and_conditions = ACCEPTED;
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
EXPECT_CALL(
callback_,
Run(Pointee(AllOf(
Property(&ProcessedActionProto::status, ACTION_APPLIED),
Property(
&ProcessedActionProto::collect_user_data_result,
Property(
&CollectUserDataResultProto::is_terms_and_conditions_accepted,
true))))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, PromptIsShown) {
const char kPrompt[] = "Some message.";
ActionProto action_proto;
SetRequiredTermsFields(action_proto.mutable_collect_user_data());
action_proto.mutable_collect_user_data()->set_prompt(kPrompt);
EXPECT_CALL(mock_action_delegate_, SetStatusMessage(kPrompt));
EXPECT_CALL(callback_, Run(_));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, SelectLogin) {
ActionProto action_proto;
SetRequiredTermsFields(action_proto.mutable_collect_user_data());
auto* login_details =
action_proto.mutable_collect_user_data()->mutable_login_details();
auto* login_option = login_details->add_login_options();
login_option->mutable_password_manager();
login_option->set_payload("payload");
// Action should fetch the logins, but not the passwords.
EXPECT_CALL(mock_website_login_fetcher_, OnGetLoginsForUrl(GURL(kFakeUrl), _))
.Times(1);
EXPECT_CALL(mock_website_login_fetcher_, OnGetPasswordForLogin(_, _))
.Times(0);
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
user_data->login_choice_identifier.assign(
collect_user_data_options->login_choices[0].identifier);
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
EXPECT_CALL(callback_,
Run(Pointee(AllOf(
Property(&ProcessedActionProto::status, ACTION_APPLIED),
Property(&ProcessedActionProto::collect_user_data_result,
Property(&CollectUserDataResultProto::login_payload,
"payload"))))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, LoginChoiceAutomaticIfNoOtherOptions) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
SetRequiredTermsFields(collect_user_data_proto);
collect_user_data_proto->set_request_terms_and_conditions(false);
auto* login_details = collect_user_data_proto->mutable_login_details();
auto* login_option = login_details->add_login_options();
login_option->mutable_custom()->set_label("Guest Checkout");
login_option->set_payload("guest");
login_option->set_choose_automatically_if_no_other_options(true);
login_option = login_details->add_login_options();
login_option->mutable_password_manager();
login_option->set_payload("password_manager");
ON_CALL(mock_website_login_fetcher_, OnGetLoginsForUrl(_, _))
.WillByDefault(
RunOnceCallback<1>(std::vector<WebsiteLoginFetcher::Login>{}));
EXPECT_CALL(mock_action_delegate_, CollectUserData(_, _)).Times(0);
EXPECT_CALL(callback_,
Run(Pointee(AllOf(
Property(&ProcessedActionProto::status, ACTION_APPLIED),
Property(&ProcessedActionProto::collect_user_data_result,
Property(&CollectUserDataResultProto::login_payload,
"guest"))))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, SelectLoginFailsIfNoOptionAvailable) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
SetRequiredTermsFields(collect_user_data_proto);
auto* login_details = collect_user_data_proto->mutable_login_details();
auto* login_option = login_details->add_login_options();
login_option->mutable_password_manager();
login_option->set_payload("password_manager");
ON_CALL(mock_website_login_fetcher_, OnGetLoginsForUrl(_, _))
.WillByDefault(
RunOnceCallback<1>(std::vector<WebsiteLoginFetcher::Login>{}));
EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
COLLECT_USER_DATA_ERROR))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, SelectContactDetails) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
SetRequiredTermsFields(collect_user_data_proto);
collect_user_data_proto->set_request_terms_and_conditions(false);
auto* contact_details_proto =
collect_user_data_proto->mutable_contact_details();
contact_details_proto->set_contact_details_name(kMemoryLocation);
contact_details_proto->set_request_payer_name(true);
contact_details_proto->set_request_payer_email(true);
contact_details_proto->set_request_payer_phone(true);
autofill::AutofillProfile contact_profile;
contact_profile.SetRawInfo(autofill::ServerFieldType::NAME_FULL,
base::UTF8ToUTF16("Marion Mitchell Morrison"));
contact_profile.SetRawInfo(autofill::ServerFieldType::NAME_FIRST,
base::UTF8ToUTF16("Marion"));
contact_profile.SetRawInfo(autofill::ServerFieldType::NAME_MIDDLE,
base::UTF8ToUTF16("Mitchell"));
contact_profile.SetRawInfo(autofill::ServerFieldType::NAME_LAST,
base::UTF8ToUTF16("Morrison"));
contact_profile.SetRawInfo(autofill::ServerFieldType::EMAIL_ADDRESS,
base::UTF8ToUTF16("marion@me.xyz"));
contact_profile.SetRawInfo(autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER,
base::UTF8ToUTF16("16505678910"));
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[=](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
user_data->contact_profile =
std::make_unique<autofill::AutofillProfile>(contact_profile);
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
EXPECT_CALL(callback_,
Run(Pointee(AllOf(
Property(&ProcessedActionProto::status, ACTION_APPLIED),
Property(&ProcessedActionProto::collect_user_data_result,
Property(&CollectUserDataResultProto::payer_email,
"marion@me.xyz"))))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
EXPECT_EQ(client_memory_.has_selected_address(kMemoryLocation), true);
auto* profile = client_memory_.selected_address(kMemoryLocation);
EXPECT_EQ(profile->GetRawInfo(autofill::NAME_FULL),
base::UTF8ToUTF16("Marion Mitchell Morrison"));
EXPECT_EQ(profile->GetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER),
base::UTF8ToUTF16("16505678910"));
EXPECT_EQ(profile->GetRawInfo(autofill::EMAIL_ADDRESS),
base::UTF8ToUTF16("marion@me.xyz"));
}
TEST_F(CollectUserDataActionTest, SelectPaymentMethod) {
ActionProto action_proto;
SetRequiredTermsFields(action_proto.mutable_collect_user_data());
action_proto.mutable_collect_user_data()->set_request_payment_method(true);
action_proto.mutable_collect_user_data()->set_request_terms_and_conditions(
false);
autofill::AutofillProfile billing_profile(base::GenerateGUID(), kFakeUrl);
autofill::test::SetProfileInfo(&billing_profile, "Marion", "Mitchell",
"Morrison", "marion@me.xyz", "Fox",
"123 Zoo St.", "unit 5", "Hollywood", "CA",
"91601", "US", "16505678910");
autofill::CreditCard credit_card(base::GenerateGUID(), kFakeUrl);
autofill::test::SetCreditCardInfo(&credit_card, "Marion Mitchell",
"4111 1111 1111 1111", "01", "2020",
billing_profile.guid());
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[=](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->card =
std::make_unique<autofill::CreditCard>(credit_card);
user_data->billing_address =
std::make_unique<autofill::AutofillProfile>(billing_profile);
user_data->succeed = true;
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
EXPECT_CALL(
callback_,
Run(Pointee(AllOf(
Property(&ProcessedActionProto::status, ACTION_APPLIED),
Property(&ProcessedActionProto::collect_user_data_result,
Property(&CollectUserDataResultProto::card_issuer_network,
"visa"))))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
EXPECT_EQ(client_memory_.has_selected_card(), true);
EXPECT_THAT(client_memory_.selected_card()->Compare(credit_card), Eq(0));
}
TEST_F(CollectUserDataActionTest, MandatoryPostalCodeWithoutErrorMessageFails) {
ActionProto action_proto;
action_proto.mutable_collect_user_data()->set_request_payment_method(true);
action_proto.mutable_collect_user_data()->set_require_billing_postal_code(
true);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, ContactDetailsCanHandleUtf8) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
SetRequiredTermsFields(collect_user_data_proto);
collect_user_data_proto->set_request_terms_and_conditions(false);
auto* contact_details_proto =
collect_user_data_proto->mutable_contact_details();
contact_details_proto->set_contact_details_name(kMemoryLocation);
contact_details_proto->set_request_payer_name(true);
contact_details_proto->set_request_payer_email(true);
// Name = 艾丽森 in UTF-8.
autofill::AutofillProfile contact_profile;
contact_profile.SetRawInfo(
autofill::ServerFieldType::NAME_FULL,
base::UTF8ToUTF16("\xE8\x89\xBE\xE4\xB8\xBD\xE6\xA3\xAE"));
contact_profile.SetRawInfo(
autofill::ServerFieldType::EMAIL_ADDRESS,
base::UTF8ToUTF16("\xE8\x89\xBE\xE4\xB8\xBD\xE6\xA3\xAE@example.com"));
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[=](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
user_data->contact_profile =
std::make_unique<autofill::AutofillProfile>(contact_profile);
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
EXPECT_CALL(
callback_,
Run(Pointee(AllOf(
Property(&ProcessedActionProto::status, ACTION_APPLIED),
Property(
&ProcessedActionProto::collect_user_data_result,
Property(&CollectUserDataResultProto::payer_email,
"\xE8\x89\xBE\xE4\xB8\xBD\xE6\xA3\xAE@example.com"))))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
EXPECT_EQ(client_memory_.has_selected_address(kMemoryLocation), true);
auto* profile = client_memory_.selected_address(kMemoryLocation);
EXPECT_EQ(profile->GetRawInfo(autofill::NAME_FULL),
base::UTF8ToUTF16("\xE8\x89\xBE\xE4\xB8\xBD\xE6\xA3\xAE"));
EXPECT_EQ(
profile->GetRawInfo(autofill::EMAIL_ADDRESS),
base::UTF8ToUTF16("\xE8\x89\xBE\xE4\xB8\xBD\xE6\xA3\xAE@example.com"));
}
TEST_F(CollectUserDataActionTest, UserDataComplete_Contact) {
UserData user_data;
CollectUserDataOptions options;
EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, options));
user_data.contact_profile = std::make_unique<autofill::AutofillProfile>(
base::GenerateGUID(), kFakeUrl);
options.request_payer_email = true;
EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, options));
user_data.contact_profile->SetRawInfo(
autofill::ServerFieldType::EMAIL_ADDRESS,
base::UTF8ToUTF16("joedoe@example.com"));
EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, options));
options.request_payer_name = true;
EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, options));
user_data.contact_profile->SetRawInfo(autofill::ServerFieldType::NAME_FULL,
base::UTF8ToUTF16("Joe Doe"));
EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, options));
options.request_payer_phone = true;
EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, options));
user_data.contact_profile->SetRawInfo(
autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER,
base::UTF8ToUTF16("+1 23 456 789 01"));
EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, options));
}
TEST_F(CollectUserDataActionTest, UserDataComplete_Payment) {
UserData user_data;
CollectUserDataOptions options;
options.request_payment_method = true;
EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, options));
// Valid credit card, but no billing address.
user_data.card =
std::make_unique<autofill::CreditCard>(base::GenerateGUID(), kFakeUrl);
autofill::test::SetCreditCardInfo(user_data.card.get(), "Marion Mitchell",
"4111 1111 1111 1111", "01", "2020",
/* billing_address_id = */ "");
EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, options));
// Incomplete billing address.
user_data.billing_address = std::make_unique<autofill::AutofillProfile>(
base::GenerateGUID(), kFakeUrl);
autofill::test::SetProfileInfo(user_data.billing_address.get(), "Marion",
"Mitchell", "Morrison", "marion@me.xyz", "Fox",
"123 Zoo St.", "unit 5", "Hollywood", "CA",
/* zipcode = */ "", "US", "16505678910");
user_data.card->set_billing_address_id(user_data.billing_address->guid());
EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, options));
user_data.billing_address->SetRawInfo(autofill::ADDRESS_HOME_ZIP,
base::UTF8ToUTF16("91601"));
EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, options));
// Zip code is optional in Argentinian address.
user_data.billing_address->SetRawInfo(autofill::ADDRESS_HOME_ZIP,
base::UTF8ToUTF16(""));
user_data.billing_address->SetRawInfo(autofill::ADDRESS_HOME_COUNTRY,
base::UTF8ToUTF16("AR"));
EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, options));
options.require_billing_postal_code = true;
EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, options));
user_data.billing_address->SetRawInfo(autofill::ADDRESS_HOME_ZIP,
base::UTF8ToUTF16("B1675"));
EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, options));
}
TEST_F(CollectUserDataActionTest, UserDataComplete_Terms) {
UserData user_data;
CollectUserDataOptions options;
options.accept_terms_and_conditions_text.assign("Accept T&C");
EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, options));
user_data.terms_and_conditions = REQUIRES_REVIEW;
EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, options));
user_data.terms_and_conditions = ACCEPTED;
EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, options));
}
TEST_F(CollectUserDataActionTest, UserDataComplete_Login) {
UserData user_data;
CollectUserDataOptions options;
options.request_login_choice = true;
EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, options));
user_data.login_choice_identifier.assign("1");
EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, options));
}
TEST_F(CollectUserDataActionTest, UserDataComplete_ShippingAddress) {
UserData user_data;
CollectUserDataOptions options;
options.request_shipping = true;
EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, options));
// Incomplete address.
user_data.shipping_address = std::make_unique<autofill::AutofillProfile>(
base::GenerateGUID(), kFakeUrl);
autofill::test::SetProfileInfo(user_data.shipping_address.get(), "Marion",
"Mitchell", "Morrison", "marion@me.xyz", "Fox",
"123 Zoo St.", "unit 5", "Hollywood", "CA",
/* zipcode = */ "", "US", "16505678910");
EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, options));
user_data.shipping_address->SetRawInfo(autofill::ADDRESS_HOME_ZIP,
base::UTF8ToUTF16("91601"));
EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, options));
}
TEST_F(CollectUserDataActionTest, UserDataComplete_DateTimeRange) {
UserData user_data;
CollectUserDataOptions options;
options.request_date_time_range = true;
EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, options));
SetDateTimeProto(&user_data.date_time_range_start, 2019, 12, 31, 10, 30, 0);
SetDateTimeProto(&user_data.date_time_range_end, 2019, 1, 28, 16, 0, 0);
// Start date not before end date.
EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, options));
user_data.date_time_range_end.mutable_date()->set_year(2020);
EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, options));
}
TEST_F(CollectUserDataActionTest, SelectDateTimeRange) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
SetRequiredTermsFields(collect_user_data_proto);
collect_user_data_proto->set_request_terms_and_conditions(false);
auto* date_time_proto = collect_user_data_proto->mutable_date_time_range();
SetDateTimeProto(date_time_proto->mutable_start(), 2019, 10, 21, 8, 0, 0);
SetDateTimeProto(date_time_proto->mutable_end(), 2019, 11, 5, 16, 0, 0);
SetDateTimeProto(date_time_proto->mutable_min(), 2019, 11, 5, 16, 0, 0);
SetDateTimeProto(date_time_proto->mutable_max(), 2020, 11, 5, 16, 0, 0);
date_time_proto->set_start_label("Pick up");
date_time_proto->set_end_label("Return");
DateTimeProto actual_pickup_time;
DateTimeProto actual_return_time;
SetDateTimeProto(&actual_pickup_time, 2019, 10, 21, 7, 0, 0);
SetDateTimeProto(&actual_return_time, 2019, 10, 25, 19, 0, 0);
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[&](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
user_data->date_time_range_start = actual_pickup_time;
user_data->date_time_range_end = actual_return_time;
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
EXPECT_CALL(
callback_,
Run(Pointee(
AllOf(Property(&ProcessedActionProto::status, ACTION_APPLIED),
Property(&ProcessedActionProto::collect_user_data_result,
Property(&CollectUserDataResultProto::date_time_start,
EqualsProto(actual_pickup_time))),
Property(&ProcessedActionProto::collect_user_data_result,
Property(&CollectUserDataResultProto::date_time_end,
EqualsProto(actual_return_time)))))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, StaticSectionValid) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
SetRequiredTermsFields(collect_user_data_proto);
collect_user_data_proto->set_request_terms_and_conditions(false);
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
auto* static_section =
collect_user_data_proto->add_additional_prepended_sections();
{
CollectUserDataAction action(&mock_action_delegate_, action_proto);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
action.ProcessAction(callback_.Get());
}
static_section->set_title("Static section");
{
CollectUserDataAction action(&mock_action_delegate_, action_proto);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
action.ProcessAction(callback_.Get());
}
static_section->mutable_static_text_section()->set_text("Lorem ipsum.");
{
CollectUserDataAction action(&mock_action_delegate_, action_proto);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
action.ProcessAction(callback_.Get());
}
}
TEST_F(CollectUserDataActionTest, TextInputSectionValid) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
SetRequiredTermsFields(collect_user_data_proto);
collect_user_data_proto->set_request_terms_and_conditions(false);
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
auto* text_input_section =
collect_user_data_proto->add_additional_prepended_sections();
{
CollectUserDataAction action(&mock_action_delegate_, action_proto);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
action.ProcessAction(callback_.Get());
}
text_input_section->set_title("Text input section");
{
CollectUserDataAction action(&mock_action_delegate_, action_proto);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
action.ProcessAction(callback_.Get());
}
auto* input_field =
text_input_section->mutable_text_input_section()->add_input_fields();
input_field->set_value("12345");
{
CollectUserDataAction action(&mock_action_delegate_, action_proto);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
action.ProcessAction(callback_.Get());
}
input_field->set_input_type(TextInputProto::INPUT_ALPHANUMERIC);
{
CollectUserDataAction action(&mock_action_delegate_, action_proto);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
action.ProcessAction(callback_.Get());
}
input_field->set_client_memory_key("code");
{
CollectUserDataAction action(&mock_action_delegate_, action_proto);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
action.ProcessAction(callback_.Get());
}
// Duplicate input field fails due to duplicate memory key.
*text_input_section->mutable_text_input_section()->add_input_fields() =
*input_field;
{
CollectUserDataAction action(&mock_action_delegate_, action_proto);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
action.ProcessAction(callback_.Get());
}
text_input_section->mutable_text_input_section()
->mutable_input_fields(1)
->set_client_memory_key("something else");
{
CollectUserDataAction action(&mock_action_delegate_, action_proto);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
action.ProcessAction(callback_.Get());
}
}
TEST_F(CollectUserDataActionTest, TextInputSectionWritesToClientMemory) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
SetRequiredTermsFields(collect_user_data_proto);
collect_user_data_proto->set_request_terms_and_conditions(false);
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
user_data->additional_values_to_store["key2"] = "modified";
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
auto* text_input_section =
collect_user_data_proto->add_additional_prepended_sections();
text_input_section->set_title("Text input section");
auto* input_field_1 =
text_input_section->mutable_text_input_section()->add_input_fields();
input_field_1->set_value("initial");
input_field_1->set_input_type(TextInputProto::INPUT_ALPHANUMERIC);
input_field_1->set_client_memory_key("key1");
auto* input_field_2 =
text_input_section->mutable_text_input_section()->add_input_fields();
input_field_2->set_value("initial");
input_field_2->set_input_type(TextInputProto::INPUT_ALPHANUMERIC);
input_field_2->set_client_memory_key("key2");
EXPECT_FALSE(client_memory_.has_additional_value("key1"));
EXPECT_FALSE(client_memory_.has_additional_value("key2"));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
action.ProcessAction(callback_.Get());
EXPECT_EQ(*client_memory_.additional_value("key1"), "initial");
EXPECT_EQ(*client_memory_.additional_value("key2"), "modified");
}
TEST_F(CollectUserDataActionTest, AllowedBasicCardNetworks) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
SetRequiredTermsFields(collect_user_data_proto);
collect_user_data_proto->set_request_terms_and_conditions(false);
std::string kSupportedBasicCardNetworks[] = {"amex", "diners", "discover",
"elo", "jcb", "mastercard",
"mir", "unionpay", "visa"};
for (const auto& network : kSupportedBasicCardNetworks) {
*collect_user_data_proto->add_supported_basic_card_networks() = network;
}
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
user_data->billing_address =
std::make_unique<autofill::AutofillProfile>(
base::GenerateGUID(), kFakeUrl);
autofill::test::SetProfileInfo(
user_data->billing_address.get(), "Marion", "Mitchell",
"Morrison", "marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "96043", "US", "16505678910");
user_data->card = std::make_unique<autofill::CreditCard>(
base::GenerateGUID(), kFakeUrl);
autofill::test::SetCreditCardInfo(
user_data->card.get(), "Marion Mitchell", "4111 1111 1111 1111",
"01", "2020", user_data->billing_address->guid());
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, InvalidBasicCardNetworks) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
SetRequiredTermsFields(collect_user_data_proto);
collect_user_data_proto->set_request_terms_and_conditions(false);
*collect_user_data_proto->add_supported_basic_card_networks() = "visa";
*collect_user_data_proto->add_supported_basic_card_networks() =
"unknown_network";
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, SortsCompleteProfilesAlphabetically) {
ON_CALL(mock_personal_data_manager_, IsAutofillProfileEnabled)
.WillByDefault(Return(true));
autofill::AutofillProfile profile_a;
autofill::test::SetProfileInfo(&profile_a, "Adam", "", "West",
"adam.west@gmail.com", "", "", "", "", "", "",
"", "");
LOG(ERROR) << "ZZZ raw " << profile_a.GetRawInfo(autofill::NAME_FULL);
LOG(ERROR) << "ZZZ " << profile_a.GetInfo(autofill::NAME_FULL, "en-US");
LOG(ERROR) << "ZZZ raw " << profile_a.GetRawInfo(autofill::NAME_FIRST);
LOG(ERROR) << "ZZZ " << profile_a.GetInfo(autofill::NAME_FIRST, "en-US");
LOG(ERROR) << "ZZZ raw " << profile_a.GetRawInfo(autofill::NAME_LAST);
LOG(ERROR) << "ZZZ " << profile_a.GetInfo(autofill::NAME_LAST, "en-US");
autofill::AutofillProfile profile_b;
autofill::test::SetProfileInfo(&profile_b, "Berta", "", "West",
"berta.west@gmail.com", "", "", "", "", "", "",
"", "");
autofill::AutofillProfile profile_unicode;
autofill::test::SetProfileInfo(&profile_unicode,
"\xC3\x85"
"dam",
"", "West", "aedam.west@gmail.com", "", "", "",
"", "", "", "", "");
// Specify profiles in reverse order to force sorting.
std::vector<autofill::AutofillProfile*> profiles(
{&profile_unicode, &profile_b, &profile_a});
ON_CALL(mock_personal_data_manager_, GetProfiles)
.WillByDefault(Return(profiles));
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[=](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
user_data->contact_profile =
std::make_unique<autofill::AutofillProfile>(profile_a);
EXPECT_THAT(user_data->available_profiles, SizeIs(profiles.size()));
EXPECT_EQ(user_data->available_profiles[0]->Compare(profile_a), 0);
EXPECT_EQ(user_data->available_profiles[1]->Compare(profile_b), 0);
EXPECT_EQ(
user_data->available_profiles[2]->Compare(profile_unicode), 0);
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
ActionProto action_proto;
auto* user_data = action_proto.mutable_collect_user_data();
SetRequiredTermsFields(user_data);
auto* contact_details = user_data->mutable_contact_details();
contact_details->set_request_payer_name(true);
contact_details->set_request_payer_email(true);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, SortsProfilesByCompleteness) {
ON_CALL(mock_personal_data_manager_, IsAutofillProfileEnabled)
.WillByDefault(Return(true));
autofill::AutofillProfile profile_complete;
autofill::test::SetProfileInfo(
&profile_complete, "Charlie", "", "West", "charlie.west@gmail.com", "",
"Baker Street 221b", "", "London", "", "WC2N 5DU", "UK", "+44");
autofill::AutofillProfile profile_no_phone;
autofill::test::SetProfileInfo(
&profile_no_phone, "Berta", "", "West", "berta.west@gmail.com", "",
"Baker Street 221b", "", "London", "", "WC2N 5DU", "UK", "");
autofill::AutofillProfile profile_incomplete;
autofill::test::SetProfileInfo(&profile_incomplete, "Adam", "", "West",
"adam.west@gmail.com", "", "", "", "", "", "",
"", "");
// Specify profiles in reverse order to force sorting.
std::vector<autofill::AutofillProfile*> profiles(
{&profile_incomplete, &profile_no_phone, &profile_complete});
ON_CALL(mock_personal_data_manager_, GetProfiles)
.WillByDefault(Return(profiles));
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[=](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
user_data->contact_profile =
std::make_unique<autofill::AutofillProfile>(profile_complete);
user_data->shipping_address =
std::make_unique<autofill::AutofillProfile>(profile_complete);
EXPECT_THAT(user_data->available_profiles, SizeIs(profiles.size()));
EXPECT_EQ(
user_data->available_profiles[0]->Compare(profile_complete), 0);
EXPECT_EQ(
user_data->available_profiles[1]->Compare(profile_no_phone), 0);
EXPECT_EQ(
user_data->available_profiles[2]->Compare(profile_incomplete),
0);
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
ActionProto action_proto;
auto* user_data = action_proto.mutable_collect_user_data();
SetRequiredTermsFields(user_data);
user_data->set_shipping_address_name("Address");
auto* contact_details = user_data->mutable_contact_details();
contact_details->set_request_payer_name(true);
contact_details->set_request_payer_email(true);
contact_details->set_request_payer_phone(true);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, AttachesCreditCardsWithAddress) {
ON_CALL(mock_personal_data_manager_, IsAutofillCreditCardEnabled)
.WillByDefault(Return(true));
ON_CALL(mock_personal_data_manager_, ShouldSuggestServerCards)
.WillByDefault(Return(true));
autofill::AutofillProfile billing_address;
autofill::test::SetProfileInfo(
&billing_address, "Berta", "", "West", "berta.west@gmail.com", "",
"Baker Street 221b", "", "London", "", "WC2N 5DU", "UK", "+44");
ON_CALL(mock_personal_data_manager_, GetProfileByGUID("GUID"))
.WillByDefault(Return(&billing_address));
autofill::CreditCard card_with_address;
autofill::test::SetCreditCardInfo(&card_with_address, "John Doe",
"4111111111111111", "1", "2050",
/* billing_address_id= */ "GUID");
ON_CALL(mock_personal_data_manager_, GetCreditCards())
.WillByDefault(
Return(std::vector<autofill::CreditCard*>({&card_with_address})));
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke(
[=](std::unique_ptr<CollectUserDataOptions> collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
EXPECT_THAT(user_data->available_payment_instruments, SizeIs(1));
EXPECT_EQ(
user_data->available_payment_instruments[0]->card->Compare(
card_with_address),
0);
EXPECT_EQ(user_data->available_payment_instruments[0]
->billing_address->Compare(billing_address),
0);
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
ActionProto action_proto;
auto* user_data = action_proto.mutable_collect_user_data();
SetRequiredTermsFields(user_data);
user_data->add_supported_basic_card_networks("visa");
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
TEST_F(CollectUserDataActionTest, AttachesCreditCardsWithoutAddress) {
ON_CALL(mock_personal_data_manager_, IsAutofillCreditCardEnabled)
.WillByDefault(Return(true));
ON_CALL(mock_personal_data_manager_, ShouldSuggestServerCards)
.WillByDefault(Return(true));
autofill::CreditCard card_without_address;
autofill::test::SetCreditCardInfo(&card_without_address, "John Doe",
"4111111111111111", "1", "2050",
/* billing_address_id= */ "");
ON_CALL(mock_personal_data_manager_, GetCreditCards())
.WillByDefault(
Return(std::vector<autofill::CreditCard*>({&card_without_address})));
ON_CALL(mock_action_delegate_, CollectUserData(_, _))
.WillByDefault(Invoke([=](std::unique_ptr<CollectUserDataOptions>
collect_user_data_options,
std::unique_ptr<UserData> user_data) {
user_data->succeed = true;
EXPECT_THAT(user_data->available_payment_instruments, SizeIs(1));
EXPECT_EQ(user_data->available_payment_instruments[0]->card->Compare(
card_without_address),
0);
EXPECT_EQ(
user_data->available_payment_instruments[0]->billing_address.get(),
nullptr);
std::move(collect_user_data_options->confirm_callback)
.Run(std::move(user_data));
}));
ActionProto action_proto;
auto* user_data = action_proto.mutable_collect_user_data();
SetRequiredTermsFields(user_data);
user_data->add_supported_basic_card_networks("visa");
EXPECT_CALL(mock_personal_data_manager_, GetProfileByGUID(_)).Times(0);
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
} // namespace
} // namespace autofill_assistant