blob: 2ae1798b91db8ec5d46b292462efaf6c0644adec [file] [log] [blame]
// Copyright 2017 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 "ios/chrome/browser/payments/payment_request.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/payments/core/currency_formatter.h"
#include "components/payments/core/payment_method_data.h"
#include "ios/chrome/browser/application_context.h"
#include "ios/web/public/payments/payment_request.h"
#include "testing/gtest/include/gtest/gtest.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
class PaymentRequestTest : public testing::Test {
protected:
// Returns PaymentDetails with one shipping option that's selected.
web::PaymentDetails CreateDetailsWithShippingOption() {
web::PaymentDetails details;
std::vector<web::PaymentShippingOption> shipping_options;
web::PaymentShippingOption option1;
option1.id = base::UTF8ToUTF16("option:1");
option1.selected = true;
shipping_options.push_back(std::move(option1));
details.shipping_options = std::move(shipping_options);
return details;
}
web::PaymentOptions CreatePaymentOptions(bool request_payer_name,
bool request_payer_phone,
bool request_payer_email,
bool request_shipping) {
web::PaymentOptions options;
options.request_payer_name = request_payer_name;
options.request_payer_phone = request_payer_phone;
options.request_payer_email = request_payer_email;
options.request_shipping = request_shipping;
return options;
}
};
// Tests that the payments::CurrencyFormatter is constructed with the correct
// currency code and currency system.
TEST_F(PaymentRequestTest, CreatesCurrencyFormatterCorrectly) {
ASSERT_EQ("en", GetApplicationContext()->GetApplicationLocale());
web::PaymentRequest web_payment_request;
autofill::TestPersonalDataManager personal_data_manager;
web_payment_request.details.total.amount.currency = base::ASCIIToUTF16("USD");
PaymentRequest payment_request1(web_payment_request, &personal_data_manager);
payments::CurrencyFormatter* currency_formatter =
payment_request1.GetOrCreateCurrencyFormatter();
EXPECT_EQ(base::UTF8ToUTF16("$55.00"), currency_formatter->Format("55.00"));
EXPECT_EQ("USD", currency_formatter->formatted_currency_code());
web_payment_request.details.total.amount.currency = base::ASCIIToUTF16("JPY");
PaymentRequest payment_request2(web_payment_request, &personal_data_manager);
currency_formatter = payment_request2.GetOrCreateCurrencyFormatter();
EXPECT_EQ(base::UTF8ToUTF16("¥55"), currency_formatter->Format("55.00"));
EXPECT_EQ("JPY", currency_formatter->formatted_currency_code());
web_payment_request.details.total.amount.currency_system =
base::ASCIIToUTF16("NOT_ISO4217");
web_payment_request.details.total.amount.currency = base::ASCIIToUTF16("USD");
PaymentRequest payment_request3(web_payment_request, &personal_data_manager);
currency_formatter = payment_request3.GetOrCreateCurrencyFormatter();
EXPECT_EQ(base::UTF8ToUTF16("55.00"), currency_formatter->Format("55.00"));
EXPECT_EQ("USD", currency_formatter->formatted_currency_code());
}
// Tests that the accepted card networks are identified correctly.
TEST_F(PaymentRequestTest, AcceptedPaymentNetworks) {
web::PaymentRequest web_payment_request;
autofill::TestPersonalDataManager personal_data_manager;
payments::PaymentMethodData method_datum1;
method_datum1.supported_methods.push_back("visa");
web_payment_request.method_data.push_back(method_datum1);
payments::PaymentMethodData method_datum2;
method_datum2.supported_methods.push_back("mastercard");
web_payment_request.method_data.push_back(method_datum2);
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
ASSERT_EQ(2U, payment_request.supported_card_networks().size());
EXPECT_EQ("visa", payment_request.supported_card_networks()[0]);
EXPECT_EQ("mastercard", payment_request.supported_card_networks()[1]);
}
// Test that parsing supported methods (with invalid values and duplicates)
// works as expected.
TEST_F(PaymentRequestTest, SupportedMethods) {
web::PaymentRequest web_payment_request;
autofill::TestPersonalDataManager personal_data_manager;
payments::PaymentMethodData method_datum1;
method_datum1.supported_methods.push_back("visa");
method_datum1.supported_methods.push_back("mastercard");
method_datum1.supported_methods.push_back("invalid");
method_datum1.supported_methods.push_back("");
method_datum1.supported_methods.push_back("visa");
web_payment_request.method_data.push_back(method_datum1);
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
ASSERT_EQ(2U, payment_request.supported_card_networks().size());
EXPECT_EQ("visa", payment_request.supported_card_networks()[0]);
EXPECT_EQ("mastercard", payment_request.supported_card_networks()[1]);
}
// Test that parsing supported methods in different method data entries (with
// invalid values and duplicates) works as expected.
TEST_F(PaymentRequestTest, SupportedMethods_MultipleEntries) {
web::PaymentRequest web_payment_request;
autofill::TestPersonalDataManager personal_data_manager;
payments::PaymentMethodData method_datum1;
method_datum1.supported_methods.push_back("visa");
web_payment_request.method_data.push_back(method_datum1);
payments::PaymentMethodData method_datum2;
method_datum2.supported_methods.push_back("mastercard");
web_payment_request.method_data.push_back(method_datum2);
payments::PaymentMethodData method_datum3;
method_datum3.supported_methods.push_back("");
web_payment_request.method_data.push_back(method_datum3);
payments::PaymentMethodData method_datum4;
method_datum4.supported_methods.push_back("visa");
web_payment_request.method_data.push_back(method_datum4);
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
ASSERT_EQ(2U, payment_request.supported_card_networks().size());
EXPECT_EQ("visa", payment_request.supported_card_networks()[0]);
EXPECT_EQ("mastercard", payment_request.supported_card_networks()[1]);
}
// Test that only specifying basic-card means that all are supported.
TEST_F(PaymentRequestTest, SupportedMethods_OnlyBasicCard) {
web::PaymentRequest web_payment_request;
autofill::TestPersonalDataManager personal_data_manager;
payments::PaymentMethodData method_datum1;
method_datum1.supported_methods.push_back("basic-card");
web_payment_request.method_data.push_back(method_datum1);
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
// All of the basic card networks are supported.
ASSERT_EQ(8U, payment_request.supported_card_networks().size());
EXPECT_EQ("amex", payment_request.supported_card_networks()[0]);
EXPECT_EQ("diners", payment_request.supported_card_networks()[1]);
EXPECT_EQ("discover", payment_request.supported_card_networks()[2]);
EXPECT_EQ("jcb", payment_request.supported_card_networks()[3]);
EXPECT_EQ("mastercard", payment_request.supported_card_networks()[4]);
EXPECT_EQ("mir", payment_request.supported_card_networks()[5]);
EXPECT_EQ("unionpay", payment_request.supported_card_networks()[6]);
EXPECT_EQ("visa", payment_request.supported_card_networks()[7]);
}
// Test that specifying a method AND basic-card means that all are supported,
// but with the method as first.
TEST_F(PaymentRequestTest, SupportedMethods_BasicCard_WithSpecificMethod) {
web::PaymentRequest web_payment_request;
autofill::TestPersonalDataManager personal_data_manager;
payments::PaymentMethodData method_datum1;
method_datum1.supported_methods.push_back("jcb");
method_datum1.supported_methods.push_back("basic-card");
web_payment_request.method_data.push_back(method_datum1);
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
// All of the basic card networks are supported, but JCB is first because it
// was specified first.
EXPECT_EQ(8u, payment_request.supported_card_networks().size());
EXPECT_EQ("jcb", payment_request.supported_card_networks()[0]);
EXPECT_EQ("amex", payment_request.supported_card_networks()[1]);
EXPECT_EQ("diners", payment_request.supported_card_networks()[2]);
EXPECT_EQ("discover", payment_request.supported_card_networks()[3]);
EXPECT_EQ("mastercard", payment_request.supported_card_networks()[4]);
EXPECT_EQ("mir", payment_request.supported_card_networks()[5]);
EXPECT_EQ("unionpay", payment_request.supported_card_networks()[6]);
EXPECT_EQ("visa", payment_request.supported_card_networks()[7]);
}
// Test that specifying basic-card with a supported network (with previous
// supported methods) will work as expected
TEST_F(PaymentRequestTest, SupportedMethods_BasicCard_Overlap) {
web::PaymentRequest web_payment_request;
autofill::TestPersonalDataManager personal_data_manager;
payments::PaymentMethodData method_datum1;
method_datum1.supported_methods.push_back("mastercard");
method_datum1.supported_methods.push_back("visa");
web_payment_request.method_data.push_back(method_datum1);
payments::PaymentMethodData method_datum2;
method_datum2.supported_methods.push_back("basic-card");
method_datum2.supported_networks.push_back("visa");
method_datum2.supported_networks.push_back("mastercard");
method_datum2.supported_networks.push_back("unionpay");
web_payment_request.method_data.push_back(method_datum2);
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
EXPECT_EQ(3u, payment_request.supported_card_networks().size());
EXPECT_EQ("mastercard", payment_request.supported_card_networks()[0]);
EXPECT_EQ("visa", payment_request.supported_card_networks()[1]);
EXPECT_EQ("unionpay", payment_request.supported_card_networks()[2]);
}
// Test that specifying basic-card with supported networks after specifying
// some methods
TEST_F(PaymentRequestTest, SupportedMethods_BasicCard_WithSupportedNetworks) {
web::PaymentRequest web_payment_request;
autofill::TestPersonalDataManager personal_data_manager;
payments::PaymentMethodData method_datum1;
method_datum1.supported_methods.push_back("basic-card");
method_datum1.supported_networks.push_back("visa");
method_datum1.supported_networks.push_back("unionpay");
web_payment_request.method_data.push_back(method_datum1);
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
// Only the specified networks are supported.
EXPECT_EQ(2u, payment_request.supported_card_networks().size());
EXPECT_EQ("visa", payment_request.supported_card_networks()[0]);
EXPECT_EQ("unionpay", payment_request.supported_card_networks()[1]);
}
// Tests that a credit card can be added to the list of available credit cards.
TEST_F(PaymentRequestTest, AddCreditCard) {
web::PaymentRequest web_payment_request;
payments::PaymentMethodData method_datum;
method_datum.supported_methods.push_back("basic-card");
method_datum.supported_networks.push_back("visa");
method_datum.supported_networks.push_back("amex");
web_payment_request.method_data.push_back(method_datum);
autofill::TestPersonalDataManager personal_data_manager;
autofill::CreditCard credit_card_1 = autofill::test::GetCreditCard();
personal_data_manager.AddTestingCreditCard(&credit_card_1);
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
EXPECT_EQ(1U, payment_request.credit_cards().size());
autofill::CreditCard credit_card_2 = autofill::test::GetCreditCard2();
autofill::CreditCard* added_credit_card =
payment_request.AddCreditCard(credit_card_2);
EXPECT_EQ(2U, payment_request.credit_cards().size());
EXPECT_EQ(credit_card_2, *added_credit_card);
}
// Tests that a profile can be added to the list of available profiles.
TEST_F(PaymentRequestTest, AddAutofillProfile) {
web::PaymentRequest web_payment_request;
web_payment_request.options = CreatePaymentOptions(
/*request_payer_name=*/true, /*request_payer_phone=*/true,
/*request_payer_email=*/true, /*request_shipping=*/true);
autofill::TestPersonalDataManager personal_data_manager;
autofill::AutofillProfile profile_1 = autofill::test::GetFullProfile();
personal_data_manager.AddTestingProfile(&profile_1);
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
EXPECT_EQ(1U, payment_request.shipping_profiles().size());
EXPECT_EQ(1U, payment_request.contact_profiles().size());
autofill::AutofillProfile profile_2 = autofill::test::GetFullProfile2();
autofill::AutofillProfile* added_profile =
payment_request.AddAutofillProfile(profile_2);
EXPECT_EQ(2U, payment_request.shipping_profiles().size());
EXPECT_EQ(2U, payment_request.contact_profiles().size());
EXPECT_EQ(profile_2, *added_profile);
}
// Test that parsing shipping options works as expected.
TEST_F(PaymentRequestTest, SelectedShippingOptions) {
web::PaymentRequest web_payment_request;
autofill::TestPersonalDataManager personal_data_manager;
web::PaymentDetails details;
std::vector<web::PaymentShippingOption> shipping_options;
web::PaymentShippingOption option1;
option1.id = base::UTF8ToUTF16("option:1");
option1.selected = false;
shipping_options.push_back(std::move(option1));
web::PaymentShippingOption option2;
option2.id = base::UTF8ToUTF16("option:2");
option2.selected = true;
shipping_options.push_back(std::move(option2));
web::PaymentShippingOption option3;
option3.id = base::UTF8ToUTF16("option:3");
option3.selected = true;
shipping_options.push_back(std::move(option3));
details.shipping_options = std::move(shipping_options);
web_payment_request.details = std::move(details);
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
// The last one marked "selected" should be selected.
EXPECT_EQ(base::UTF8ToUTF16("option:3"),
payment_request.selected_shipping_option()->id);
// Simulate an update that no longer has any shipping options. There is no
// longer a selected shipping option.
web::PaymentDetails new_details;
payment_request.UpdatePaymentDetails(std::move(new_details));
EXPECT_EQ(nullptr, payment_request.selected_shipping_option());
}
// Test that loading profiles when none are available works as expected.
TEST_F(PaymentRequestTest, SelectedProfiles_NoProfiles) {
autofill::TestPersonalDataManager personal_data_manager;
web::PaymentRequest web_payment_request;
web_payment_request.details = CreateDetailsWithShippingOption();
web_payment_request.options = CreatePaymentOptions(
/*request_payer_name=*/true, /*request_payer_phone=*/true,
/*request_payer_email=*/true, /*request_shipping=*/true);
// No profiles are selected because none are available!
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
EXPECT_EQ(nullptr, payment_request.selected_shipping_profile());
EXPECT_EQ(nullptr, payment_request.selected_contact_profile());
}
// Test that loading complete shipping and contact profiles works as expected.
TEST_F(PaymentRequestTest, SelectedProfiles_Complete) {
autofill::TestPersonalDataManager personal_data_manager;
autofill::AutofillProfile address = autofill::test::GetFullProfile();
address.set_use_count(5U);
personal_data_manager.AddTestingProfile(&address);
autofill::AutofillProfile address2 = autofill::test::GetFullProfile2();
address2.set_use_count(15U);
personal_data_manager.AddTestingProfile(&address2);
web::PaymentRequest web_payment_request;
web_payment_request.details = CreateDetailsWithShippingOption();
web_payment_request.options = CreatePaymentOptions(
/*request_payer_name=*/true, /*request_payer_phone=*/true,
/*request_payer_email=*/true, /*request_shipping=*/true);
// address2 is selected because it has the most use count (Frecency model).
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
EXPECT_EQ(address2.guid(),
payment_request.selected_shipping_profile()->guid());
EXPECT_EQ(address2.guid(),
payment_request.selected_contact_profile()->guid());
}
// Test that loading complete shipping and contact profiles, when there are no
// shipping options available, works as expected.
TEST_F(PaymentRequestTest, SelectedProfiles_Complete_NoShippingOption) {
autofill::TestPersonalDataManager personal_data_manager;
autofill::AutofillProfile address = autofill::test::GetFullProfile();
address.set_use_count(5U);
personal_data_manager.AddTestingProfile(&address);
web::PaymentRequest web_payment_request;
// No shipping options.
web_payment_request.details = web::PaymentDetails();
web_payment_request.options = CreatePaymentOptions(
/*request_payer_name=*/true, /*request_payer_phone=*/true,
/*request_payer_email=*/true, /*request_shipping=*/true);
// No shipping profile is selected because the merchant has not selected a
// shipping option. However there is a suitable contact profile.
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
EXPECT_EQ(nullptr, payment_request.selected_shipping_profile());
EXPECT_EQ(address.guid(), payment_request.selected_contact_profile()->guid());
}
// Test that loading incomplete shipping and contact profiles works as expected.
TEST_F(PaymentRequestTest, SelectedProfiles_Incomplete) {
autofill::TestPersonalDataManager personal_data_manager;
// Add a profile with no phone (incomplete).
autofill::AutofillProfile address1 = autofill::test::GetFullProfile();
address1.SetInfo(autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
base::string16(), "en-US");
address1.set_use_count(5U);
personal_data_manager.AddTestingProfile(&address1);
// Add a complete profile, with fewer use counts.
autofill::AutofillProfile address2 = autofill::test::GetFullProfile2();
address2.set_use_count(3U);
personal_data_manager.AddTestingProfile(&address2);
web::PaymentRequest web_payment_request;
web_payment_request.details = CreateDetailsWithShippingOption();
web_payment_request.options = CreatePaymentOptions(
/*request_payer_name=*/true, /*request_payer_phone=*/true,
/*request_payer_email=*/true, /*request_shipping=*/true);
// Even though address1 has more use counts, address2 is selected because it
// is complete.
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
EXPECT_EQ(address2.guid(),
payment_request.selected_shipping_profile()->guid());
EXPECT_EQ(address2.guid(),
payment_request.selected_contact_profile()->guid());
}
// Test that loading incomplete contact profiles works as expected when the
// merchant is not interested in the missing field. Test that the most complete
// shipping profile is selected.
TEST_F(PaymentRequestTest,
SelectedProfiles_IncompleteContact_NoRequestPayerPhone) {
autofill::TestPersonalDataManager personal_data_manager;
// Add a profile with no phone (incomplete).
autofill::AutofillProfile address1 = autofill::test::GetFullProfile();
address1.SetInfo(autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
base::string16(), "en-US");
address1.set_use_count(5U);
personal_data_manager.AddTestingProfile(&address1);
// Add a complete profile, with fewer use counts.
autofill::AutofillProfile address2 = autofill::test::GetFullProfile();
address2.set_use_count(3U);
personal_data_manager.AddTestingProfile(&address2);
web::PaymentRequest web_payment_request;
web_payment_request.details = CreateDetailsWithShippingOption();
// The merchant doesn't care about the phone number.
web_payment_request.options = CreatePaymentOptions(
/*request_payer_name=*/true, /*request_payer_phone=*/false,
/*request_payer_email=*/true, /*request_shipping=*/true);
// address1 has more use counts, and even though it has no phone number, it's
// still selected as the contact profile because merchant doesn't require
// phone. address2 is selected as the shipping profile because it's the most
// complete for shipping.
PaymentRequest payment_request(web_payment_request, &personal_data_manager);
EXPECT_EQ(address2.guid(),
payment_request.selected_shipping_profile()->guid());
EXPECT_EQ(address1.guid(),
payment_request.selected_contact_profile()->guid());
}