Commit 30cce44a authored by sandromaggi's avatar sandromaggi Committed by Commit Bot

[Autofill Assistant] Implementation for pattern in fallback.

This is an implementation of the pattern proposal for Assistant Autofill
fallback handler.

Note that this does not solve the full range of issues we might have
with phone numbers. This works for static pages, where we know what the
expected input-format is.

This CL gives more flexibility in how to combine the values as an
expression. All available information is automatically extracted and
exposed for use.

This should go together with the backend CL: cl/293790701

Bug: b/147755494
Bug: b/147281090
Change-Id: I4f5e03fde7001767df92ba869d990b1804d421fa
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2030887
Commit-Queue: Sandro Maggi <sandromaggi@google.com>
Reviewed-by: default avatarClemens Arbesser <arbesser@google.com>
Cr-Commit-Position: refs/heads/master@{#740304}
parent 318ceb6e
......@@ -53,7 +53,6 @@ import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto
import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto.PresentationProto;
import org.chromium.chrome.browser.autofill_assistant.proto.UseAddressProto;
import org.chromium.chrome.browser.autofill_assistant.proto.UseAddressProto.RequiredField;
import org.chromium.chrome.browser.autofill_assistant.proto.UseAddressProto.RequiredField.AddressField;
import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
......@@ -116,14 +115,14 @@ public class AutofillAssistantPersonalDataManagerTest {
"#profile_name"))
.addRequiredFields(
RequiredField.newBuilder()
.setAddressField(AddressField.FULL_NAME)
.setValueExpression("7")
.setElement(
ElementReferenceProto.newBuilder()
.addSelectors(
"#profile_name")))
.addRequiredFields(
RequiredField.newBuilder()
.setAddressField(AddressField.EMAIL)
.setValueExpression("9")
.setElement(
ElementReferenceProto.newBuilder()
.addSelectors("#email"))))
......
......@@ -10,9 +10,13 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/optional.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/batch_element_checker.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "third_party/re2/src/re2/re2.h"
#include "third_party/re2/src/re2/stringpiece.h"
namespace autofill_assistant {
namespace {
......@@ -25,7 +29,7 @@ AutofillErrorInfoProto::AutofillFieldError* AddAutofillError(
->add_autofill_field_error();
*field_error->mutable_field() =
required_field.selector.ToElementReferenceProto();
field_error->set_field_key(required_field.fallback_key);
field_error->set_value_expression(required_field.value_expression);
return field_error;
}
......@@ -53,21 +57,67 @@ RequiredFieldsFallbackHandler::RequiredFieldsFallbackHandler(
action_delegate_ = action_delegate;
}
RequiredFieldsFallbackHandler::~RequiredFieldsFallbackHandler() {}
RequiredFieldsFallbackHandler::~RequiredFieldsFallbackHandler() = default;
RequiredFieldsFallbackHandler::FallbackData::FallbackData() {}
RequiredFieldsFallbackHandler::RequiredField::RequiredField() = default;
RequiredFieldsFallbackHandler::FallbackData::~FallbackData() {}
RequiredFieldsFallbackHandler::RequiredField::~RequiredField() = default;
RequiredFieldsFallbackHandler::RequiredField::RequiredField(
const RequiredFieldsFallbackHandler::RequiredField& r) = default;
RequiredFieldsFallbackHandler::FallbackData::FallbackData() = default;
RequiredFieldsFallbackHandler::FallbackData::~FallbackData() = default;
void RequiredFieldsFallbackHandler::FallbackData::AddFormGroup(
const autofill::FormGroup& form_group) {
autofill::ServerFieldTypeSet available_fields;
form_group.GetNonEmptyTypes("en-US", &available_fields);
for (const auto& field : available_fields) {
field_values.emplace(static_cast<int>(field),
base::UTF16ToUTF8(form_group.GetInfo(
autofill::AutofillType(field), "en-US")));
}
}
base::Optional<std::string>
RequiredFieldsFallbackHandler::FallbackData::GetValue(int key) {
auto it = field_values.find(key);
if (it != field_values.end()) {
if (it != field_values.end() && !it->second.empty()) {
return it->second;
}
return base::nullopt;
}
base::Optional<std::string>
RequiredFieldsFallbackHandler::FallbackData::EvaluateExpression(
const std::string& value_expression) {
int key;
if (base::StringToInt(value_expression, &key)) {
return this->GetValue(key);
}
std::string out = value_expression;
std::string extractor = R"re(\$\{([^}]+)\})re";
re2::StringPiece input(value_expression);
while (re2::RE2::FindAndConsume(&input, extractor, &key)) {
auto rewrite_value = this->GetValue(key);
if (!rewrite_value.has_value()) {
VLOG(1) << "No value for " << key << " in " << value_expression;
return base::nullopt;
}
re2::RE2::Replace(&out, extractor, re2::StringPiece(rewrite_value.value()));
}
if (out.empty()) {
return base::nullopt;
}
return out;
}
void RequiredFieldsFallbackHandler::CheckAndFallbackRequiredFields(
const ClientStatus& initial_autofill_status,
std::unique_ptr<FallbackData> fallback_data,
......@@ -160,7 +210,8 @@ void RequiredFieldsFallbackHandler::OnCheckRequiredFieldsDone(
continue;
}
if (fallback_data->GetValue(required_field.fallback_key).has_value()) {
if (fallback_data->EvaluateExpression(required_field.value_expression)
.has_value()) {
has_fallbacks = true;
} else {
FillStatusDetailsWithMissingFallbackData(required_field, &client_status_);
......@@ -211,7 +262,8 @@ void RequiredFieldsFallbackHandler::OnGetFallbackFieldTag(
const std::string& element_tag) {
// Set the next field to its fallback value.
const RequiredField& required_field = required_fields_[required_fields_index];
auto fallback_value = fallback_data->GetValue(required_field.fallback_key);
auto fallback_value =
fallback_data->EvaluateExpression(required_field.value_expression);
if (!fallback_value.has_value()) {
VLOG(3) << "No fallback for " << required_field.selector;
// If there is no fallback value, we skip this failed field.
......
......@@ -27,13 +27,16 @@ class RequiredFieldsFallbackHandler {
public:
enum FieldValueStatus { UNKNOWN, EMPTY, NOT_EMPTY };
struct RequiredField {
RequiredField();
~RequiredField();
RequiredField(const RequiredField& copy);
Selector selector;
bool simulate_key_presses = false;
int delay_in_millisecond = 0;
bool forced = false;
FieldValueStatus status = UNKNOWN;
int fallback_key;
std::string value_expression;
// Returns true if fallback is required for this field.
bool ShouldFallback(bool has_fallback_data) const {
......@@ -49,12 +52,17 @@ class RequiredFieldsFallbackHandler {
FallbackData();
~FallbackData();
// the key of the map should be the same as the |fallback_key| of the
// required field.
// The key of the map. Should be either an entry of field_types.h or an
// enum of Use*Action::AutofillAssistantCustomField.
std::map<int, std::string> field_values;
void AddFormGroup(const autofill::FormGroup& form_group);
base::Optional<std::string> GetValue(int key);
base::Optional<std::string> EvaluateExpression(
const std::string& value_expression);
private:
DISALLOW_COPY_AND_ASSIGN(FallbackData);
};
......
......@@ -10,9 +10,6 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/optional.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
......@@ -33,15 +30,14 @@ UseAddressAction::UseAddressAction(ActionDelegate* delegate,
std::vector<RequiredField> required_fields;
for (const auto& required_field_proto :
proto_.use_address().required_fields()) {
if (required_field_proto.address_field() ==
UseAddressProto::RequiredField::UNDEFINED) {
VLOG(1) << "address_field enum not set, skipping required field";
if (required_field_proto.value_expression().empty()) {
VLOG(1) << "no fallback filling information provided, skipping field";
continue;
}
required_fields.emplace_back();
RequiredField& required_field = required_fields.back();
required_field.fallback_key = (int)required_field_proto.address_field();
required_field.value_expression = required_field_proto.value_expression();
required_field.selector = Selector(required_field_proto.element());
required_field.simulate_key_presses =
required_field_proto.simulate_key_presses();
......@@ -125,56 +121,12 @@ void UseAddressAction::OnFormFilled(std::unique_ptr<FallbackData> fallback_data,
weak_ptr_factory_.GetWeakPtr()));
}
// This logic is from NameInfo::FullName.
base::string16 FullName(const autofill::AutofillProfile& profile) {
return autofill::data_util::JoinNameParts(
profile.GetRawInfo(autofill::NAME_FIRST),
profile.GetRawInfo(autofill::NAME_MIDDLE),
profile.GetRawInfo(autofill::NAME_LAST));
}
std::unique_ptr<FallbackData> UseAddressAction::CreateFallbackData(
const autofill::AutofillProfile& profile) {
auto fallback_data = std::make_unique<FallbackData>();
fallback_data->field_values.emplace(
(int)UseAddressProto::RequiredField::FIRST_NAME,
base::UTF16ToUTF8(profile.GetRawInfo(autofill::NAME_FIRST)));
fallback_data->field_values.emplace(
(int)UseAddressProto::RequiredField::LAST_NAME,
base::UTF16ToUTF8(profile.GetRawInfo(autofill::NAME_LAST)));
fallback_data->field_values.emplace(
(int)UseAddressProto::RequiredField::FULL_NAME,
base::UTF16ToUTF8(FullName(profile)));
fallback_data->field_values.emplace(
(int)UseAddressProto::RequiredField::PHONE_NUMBER,
base::UTF16ToUTF8(profile.GetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER)));
fallback_data->field_values.emplace(
(int)UseAddressProto::RequiredField::EMAIL,
base::UTF16ToUTF8(profile.GetRawInfo(autofill::EMAIL_ADDRESS)));
fallback_data->field_values.emplace(
(int)UseAddressProto::RequiredField::ORGANIZATION,
base::UTF16ToUTF8(profile.GetRawInfo(autofill::COMPANY_NAME)));
fallback_data->field_values.emplace(
(int)UseAddressProto::RequiredField::COUNTRY_CODE,
base::UTF16ToUTF8(profile.GetRawInfo(autofill::ADDRESS_HOME_COUNTRY)));
fallback_data->field_values.emplace(
(int)UseAddressProto::RequiredField::REGION,
base::UTF16ToUTF8(profile.GetRawInfo(autofill::ADDRESS_HOME_STATE)));
fallback_data->field_values.emplace(
(int)UseAddressProto::RequiredField::STREET_ADDRESS,
base::UTF16ToUTF8(
profile.GetRawInfo(autofill::ADDRESS_HOME_STREET_ADDRESS)));
fallback_data->field_values.emplace(
(int)UseAddressProto::RequiredField::LOCALITY,
base::UTF16ToUTF8(profile.GetRawInfo(autofill::ADDRESS_HOME_CITY)));
fallback_data->field_values.emplace(
(int)UseAddressProto::RequiredField::DEPENDANT_LOCALITY,
base::UTF16ToUTF8(
profile.GetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_LOCALITY)));
fallback_data->field_values.emplace(
(int)UseAddressProto::RequiredField::POSTAL_CODE,
base::UTF16ToUTF8(profile.GetRawInfo(autofill::ADDRESS_HOME_ZIP)));
fallback_data->AddFormGroup(profile);
return fallback_data;
}
} // namespace autofill_assistant
......@@ -7,6 +7,7 @@
#include <utility>
#include "base/guid.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
......@@ -41,10 +42,7 @@ class UseAddressActionTest : public testing::Test {
base::GenerateGUID(), autofill::test::kEmptyOrigin);
autofill::test::SetProfileInfo(autofill_profile.get(), kFirstName, "",
kLastName, kEmail, "", "", "", "", "", "",
"", "");
autofill::test::SetProfileInfo(&autofill_profile_, kFirstName, "",
kLastName, kEmail, "", "", "", "", "", "",
"", "");
"", kPhoneNumber);
user_data_.selected_addresses_[kAddressName] = std::move(autofill_profile);
ON_CALL(mock_personal_data_manager_, GetProfileByGUID)
......@@ -68,6 +66,7 @@ class UseAddressActionTest : public testing::Test {
const char* const kFirstName = "FirstName";
const char* const kLastName = "LastName";
const char* const kEmail = "foobar@gmail.com";
const char* const kPhoneNumber = "+41791234567";
ActionProto CreateUseAddressAction() {
ActionProto action;
......@@ -77,12 +76,11 @@ class UseAddressActionTest : public testing::Test {
return action;
}
UseAddressProto::RequiredField* AddRequiredField(
ActionProto* action,
UseAddressProto::RequiredField::AddressField type,
std::string selector) {
UseAddressProto::RequiredField* AddRequiredField(ActionProto* action,
std::string value_expression,
std::string selector) {
auto* required_field = action->mutable_use_address()->add_required_fields();
required_field->set_address_field(type);
required_field->set_value_expression(value_expression);
required_field->mutable_element()->add_selectors(selector);
return required_field;
}
......@@ -178,11 +176,17 @@ TEST_F(UseAddressActionTest, ValidationSucceeds) {
InSequence seq;
ActionProto action_proto = CreateUseAddressAction();
AddRequiredField(&action_proto, UseAddressProto::RequiredField::FIRST_NAME,
AddRequiredField(&action_proto,
base::NumberToString(
static_cast<int>(autofill::ServerFieldType::NAME_FIRST)),
"#first_name");
AddRequiredField(&action_proto, UseAddressProto::RequiredField::LAST_NAME,
AddRequiredField(&action_proto,
base::NumberToString(
static_cast<int>(autofill::ServerFieldType::NAME_LAST)),
"#last_name");
AddRequiredField(&action_proto, UseAddressProto::RequiredField::EMAIL,
AddRequiredField(&action_proto,
base::NumberToString(static_cast<int>(
autofill::ServerFieldType::EMAIL_ADDRESS)),
"#email");
// Autofill succeeds.
......@@ -204,11 +208,17 @@ TEST_F(UseAddressActionTest, FallbackFails) {
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
ActionProto action_proto = CreateUseAddressAction();
AddRequiredField(&action_proto, UseAddressProto::RequiredField::FIRST_NAME,
AddRequiredField(&action_proto,
base::NumberToString(
static_cast<int>(autofill::ServerFieldType::NAME_FIRST)),
"#first_name");
AddRequiredField(&action_proto, UseAddressProto::RequiredField::LAST_NAME,
AddRequiredField(&action_proto,
base::NumberToString(
static_cast<int>(autofill::ServerFieldType::NAME_LAST)),
"#last_name");
AddRequiredField(&action_proto, UseAddressProto::RequiredField::EMAIL,
AddRequiredField(&action_proto,
base::NumberToString(static_cast<int>(
autofill::ServerFieldType::EMAIL_ADDRESS)),
"#email");
// Autofill succeeds.
......@@ -242,11 +252,17 @@ TEST_F(UseAddressActionTest, FallbackSucceeds) {
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
ActionProto action_proto = CreateUseAddressAction();
AddRequiredField(&action_proto, UseAddressProto::RequiredField::FIRST_NAME,
AddRequiredField(&action_proto,
base::NumberToString(
static_cast<int>(autofill::ServerFieldType::NAME_FIRST)),
"#first_name");
AddRequiredField(&action_proto, UseAddressProto::RequiredField::LAST_NAME,
AddRequiredField(&action_proto,
base::NumberToString(
static_cast<int>(autofill::ServerFieldType::NAME_LAST)),
"#last_name");
AddRequiredField(&action_proto, UseAddressProto::RequiredField::EMAIL,
AddRequiredField(&action_proto,
base::NumberToString(static_cast<int>(
autofill::ServerFieldType::EMAIL_ADDRESS)),
"#email");
// Autofill succeeds.
......@@ -306,7 +322,9 @@ TEST_F(UseAddressActionTest,
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
ActionProto action_proto = CreateUseAddressAction();
AddRequiredField(&action_proto, UseAddressProto::RequiredField::FIRST_NAME,
AddRequiredField(&action_proto,
base::NumberToString(
static_cast<int>(autofill::ServerFieldType::NAME_FIRST)),
"#first_name");
EXPECT_CALL(mock_action_delegate_,
......@@ -344,5 +362,39 @@ TEST_F(UseAddressActionTest,
OTHER_ACTION_STATUS);
}
TEST_F(UseAddressActionTest, FallbackForPhoneSucceeds) {
ON_CALL(mock_action_delegate_, GetElementTag(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
ActionProto action_proto = CreateUseAddressAction();
AddRequiredField(&action_proto, "(+${12}) (${11}) ${10}", "#phone_number");
// Autofill succeeds.
EXPECT_CALL(mock_action_delegate_,
OnFillAddressForm(
NotNull(), Eq(Selector({kFakeSelector}).MustBeVisible()), _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
// Validation fails when getting phone number.
EXPECT_CALL(mock_web_controller_,
OnGetFieldValue(Eq(Selector({"#phone_number"})), _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
// Fallback succeeds.
Expectation set_first_name =
EXPECT_CALL(mock_action_delegate_,
OnSetFieldValue(Eq(Selector({"#phone_number"})),
"(+41) (79) 1234567", _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
// Second validation succeeds.
EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _))
.After(set_first_name)
.WillRepeatedly(RunOnceCallback<1>(OkClientStatus(), "not empty"));
EXPECT_EQ(ProcessedActionStatusProto::ACTION_APPLIED,
ProcessAction(action_proto));
}
} // namespace
} // namespace autofill_assistant
......@@ -10,8 +10,6 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/optional.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
......@@ -33,15 +31,14 @@ UseCreditCardAction::UseCreditCardAction(ActionDelegate* delegate,
prompt_ = proto.use_card().prompt();
std::vector<RequiredField> required_fields;
for (const auto& required_field_proto : proto_.use_card().required_fields()) {
if (required_field_proto.card_field() ==
UseCreditCardProto::RequiredField::UNDEFINED) {
VLOG(1) << "card_field enum not set, skipping required field";
if (required_field_proto.value_expression().empty()) {
VLOG(1) << "no fallback filling information provided, skipping field";
continue;
}
required_fields.emplace_back();
RequiredField& required_field = required_fields.back();
required_field.fallback_key = (int)required_field_proto.card_field();
required_field.value_expression = required_field_proto.value_expression();
required_field.selector = Selector(required_field_proto.element());
required_field.simulate_key_presses =
required_field_proto.simulate_key_presses();
......@@ -130,42 +127,20 @@ std::unique_ptr<FallbackData> UseCreditCardAction::CreateFallbackData(
const base::string16& cvc,
const autofill::CreditCard& card) {
auto fallback_data = std::make_unique<FallbackData>();
fallback_data->field_values.emplace(
(int)UseCreditCardProto::RequiredField::CREDIT_CARD_VERIFICATION_CODE,
base::UTF16ToUTF8(cvc));
if (card.expiration_month() > 0) {
fallback_data->field_values.emplace(
(int)UseCreditCardProto::RequiredField::CREDIT_CARD_EXP_MONTH,
base::StringPrintf("%02d", card.expiration_month()));
}
if (card.expiration_year() > 0) {
fallback_data->field_values.emplace(
(int)UseCreditCardProto::RequiredField::CREDIT_CARD_EXP_2_DIGIT_YEAR,
base::StringPrintf("%02d", card.expiration_year() % 100));
fallback_data->field_values.emplace(
(int)UseCreditCardProto::RequiredField::CREDIT_CARD_EXP_4_DIGIT_YEAR,
base::StringPrintf("%04d", card.expiration_year()));
if (card.expiration_month() > 0) {
fallback_data->field_values.emplace(
(int)UseCreditCardProto::RequiredField::CREDIT_CARD_EXP_MM_YY,
base::StrCat(
{base::StringPrintf("%02d", card.expiration_month()), "/",
base::StringPrintf("%02d", card.expiration_year() % 100)}));
}
}
fallback_data->field_values.emplace(
(int)UseCreditCardProto::RequiredField::CREDIT_CARD_CARD_HOLDER_NAME,
base::UTF16ToUTF8(card.GetRawInfo(autofill::CREDIT_CARD_NAME_FULL)));
static_cast<int>(
UseCreditCardProto::RequiredField::CREDIT_CARD_VERIFICATION_CODE),
base::UTF16ToUTF8(cvc));
fallback_data->field_values.emplace(
(int)UseCreditCardProto::RequiredField::CREDIT_CARD_NUMBER,
(int)UseCreditCardProto::RequiredField::CREDIT_CARD_RAW_NUMBER,
base::UTF16ToUTF8(card.GetRawInfo(autofill::CREDIT_CARD_NUMBER)));
fallback_data->field_values.emplace(
(int)UseCreditCardProto::RequiredField::CREDIT_CARD_NETWORK,
static_cast<int>(UseCreditCardProto::RequiredField::CREDIT_CARD_NETWORK),
autofill::data_util::GetPaymentRequestData(card.network())
.basic_card_issuer_network);
fallback_data->AddFormGroup(card);
return fallback_data;
}
} // namespace autofill_assistant
......@@ -7,6 +7,7 @@
#include <utility>
#include "base/guid.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
......@@ -25,7 +26,6 @@ using ::base::test::RunOnceCallback;
using ::testing::_;
using ::testing::Eq;
using ::testing::Expectation;
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::NotNull;
using ::testing::Return;
......@@ -41,9 +41,6 @@ class UseCreditCardActionTest : public testing::Test {
autofill::test::SetProfileInfo(autofill_profile.get(), kFirstName, "",
kLastName, kEmail, "", "", "", "", "", "",
"", "");
autofill::test::SetProfileInfo(&autofill_profile_, kFirstName, "",
kLastName, kEmail, "", "", "", "", "", "",
"", "");
user_data_.selected_addresses_[kAddressName] = std::move(autofill_profile);
ON_CALL(mock_personal_data_manager_, GetProfileByGUID)
.WillByDefault(Return(&autofill_profile_));
......@@ -76,10 +73,10 @@ class UseCreditCardActionTest : public testing::Test {
UseCreditCardProto::RequiredField* AddRequiredField(
ActionProto* action,
UseCreditCardProto::RequiredField::CardField type,
std::string value_expression,
std::string selector) {
auto* required_field = action->mutable_use_card()->add_required_fields();
required_field->set_card_field(type);
required_field->set_value_expression(value_expression);
required_field->mutable_element()->add_selectors(selector);
return required_field;
}
......@@ -137,10 +134,13 @@ TEST_F(UseCreditCardActionTest, FillCreditCardRequiredFieldsFilled) {
ActionProto action = CreateUseCreditCardAction();
AddRequiredField(
&action, UseCreditCardProto::RequiredField::CREDIT_CARD_VERIFICATION_CODE,
&action,
base::NumberToString(static_cast<int>(
UseCreditCardProto::RequiredField::CREDIT_CARD_VERIFICATION_CODE)),
"#cvc");
AddRequiredField(&action,
UseCreditCardProto::RequiredField::CREDIT_CARD_EXP_MONTH,
base::NumberToString(static_cast<int>(
autofill::ServerFieldType::CREDIT_CARD_EXP_MONTH)),
"#expmonth");
autofill::CreditCard credit_card;
......@@ -162,28 +162,35 @@ TEST_F(UseCreditCardActionTest, FillCreditCardWithFallback) {
ActionProto action = CreateUseCreditCardAction();
AddRequiredField(
&action, UseCreditCardProto::RequiredField::CREDIT_CARD_VERIFICATION_CODE,
&action,
base::NumberToString(static_cast<int>(
UseCreditCardProto::RequiredField::CREDIT_CARD_VERIFICATION_CODE)),
"#cvc");
AddRequiredField(&action,
UseCreditCardProto::RequiredField::CREDIT_CARD_EXP_MONTH,
base::NumberToString(static_cast<int>(
autofill::ServerFieldType::CREDIT_CARD_EXP_MONTH)),
"#expmonth");
AddRequiredField(
&action, UseCreditCardProto::RequiredField::CREDIT_CARD_EXP_2_DIGIT_YEAR,
&action,
base::NumberToString(static_cast<int>(
autofill::ServerFieldType::CREDIT_CARD_EXP_2_DIGIT_YEAR)),
"#expyear2");
AddRequiredField(
&action, UseCreditCardProto::RequiredField::CREDIT_CARD_EXP_4_DIGIT_YEAR,
&action,
base::NumberToString(static_cast<int>(
autofill::ServerFieldType::CREDIT_CARD_EXP_4_DIGIT_YEAR)),
"#expyear4");
AddRequiredField(
&action, UseCreditCardProto::RequiredField::CREDIT_CARD_CARD_HOLDER_NAME,
"#card_name");
AddRequiredField(&action,
UseCreditCardProto::RequiredField::CREDIT_CARD_NUMBER,
"#card_number");
base::NumberToString(static_cast<int>(
autofill::ServerFieldType::CREDIT_CARD_NAME_FULL)),
"#card_name");
AddRequiredField(&action,
UseCreditCardProto::RequiredField::CREDIT_CARD_EXP_MM_YY,
"#exp_month_year2");
base::NumberToString(static_cast<int>(
autofill::ServerFieldType::CREDIT_CARD_NUMBER)),
"#card_number");
AddRequiredField(&action,
UseCreditCardProto::RequiredField::CREDIT_CARD_NETWORK,
base::NumberToString(static_cast<int>(
UseCreditCardProto::RequiredField::CREDIT_CARD_NETWORK)),
"#network");
// First validation fails.
......@@ -201,9 +208,6 @@ TEST_F(UseCreditCardActionTest, FillCreditCardWithFallback) {
EXPECT_CALL(mock_web_controller_,
OnGetFieldValue(Selector({"#card_number"}), _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
EXPECT_CALL(mock_web_controller_,
OnGetFieldValue(Selector({"#exp_month_year2"}), _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
EXPECT_CALL(mock_web_controller_, OnGetFieldValue(Selector({"#network"}), _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
......@@ -233,10 +237,6 @@ TEST_F(UseCreditCardActionTest, FillCreditCardWithFallback) {
mock_action_delegate_,
OnSetFieldValue(Selector({"#card_number"}), "4111111111111111", _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
Expectation set_exp_month_year2 =
EXPECT_CALL(mock_action_delegate_,
OnSetFieldValue(Selector({"#exp_month_year2"}), "09/24", _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
Expectation set_card_network =
EXPECT_CALL(mock_action_delegate_,
OnSetFieldValue(Selector({"#network"}), "visa", _))
......@@ -263,10 +263,6 @@ TEST_F(UseCreditCardActionTest, FillCreditCardWithFallback) {
OnGetFieldValue(Selector({"#card_number"}), _))
.After(set_expyear4)
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
EXPECT_CALL(mock_web_controller_,
OnGetFieldValue(Selector({"#exp_month_year2"}), _))
.After(set_expyear4)
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
EXPECT_CALL(mock_web_controller_, OnGetFieldValue(Selector({"#network"}), _))
.After(set_card_network)
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
......@@ -296,7 +292,9 @@ TEST_F(UseCreditCardActionTest, ForcedFallback) {
ActionProto action = CreateUseCreditCardAction();
auto* cvc_required = AddRequiredField(
&action, UseCreditCardProto::RequiredField::CREDIT_CARD_VERIFICATION_CODE,
&action,
base::NumberToString(static_cast<int>(
UseCreditCardProto::RequiredField::CREDIT_CARD_VERIFICATION_CODE)),
"#cvc");
cvc_required->set_forced(true);
cvc_required->set_simulate_key_presses(true);
......@@ -357,7 +355,9 @@ TEST_F(UseCreditCardActionTest,
ActionProto action_proto = CreateUseCreditCardAction();
AddRequiredField(
&action_proto,
UseCreditCardProto::RequiredField::CREDIT_CARD_VERIFICATION_CODE, "#cvc");
base::NumberToString(static_cast<int>(
UseCreditCardProto::RequiredField::CREDIT_CARD_VERIFICATION_CODE)),
"#cvc");
autofill::CreditCard credit_card;
user_data_.selected_card_ =
......@@ -397,5 +397,50 @@ TEST_F(UseCreditCardActionTest,
OTHER_ACTION_STATUS);
}
TEST_F(UseCreditCardActionTest, FallbackForCardExpirationSucceeds) {
ON_CALL(mock_action_delegate_, GetElementTag(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
ActionProto action_proto = CreateUseCreditCardAction();
AddRequiredField(&action_proto, "${53} - ${55}", "#expiration_date");
// Autofill succeeds.
autofill::CreditCard credit_card;
credit_card.SetExpirationMonth(9);
credit_card.SetExpirationYear(2050);
credit_card.SetRawInfo(autofill::CREDIT_CARD_NAME_FULL,
base::UTF8ToUTF16("Jon Doe"));
credit_card.SetRawInfo(autofill::CREDIT_CARD_NUMBER,
base::UTF8ToUTF16("4111111111111111"));
user_data_.selected_card_ =
std::make_unique<autofill::CreditCard>(credit_card);
EXPECT_CALL(mock_action_delegate_, OnGetFullCard(_))
.WillOnce(RunOnceCallback<0>(credit_card, base::UTF8ToUTF16("123")));
EXPECT_CALL(mock_action_delegate_,
OnFillCardForm(_, base::UTF8ToUTF16("123"),
Selector({kFakeSelector}).MustBeVisible(), _))
.WillOnce(RunOnceCallback<3>(OkClientStatus()));
// Validation fails when getting expiration date.
EXPECT_CALL(mock_web_controller_,
OnGetFieldValue(Eq(Selector({"#expiration_date"})), _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
// Fallback succeeds.
Expectation set_expiration_date =
EXPECT_CALL(
mock_action_delegate_,
OnSetFieldValue(Eq(Selector({"#expiration_date"})), "09 - 2050", _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
// Second validation succeeds.
EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _))
.After(set_expiration_date)
.WillRepeatedly(RunOnceCallback<1>(OkClientStatus(), "not empty"));
EXPECT_EQ(ProcessedActionStatusProto::ACTION_APPLIED,
ProcessAction(action_proto));
}
} // namespace
} // namespace autofill_assistant
......@@ -640,8 +640,8 @@ message AutofillErrorInfoProto {
// The field the error occurred for.
optional ElementReferenceProto field = 1;
// The key of the fallback field. Matches the RequiredField::X enum entry.
optional int32 field_key = 2;
// The value expression associated with the field that caused the error.
optional string value_expression = 5;
oneof error_type {
// No fallback value for this field.
......@@ -650,6 +650,8 @@ message AutofillErrorInfoProto {
// The status of the action.
ProcessedActionStatusProto status = 4;
}
reserved 2;
}
// Comma separated list of address keys in the client memory when the
......@@ -936,23 +938,21 @@ message UseAddressProto {
// Message used to indicate what form fields should be filled with what
// information coming from the address.
message RequiredField {
enum AddressField {
UNDEFINED = 0;
FIRST_NAME = 1;
LAST_NAME = 2;
FULL_NAME = 3;
PHONE_NUMBER = 4;
EMAIL = 5;
ORGANIZATION = 6;
COUNTRY_CODE = 7;
REGION = 8; // e.g. state
STREET_ADDRESS = 9;
LOCALITY = 10; // e.g. city
DEPENDANT_LOCALITY = 11;
POSTAL_CODE = 12;
}
optional AddressField address_field = 1;
// Fields we add that are not mapped to field_types.h. The values must be
// negative not to overlap with the source.
enum AutofillAssistantCustomField { UNDEFINED = 0; }
// A string containing either a single integer key or multiple "${key}"
// placeholders, where the key is an integer corresponding to entries from
// field_types.h or RequiredField::AutofillAssistantCustomField.
// Example:
// * "3" -> First name.
// * "${3}" -> First name.
// * "(+${12}) (${11}) ${10}" -> phone country code, city code, number,
// e.g., (+41) (79) (1234567)
// Note that the set of actually available fields are outside of our
// control and are retrieved automatically from the provided profile.
optional string value_expression = 6;
optional ElementReferenceProto element = 2;
......@@ -967,6 +967,8 @@ message UseAddressProto {
// cases where the way autofill sets the field doesn't work on the website.
// Usually used together with simulate_key_presses.
optional bool forced = 5;
reserved 1;
}
// An optional name to allow to handle multiple addresses selection (for
......@@ -990,19 +992,25 @@ message UseCreditCardProto {
// Message used to indicate what form fields should be filled with what
// information.
message RequiredField {
enum CardField {
// Fields we add that are not mapped to field_types.h. The values must be
// negative not to overlap with the source.
enum AutofillAssistantCustomField {
UNDEFINED = 0;
CREDIT_CARD_VERIFICATION_CODE = 1;
CREDIT_CARD_EXP_MONTH = 2;
CREDIT_CARD_EXP_2_DIGIT_YEAR = 3;
CREDIT_CARD_EXP_4_DIGIT_YEAR = 4;
CREDIT_CARD_CARD_HOLDER_NAME = 5;
CREDIT_CARD_NUMBER = 6;
CREDIT_CARD_EXP_MM_YY = 7;
CREDIT_CARD_NETWORK = 8;
CREDIT_CARD_VERIFICATION_CODE = -1;
CREDIT_CARD_NETWORK = -2;
CREDIT_CARD_RAW_NUMBER = -3;
}
optional CardField card_field = 1;
// A string containing either a single integer key or multiple "${key}"
// placeholders, where the key is an integer corresponding to entries from
// field_types.h or RequiredField::AutofillAssistantCustomField.
// Example:
// * "51" -> Full name.
// * "${51}" -> Full Name.
// * "${53}/${55}" -> expiration month / expiration year
// Note that the set of actually available fields are outside of our
// control and are retrieved automatically from the provided credit card.
optional string value_expression = 6;
optional ElementReferenceProto element = 2;
......@@ -1017,6 +1025,8 @@ message UseCreditCardProto {
// cases where the way autofill sets the field doesn't work on the website.
// Usually used together with simulate_key_presses.
optional bool forced = 5;
reserved 1;
}
// An optional message to show to the user when asking to select a card.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment