| // 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 "components/payments/content/autofill_payment_app.h" |
| |
| #include <memory> |
| #include <string> |
| |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/task/single_thread_task_executor.h" |
| #include "components/autofill/core/browser/address_normalizer.h" |
| #include "components/autofill/core/browser/autofill_test_utils.h" |
| #include "components/autofill/core/browser/data_model/autofill_profile.h" |
| #include "components/autofill/core/browser/data_model/credit_card.h" |
| #include "components/autofill/core/browser/payments/full_card_request.h" |
| #include "components/autofill/core/browser/payments/payments_client.h" |
| #include "components/autofill/core/browser/personal_data_manager.h" |
| #include "components/autofill/core/browser/test_address_normalizer.h" |
| #include "components/autofill/core/browser/test_autofill_client.h" |
| #include "components/autofill/core/browser/test_personal_data_manager.h" |
| #include "components/payments/core/test_payment_request_delegate.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "services/network/public/cpp/shared_url_loader_factory.h" |
| #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" |
| #include "services/network/test/test_url_loader_factory.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| namespace payments { |
| |
| namespace { |
| |
| class FakePaymentAppDelegate : public PaymentApp::Delegate { |
| public: |
| FakePaymentAppDelegate() {} |
| |
| void OnInstrumentDetailsReady(const std::string& method_name, |
| const std::string& stringified_details, |
| const PayerData& payer_data) override { |
| on_instrument_details_ready_called_ = true; |
| } |
| |
| void OnInstrumentDetailsError(const std::string& error_message) override { |
| on_instrument_details_error_called_ = true; |
| } |
| |
| base::WeakPtr<FakePaymentAppDelegate> AsWeakPtr() { |
| return weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| bool WasOnInstrumentDetailsReadyCalled() { |
| return on_instrument_details_ready_called_; |
| } |
| |
| bool WasOnInstrumentDetailsErrorCalled() { |
| return on_instrument_details_error_called_; |
| } |
| |
| private: |
| bool on_instrument_details_ready_called_ = false; |
| bool on_instrument_details_error_called_ = false; |
| |
| base::WeakPtrFactory<FakePaymentAppDelegate> weak_ptr_factory_{this}; |
| }; |
| |
| class FakePaymentRequestDelegate : public PaymentRequestDelegate { |
| public: |
| FakePaymentRequestDelegate() |
| : locale_("en-US"), |
| last_committed_url_("https://shop.com"), |
| personal_data_("en-US"), |
| test_shared_loader_factory_( |
| base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( |
| &test_url_loader_factory_)), |
| payments_client_(test_shared_loader_factory_, |
| /*identity_manager=*/nullptr, |
| /*account_info_getter=*/nullptr), |
| full_card_request_(&autofill_client_, |
| &payments_client_, |
| &personal_data_) {} |
| |
| FakePaymentRequestDelegate(const FakePaymentRequestDelegate&) = delete; |
| FakePaymentRequestDelegate& operator=(const FakePaymentRequestDelegate&) = |
| delete; |
| |
| void ShowDialog(base::WeakPtr<PaymentRequest> request) override {} |
| |
| void CloseDialog() override {} |
| |
| void ShowErrorMessage() override {} |
| |
| autofill::PersonalDataManager* GetPersonalDataManager() override { |
| return nullptr; |
| } |
| |
| const std::string& GetApplicationLocale() const override { return locale_; } |
| |
| bool IsOffTheRecord() const override { return false; } |
| |
| const GURL& GetLastCommittedURL() const override { |
| return last_committed_url_; |
| } |
| |
| void DoFullCardRequest( |
| const autofill::CreditCard& credit_card, |
| base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate> |
| result_delegate) override { |
| full_card_request_card_ = credit_card; |
| full_card_result_delegate_ = result_delegate; |
| } |
| |
| autofill::AddressNormalizer* GetAddressNormalizer() override { |
| return &address_normalizer_; |
| } |
| |
| void CompleteFullCardRequest() { |
| full_card_result_delegate_->OnFullCardRequestSucceeded( |
| full_card_request_, full_card_request_card_, u"123"); |
| } |
| |
| autofill::RegionDataLoader* GetRegionDataLoader() override { return nullptr; } |
| |
| ukm::UkmRecorder* GetUkmRecorder() override { return nullptr; } |
| |
| private: |
| std::string locale_; |
| const GURL last_committed_url_; |
| autofill::TestAddressNormalizer address_normalizer_; |
| autofill::PersonalDataManager personal_data_; |
| network::TestURLLoaderFactory test_url_loader_factory_; |
| scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; |
| autofill::TestAutofillClient autofill_client_; |
| autofill::payments::PaymentsClient payments_client_; |
| autofill::payments::FullCardRequest full_card_request_; |
| autofill::CreditCard full_card_request_card_; |
| base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate> |
| full_card_result_delegate_; |
| }; |
| |
| } // namespace |
| |
| class AutofillPaymentAppTest : public testing::Test { |
| protected: |
| AutofillPaymentAppTest() |
| : address_(autofill::test::GetFullProfile()), |
| local_card_(autofill::test::GetCreditCard()), |
| billing_profiles_({&address_}) { |
| local_card_.set_billing_address_id(address_.guid()); |
| } |
| |
| AutofillPaymentAppTest(const AutofillPaymentAppTest&) = delete; |
| AutofillPaymentAppTest& operator=(const AutofillPaymentAppTest&) = delete; |
| |
| autofill::CreditCard& local_credit_card() { return local_card_; } |
| std::vector<autofill::AutofillProfile*>& billing_profiles() { |
| return billing_profiles_; |
| } |
| |
| private: |
| autofill::AutofillProfile address_; |
| autofill::CreditCard local_card_; |
| std::vector<autofill::AutofillProfile*> billing_profiles_; |
| }; |
| |
| // A valid local credit card is a valid app for payment. |
| TEST_F(AutofillPaymentAppTest, IsCompleteForPayment) { |
| AutofillPaymentApp app("visa", local_credit_card(), billing_profiles(), |
| "en-US", nullptr); |
| EXPECT_TRUE(app.IsCompleteForPayment()); |
| EXPECT_TRUE(app.GetMissingInfoLabel().empty()); |
| } |
| |
| // An expired local card is still a valid app for payment. |
| TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_Expired) { |
| autofill::CreditCard& card = local_credit_card(); |
| card.SetExpirationYear(2016); // Expired. |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr); |
| EXPECT_TRUE(app.IsCompleteForPayment()); |
| EXPECT_EQ(std::u16string(), app.GetMissingInfoLabel()); |
| } |
| |
| // A local card with no name is not a valid app for payment. |
| TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_NoName) { |
| autofill::CreditCard& card = local_credit_card(); |
| card.SetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL), u"", |
| "en-US"); |
| std::u16string missing_info; |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr); |
| EXPECT_FALSE(app.IsCompleteForPayment()); |
| EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_NAME_ON_CARD_REQUIRED), |
| app.GetMissingInfoLabel()); |
| } |
| |
| // A local card with no name is not a valid app for payment. |
| TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_NoNumber) { |
| autofill::CreditCard& card = local_credit_card(); |
| card.SetNumber(u""); |
| std::u16string missing_info; |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr); |
| EXPECT_FALSE(app.IsCompleteForPayment()); |
| EXPECT_EQ(l10n_util::GetStringUTF16( |
| IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE), |
| app.GetMissingInfoLabel()); |
| } |
| |
| // A local card with no billing address id is not a valid app for |
| // payment. |
| TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_NoBillinbAddressId) { |
| autofill::CreditCard& card = local_credit_card(); |
| card.set_billing_address_id(""); |
| std::u16string missing_info; |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr); |
| EXPECT_FALSE(app.IsCompleteForPayment()); |
| EXPECT_EQ( |
| l10n_util::GetStringUTF16(IDS_PAYMENTS_CARD_BILLING_ADDRESS_REQUIRED), |
| app.GetMissingInfoLabel()); |
| } |
| |
| // A local card with an invalid billing address id is not a valid app for |
| // payment. |
| TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_InvalidBillinbAddressId) { |
| autofill::CreditCard& card = local_credit_card(); |
| card.set_billing_address_id("InvalidBillingAddressId"); |
| std::u16string missing_info; |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr); |
| EXPECT_FALSE(app.IsCompleteForPayment()); |
| EXPECT_EQ( |
| l10n_util::GetStringUTF16(IDS_PAYMENTS_CARD_BILLING_ADDRESS_REQUIRED), |
| app.GetMissingInfoLabel()); |
| } |
| |
| // A local card with an incomplete billing address is not a complete app |
| // for payment. |
| TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_IncompleteBillinbAddress) { |
| autofill::AutofillProfile incomplete_profile = |
| autofill::test::GetIncompleteProfile2(); |
| billing_profiles()[0] = &incomplete_profile; |
| autofill::CreditCard& card = local_credit_card(); |
| card.set_billing_address_id(incomplete_profile.guid()); |
| std::u16string missing_info; |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr); |
| EXPECT_FALSE(app.IsCompleteForPayment()); |
| EXPECT_EQ( |
| l10n_util::GetStringUTF16(IDS_PAYMENTS_CARD_BILLING_ADDRESS_REQUIRED), |
| app.GetMissingInfoLabel()); |
| } |
| |
| // A local card with no name and no number is not a valid app for |
| // payment. |
| TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_MultipleThingsMissing) { |
| autofill::CreditCard& card = local_credit_card(); |
| card.SetNumber(u""); |
| card.SetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL), u"", |
| "en-US"); |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr); |
| EXPECT_FALSE(app.IsCompleteForPayment()); |
| EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_MORE_INFORMATION_REQUIRED), |
| app.GetMissingInfoLabel()); |
| } |
| |
| // A Masked (server) card is a valid app for payment. |
| TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_MaskedCard) { |
| autofill::CreditCard card = autofill::test::GetMaskedServerCard(); |
| ASSERT_GT(billing_profiles().size(), 0UL); |
| card.set_billing_address_id(billing_profiles()[0]->guid()); |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr); |
| EXPECT_TRUE(app.IsCompleteForPayment()); |
| EXPECT_TRUE(app.GetMissingInfoLabel().empty()); |
| } |
| |
| // An expired masked (server) card is still a valid app for payment. |
| TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_ExpiredMaskedCard) { |
| autofill::CreditCard card = autofill::test::GetMaskedServerCard(); |
| ASSERT_GT(billing_profiles().size(), 0UL); |
| card.set_billing_address_id(billing_profiles()[0]->guid()); |
| card.SetExpirationYear(2016); // Expired. |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr); |
| EXPECT_TRUE(app.IsCompleteForPayment()); |
| EXPECT_EQ(std::u16string(), app.GetMissingInfoLabel()); |
| } |
| |
| // An expired card is a valid app for canMakePayment. |
| TEST_F(AutofillPaymentAppTest, HasEnrolledInstrument_Minimal) { |
| autofill::CreditCard& card = local_credit_card(); |
| card.SetExpirationYear(2016); // Expired. |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr); |
| EXPECT_TRUE(app.HasEnrolledInstrument()); |
| } |
| |
| // An expired Masked (server) card is a valid app for canMakePayment. |
| TEST_F(AutofillPaymentAppTest, HasEnrolledInstrument_MaskedCard) { |
| autofill::CreditCard card = autofill::test::GetMaskedServerCard(); |
| card.SetExpirationYear(2016); // Expired. |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr); |
| EXPECT_TRUE(app.HasEnrolledInstrument()); |
| } |
| |
| // A card with no name is not a valid app for canMakePayment. |
| TEST_F(AutofillPaymentAppTest, HasEnrolledInstrument_NoName) { |
| autofill::CreditCard& card = local_credit_card(); |
| card.SetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL), u"", |
| "en-US"); |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr); |
| EXPECT_FALSE(app.HasEnrolledInstrument()); |
| } |
| |
| // A card with no number is not a valid app for canMakePayment. |
| TEST_F(AutofillPaymentAppTest, HasEnrolledInstrument_NoNumber) { |
| autofill::CreditCard& card = local_credit_card(); |
| card.SetNumber(u""); |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr); |
| EXPECT_FALSE(app.HasEnrolledInstrument()); |
| } |
| |
| // Tests that the autofill app only calls OnappDetailsReady when |
| // the billing address has been normalized and the card has been unmasked. |
| TEST_F(AutofillPaymentAppTest, InvokePaymentApp_NormalizationBeforeUnmask) { |
| auto personal_data_manager = |
| std::make_unique<autofill::TestPersonalDataManager>(); |
| TestPaymentRequestDelegate delegate( |
| std::make_unique<base::SingleThreadTaskExecutor>(), |
| personal_data_manager.get()); |
| delegate.DelayFullCardRequestCompletion(); |
| delegate.test_address_normalizer()->DelayNormalization(); |
| |
| autofill::CreditCard& card = local_credit_card(); |
| card.SetNumber(u""); |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", |
| delegate.GetWeakPtr()); |
| |
| FakePaymentAppDelegate app_delegate; |
| |
| app.InvokePaymentApp(app_delegate.AsWeakPtr()); |
| EXPECT_FALSE(app_delegate.WasOnInstrumentDetailsReadyCalled()); |
| EXPECT_FALSE(app_delegate.WasOnInstrumentDetailsErrorCalled()); |
| |
| delegate.test_address_normalizer()->CompleteAddressNormalization(); |
| EXPECT_FALSE(app_delegate.WasOnInstrumentDetailsReadyCalled()); |
| EXPECT_FALSE(app_delegate.WasOnInstrumentDetailsErrorCalled()); |
| |
| delegate.CompleteFullCardRequest(); |
| EXPECT_TRUE(app_delegate.WasOnInstrumentDetailsReadyCalled()); |
| EXPECT_FALSE(app_delegate.WasOnInstrumentDetailsErrorCalled()); |
| } |
| |
| // Tests that the autofill app only calls OnappDetailsReady when |
| // the billing address has been normalized and the card has been unmasked. |
| TEST_F(AutofillPaymentAppTest, InvokePaymentApp_UnmaskBeforeNormalization) { |
| auto personal_data_manager = |
| std::make_unique<autofill::TestPersonalDataManager>(); |
| TestPaymentRequestDelegate delegate( |
| std::make_unique<base::SingleThreadTaskExecutor>(), |
| personal_data_manager.get()); |
| delegate.DelayFullCardRequestCompletion(); |
| delegate.test_address_normalizer()->DelayNormalization(); |
| |
| autofill::CreditCard& card = local_credit_card(); |
| card.SetNumber(u""); |
| AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", |
| delegate.GetWeakPtr()); |
| |
| FakePaymentAppDelegate app_delegate; |
| |
| app.InvokePaymentApp(app_delegate.AsWeakPtr()); |
| EXPECT_FALSE(app_delegate.WasOnInstrumentDetailsReadyCalled()); |
| EXPECT_FALSE(app_delegate.WasOnInstrumentDetailsErrorCalled()); |
| |
| delegate.CompleteFullCardRequest(); |
| EXPECT_FALSE(app_delegate.WasOnInstrumentDetailsReadyCalled()); |
| EXPECT_FALSE(app_delegate.WasOnInstrumentDetailsErrorCalled()); |
| |
| delegate.test_address_normalizer()->CompleteAddressNormalization(); |
| EXPECT_TRUE(app_delegate.WasOnInstrumentDetailsReadyCalled()); |
| EXPECT_FALSE(app_delegate.WasOnInstrumentDetailsErrorCalled()); |
| } |
| |
| } // namespace payments |