| // 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/service_worker_payment_app.h" |
| |
| #include <memory> |
| |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "content/public/browser/stored_payment_app.h" |
| #include "content/public/common/content_features.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "content/public/test/test_browser_context.h" |
| #include "content/public/test/test_web_contents_factory.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/mojom/payments/payment_request.mojom.h" |
| |
| namespace payments { |
| |
| class ServiceWorkerPaymentAppTest : public testing::Test, |
| public PaymentRequestSpec::Observer { |
| public: |
| ServiceWorkerPaymentAppTest() { |
| web_contents_ = |
| test_web_contents_factory_.CreateWebContents(&browser_context_); |
| } |
| |
| ServiceWorkerPaymentAppTest(const ServiceWorkerPaymentAppTest&) = delete; |
| ServiceWorkerPaymentAppTest& operator=(const ServiceWorkerPaymentAppTest&) = |
| delete; |
| |
| ~ServiceWorkerPaymentAppTest() override = default; |
| |
| protected: |
| const SkBitmap* icon_bitmap() const { return icon_bitmap_; } |
| |
| void OnSpecUpdated() override {} |
| |
| void SetUp() override { |
| mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New(); |
| mojom::PaymentItemPtr total = mojom::PaymentItem::New(); |
| mojom::PaymentCurrencyAmountPtr amount = |
| mojom::PaymentCurrencyAmount::New(); |
| amount->value = "5.00"; |
| amount->currency = "USD"; |
| total->amount = std::move(amount); |
| details->total = std::move(total); |
| details->id = absl::optional<std::string>("123456"); |
| details->modifiers = std::vector<mojom::PaymentDetailsModifierPtr>(); |
| |
| mojom::PaymentDetailsModifierPtr modifier_1 = |
| mojom::PaymentDetailsModifier::New(); |
| modifier_1->total = mojom::PaymentItem::New(); |
| modifier_1->total->amount = mojom::PaymentCurrencyAmount::New(); |
| modifier_1->total->amount->currency = "USD"; |
| modifier_1->total->amount->value = "4.00"; |
| modifier_1->method_data = mojom::PaymentMethodData::New(); |
| modifier_1->method_data->supported_method = "basic-card"; |
| details->modifiers->push_back(std::move(modifier_1)); |
| |
| mojom::PaymentDetailsModifierPtr modifier_2 = |
| mojom::PaymentDetailsModifier::New(); |
| modifier_2->total = mojom::PaymentItem::New(); |
| modifier_2->total->amount = mojom::PaymentCurrencyAmount::New(); |
| modifier_2->total->amount->currency = "USD"; |
| modifier_2->total->amount->value = "3.00"; |
| modifier_2->method_data = mojom::PaymentMethodData::New(); |
| modifier_2->method_data->supported_method = "https://bobpay.com"; |
| details->modifiers->push_back(std::move(modifier_2)); |
| |
| mojom::PaymentDetailsModifierPtr modifier_3 = |
| mojom::PaymentDetailsModifier::New(); |
| modifier_3->total = mojom::PaymentItem::New(); |
| modifier_3->total->amount = mojom::PaymentCurrencyAmount::New(); |
| modifier_3->total->amount->currency = "USD"; |
| modifier_3->total->amount->value = "2.00"; |
| modifier_3->method_data = mojom::PaymentMethodData::New(); |
| modifier_3->method_data->supported_method = "https://alicepay.com"; |
| details->modifiers->push_back(std::move(modifier_3)); |
| |
| std::vector<mojom::PaymentMethodDataPtr> method_data; |
| mojom::PaymentMethodDataPtr entry_1 = mojom::PaymentMethodData::New(); |
| entry_1->supported_method = "basic-card"; |
| entry_1->supported_networks.push_back(mojom::BasicCardNetwork::UNIONPAY); |
| entry_1->supported_networks.push_back(mojom::BasicCardNetwork::JCB); |
| entry_1->supported_networks.push_back(mojom::BasicCardNetwork::VISA); |
| method_data.push_back(std::move(entry_1)); |
| |
| mojom::PaymentMethodDataPtr entry_2 = mojom::PaymentMethodData::New(); |
| entry_2->supported_method = "https://bobpay.com"; |
| method_data.push_back(std::move(entry_2)); |
| |
| spec_ = std::make_unique<PaymentRequestSpec>( |
| mojom::PaymentOptions::New(), std::move(details), |
| std::move(method_data), weak_ptr_factory_.GetWeakPtr(), "en-US"); |
| } |
| |
| void TearDown() override {} |
| |
| void CreateServiceWorkerPaymentApp(bool with_url_method) { |
| constexpr int kBitmapDimension = 16; |
| |
| std::unique_ptr<content::StoredPaymentApp> stored_app = |
| std::make_unique<content::StoredPaymentApp>(); |
| stored_app->registration_id = 123456; |
| stored_app->scope = GURL("https://bobpay.com"); |
| stored_app->name = "bobpay"; |
| stored_app->icon = std::make_unique<SkBitmap>(); |
| stored_app->icon->allocN32Pixels(kBitmapDimension, kBitmapDimension); |
| stored_app->icon->eraseColor(SK_ColorRED); |
| stored_app->enabled_methods.emplace_back("basic-card"); |
| if (with_url_method) |
| stored_app->enabled_methods.emplace_back("https://bobpay.com"); |
| stored_app->capabilities.emplace_back(content::StoredCapabilities()); |
| stored_app->capabilities.back().supported_card_networks.emplace_back( |
| static_cast<int32_t>(mojom::BasicCardNetwork::UNIONPAY)); |
| stored_app->capabilities.back().supported_card_networks.emplace_back( |
| static_cast<int32_t>(mojom::BasicCardNetwork::JCB)); |
| stored_app->user_hint = "Visa 4012 ... 1881"; |
| stored_app->prefer_related_applications = false; |
| |
| icon_bitmap_ = stored_app->icon.get(); |
| app_ = std::make_unique<ServiceWorkerPaymentApp>( |
| web_contents_, GURL("https://testmerchant.com"), |
| GURL("https://testmerchant.com/bobpay"), spec_->AsWeakPtr(), |
| std::move(stored_app), /*is_incognito=*/false, |
| /*show_processing_spinner=*/base::DoNothing()); |
| } |
| |
| ServiceWorkerPaymentApp* GetApp() { return app_.get(); } |
| |
| mojom::PaymentRequestEventDataPtr CreatePaymentRequestEventData() { |
| return app_->CreatePaymentRequestEventData(); |
| } |
| |
| mojom::CanMakePaymentEventDataPtr CreateCanMakePaymentEventData() { |
| return app_->CreateCanMakePaymentEventData(); |
| } |
| |
| private: |
| content::BrowserTaskEnvironment task_environment_; |
| content::TestBrowserContext browser_context_; |
| content::TestWebContentsFactory test_web_contents_factory_; |
| raw_ptr<content::WebContents> web_contents_; |
| |
| std::unique_ptr<PaymentRequestSpec> spec_; |
| std::unique_ptr<ServiceWorkerPaymentApp> app_; |
| raw_ptr<const SkBitmap> icon_bitmap_; |
| base::WeakPtrFactory<ServiceWorkerPaymentAppTest> weak_ptr_factory_{this}; |
| }; |
| |
| // Test app info and status are correct. |
| TEST_F(ServiceWorkerPaymentAppTest, AppInfo) { |
| CreateServiceWorkerPaymentApp(true); |
| |
| EXPECT_TRUE(GetApp()->IsCompleteForPayment()); |
| |
| EXPECT_EQ(base::UTF16ToUTF8(GetApp()->GetLabel()), "bobpay"); |
| EXPECT_EQ(base::UTF16ToUTF8(GetApp()->GetSublabel()), "bobpay.com"); |
| |
| ASSERT_NE(nullptr, GetApp()->icon_bitmap()); |
| EXPECT_EQ(GetApp()->icon_bitmap()->width(), icon_bitmap()->width()); |
| EXPECT_EQ(GetApp()->icon_bitmap()->height(), icon_bitmap()->height()); |
| } |
| |
| // Test payment request event data can be correctly constructed for invoking |
| // InvokePaymentApp. |
| TEST_F(ServiceWorkerPaymentAppTest, CreatePaymentRequestEventData) { |
| CreateServiceWorkerPaymentApp(true); |
| |
| mojom::PaymentRequestEventDataPtr event_data = |
| CreatePaymentRequestEventData(); |
| |
| EXPECT_EQ(event_data->top_origin.spec(), "https://testmerchant.com/"); |
| EXPECT_EQ(event_data->payment_request_origin.spec(), |
| "https://testmerchant.com/bobpay"); |
| |
| EXPECT_EQ(event_data->method_data.size(), 2U); |
| EXPECT_EQ(event_data->method_data[0]->supported_method, "basic-card"); |
| EXPECT_EQ(event_data->method_data[0]->supported_networks.size(), 3U); |
| EXPECT_EQ(event_data->method_data[1]->supported_method, "https://bobpay.com"); |
| |
| EXPECT_EQ(event_data->total->currency, "USD"); |
| EXPECT_EQ(event_data->total->value, "5.00"); |
| EXPECT_EQ(event_data->payment_request_id, "123456"); |
| |
| EXPECT_EQ(event_data->modifiers.size(), 2U); |
| EXPECT_EQ(event_data->modifiers[0]->total->amount->value, "4.00"); |
| EXPECT_EQ(event_data->modifiers[0]->total->amount->currency, "USD"); |
| EXPECT_EQ(event_data->modifiers[0]->method_data->supported_method, |
| "basic-card"); |
| EXPECT_EQ(event_data->modifiers[1]->total->amount->value, "3.00"); |
| EXPECT_EQ(event_data->modifiers[1]->total->amount->currency, "USD"); |
| EXPECT_EQ(event_data->modifiers[1]->method_data->supported_method, |
| "https://bobpay.com"); |
| } |
| |
| // Test CanMakePaymentEventData can be correctly constructed for invoking |
| // Validate. |
| TEST_F(ServiceWorkerPaymentAppTest, CreateCanMakePaymentEvent) { |
| CreateServiceWorkerPaymentApp(false); |
| mojom::CanMakePaymentEventDataPtr event_data = |
| CreateCanMakePaymentEventData(); |
| EXPECT_TRUE(event_data.is_null()); |
| |
| CreateServiceWorkerPaymentApp(true); |
| event_data = CreateCanMakePaymentEventData(); |
| EXPECT_FALSE(event_data.is_null()); |
| |
| EXPECT_EQ(event_data->top_origin.spec(), "https://testmerchant.com/"); |
| EXPECT_EQ(event_data->payment_request_origin.spec(), |
| "https://testmerchant.com/bobpay"); |
| |
| EXPECT_EQ(event_data->method_data.size(), 1U); |
| EXPECT_EQ(event_data->method_data[0]->supported_method, "https://bobpay.com"); |
| |
| EXPECT_EQ(event_data->modifiers.size(), 1U); |
| EXPECT_EQ(event_data->modifiers[0]->total->amount->value, "3.00"); |
| EXPECT_EQ(event_data->modifiers[0]->total->amount->currency, "USD"); |
| EXPECT_EQ(event_data->modifiers[0]->method_data->supported_method, |
| "https://bobpay.com"); |
| } |
| |
| // Test the case when CanMakePaymentEvent cannot be fired. The app should be |
| // considered valid, but not ready for payment. |
| TEST_F(ServiceWorkerPaymentAppTest, ValidateCanMakePayment) { |
| // CanMakePaymentEvent is not fired because this test app does not have any |
| // explicitly verified methods. |
| CreateServiceWorkerPaymentApp(/*with_url_method=*/true); |
| GetApp()->ValidateCanMakePayment(base::BindOnce( |
| [](ServiceWorkerPaymentApp*, bool result) { EXPECT_TRUE(result); })); |
| EXPECT_FALSE(GetApp()->HasEnrolledInstrument()); |
| } |
| |
| class ServiceWorkerPaymentAppBasicCardDisabledTest |
| : public ServiceWorkerPaymentAppTest { |
| public: |
| ServiceWorkerPaymentAppBasicCardDisabledTest( |
| const ServiceWorkerPaymentAppBasicCardDisabledTest&) = delete; |
| ServiceWorkerPaymentAppBasicCardDisabledTest& operator=( |
| const ServiceWorkerPaymentAppBasicCardDisabledTest&) = delete; |
| |
| protected: |
| ServiceWorkerPaymentAppBasicCardDisabledTest() { |
| feature_list_.InitAndDisableFeature(::features::kPaymentRequestBasicCard); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| // Test modifiers can be matched based on capabilities. |
| TEST_F(ServiceWorkerPaymentAppBasicCardDisabledTest, IsValidForModifier) { |
| CreateServiceWorkerPaymentApp(true); |
| |
| EXPECT_FALSE(GetApp()->IsValidForModifier( |
| /*method=*/"basic-card", /*supported_networks_specified=*/false, |
| /*supported_networks=*/{})); |
| |
| EXPECT_TRUE(GetApp()->IsValidForModifier( |
| /*method=*/"https://bobpay.com", /*supported_networks_specified=*/true, |
| /*supported_networks=*/{})); |
| |
| EXPECT_FALSE(GetApp()->IsValidForModifier( |
| /*method=*/"basic-card", /*supported_networks_specified=*/true, |
| /*supported_networks=*/{"mastercard"})); |
| |
| EXPECT_FALSE(GetApp()->IsValidForModifier( |
| /*method=*/"basic-card", /*supported_networks_specified=*/true, |
| /*supported_networks=*/{"unionpay"})); |
| } |
| |
| class ServiceWorkerPaymentAppBasicCardEnabledTest |
| : public ServiceWorkerPaymentAppTest { |
| public: |
| ServiceWorkerPaymentAppBasicCardEnabledTest( |
| const ServiceWorkerPaymentAppBasicCardEnabledTest&) = delete; |
| ServiceWorkerPaymentAppBasicCardEnabledTest& operator=( |
| const ServiceWorkerPaymentAppBasicCardEnabledTest&) = delete; |
| |
| protected: |
| ServiceWorkerPaymentAppBasicCardEnabledTest() { |
| feature_list_.InitAndEnableFeature(::features::kPaymentRequestBasicCard); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| // Test modifiers can be matched based on capabilities. |
| TEST_F(ServiceWorkerPaymentAppBasicCardEnabledTest, IsValidForModifier) { |
| CreateServiceWorkerPaymentApp(true); |
| |
| EXPECT_TRUE(GetApp()->IsValidForModifier( |
| /*method=*/"basic-card", /*supported_networks_specified=*/false, |
| /*supported_networks=*/{})); |
| |
| EXPECT_TRUE(GetApp()->IsValidForModifier( |
| /*method=*/"https://bobpay.com", /*supported_networks_specified=*/true, |
| /*supported_networks=*/{})); |
| |
| EXPECT_FALSE(GetApp()->IsValidForModifier( |
| /*method=*/"basic-card", /*supported_networks_specified=*/true, |
| /*supported_networks=*/{"mastercard"})); |
| |
| EXPECT_TRUE(GetApp()->IsValidForModifier( |
| /*method=*/"basic-card", /*supported_networks_specified=*/true, |
| /*supported_networks=*/{"unionpay"})); |
| } |
| |
| } // namespace payments |