| // Copyright 2020 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 "third_party/blink/renderer/modules/payments/payment_request.h" |
| |
| #include "build/build_config.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/mojom/payments/payment_request.mojom-blink.h" |
| #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" |
| #include "third_party/blink/renderer/core/dom/document.h" |
| #include "third_party/blink/renderer/core/event_type_names.h" |
| #include "third_party/blink/renderer/modules/payments/payment_test_helper.h" |
| #include "third_party/blink/renderer/platform/bindings/exception_code.h" |
| #include "third_party/blink/renderer/platform/heap/heap_allocator.h" |
| #include "third_party/blink/renderer/platform/testing/testing_platform_support.h" |
| |
| namespace blink { |
| namespace { |
| |
| class MockPaymentProvider : public payments::mojom::blink::PaymentRequest { |
| public: |
| // mojom::PaymentRequest |
| #if defined(OS_ANDROID) |
| void Init( |
| mojo::PendingRemote<payments::mojom::blink::PaymentRequestClient> client, |
| WTF::Vector<payments::mojom::blink::PaymentMethodDataPtr> method_data, |
| payments::mojom::blink::PaymentDetailsPtr details, |
| payments::mojom::blink::PaymentOptionsPtr options, |
| bool google_pay_bridge_eligible) override { |
| details_ = std::move(details); |
| } |
| #else |
| void Init( |
| mojo::PendingRemote<payments::mojom::blink::PaymentRequestClient> client, |
| WTF::Vector<payments::mojom::blink::PaymentMethodDataPtr> method_data, |
| payments::mojom::blink::PaymentDetailsPtr details, |
| payments::mojom::blink::PaymentOptionsPtr options) override { |
| details_ = std::move(details); |
| } |
| #endif |
| |
| void Show(bool is_user_gesture, bool wait_for_updated_details) override { |
| NOTREACHED(); |
| } |
| void Retry( |
| payments::mojom::blink::PaymentValidationErrorsPtr errors) override { |
| NOTREACHED(); |
| } |
| void UpdateWith( |
| payments::mojom::blink::PaymentDetailsPtr update_with_details) override { |
| NOTREACHED(); |
| } |
| void OnPaymentDetailsNotUpdated() override { NOTREACHED(); } |
| void Abort() override { NOTREACHED(); } |
| void Complete(payments::mojom::PaymentComplete result) override { |
| NOTREACHED(); |
| } |
| void CanMakePayment() override { NOTREACHED(); } |
| void HasEnrolledInstrument() override { NOTREACHED(); } |
| |
| mojo::PendingRemote<payments::mojom::blink::PaymentRequest> |
| CreatePendingRemoteAndBind() { |
| mojo::PendingRemote<payments::mojom::blink::PaymentRequest> remote; |
| receiver_.Bind(remote.InitWithNewPipeAndPassReceiver()); |
| return remote; |
| } |
| |
| payments::mojom::blink::PaymentDetailsPtr& GetDetails() { return details_; } |
| |
| private: |
| mojo::Receiver<payments::mojom::blink::PaymentRequest> receiver_{this}; |
| payments::mojom::blink::PaymentDetailsPtr details_; |
| }; |
| |
| // This test suite is about the optional total parameter of the PaymentRequest |
| // constructor. |
| class PaymentRequestOptionalTotalTest : public testing::Test { |
| public: |
| void SetUp() override { |
| payment_provider_ = std::make_unique<MockPaymentProvider>(); |
| } |
| |
| std::unique_ptr<MockPaymentProvider> payment_provider_; |
| ScopedTestingPlatformSupport<TestingPlatformSupport> platform_; |
| }; |
| |
| // This test requests a mix of app-store billing methods and normal payment |
| // methods. Total is required in this scenario. |
| TEST_F(PaymentRequestOptionalTotalTest, |
| AppStoreBillingFlagEnabledTotalIsRequiredWhenMixMethods) { |
| RuntimeEnabledFeatures::SetDigitalGoodsEnabled(true); |
| |
| PaymentRequestV8TestingScope scope; |
| // Intentionally leaves the total of details unset. |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| |
| HeapVector<Member<PaymentMethodData>> method_data(2); |
| method_data[0] = PaymentMethodData::Create(); |
| method_data[0]->setSupportedMethod("foo"); |
| method_data[1] = PaymentMethodData::Create(); |
| method_data[1]->setSupportedMethod("https://play.google.com/billing"); |
| |
| PaymentRequest::Create(scope.GetExecutionContext(), method_data, details, |
| scope.GetExceptionState()); |
| |
| EXPECT_TRUE(scope.GetExceptionState().HadException()); |
| EXPECT_EQ("required member details is undefined.", |
| scope.GetExceptionState().Message()); |
| EXPECT_FALSE(payment_provider_->GetDetails()); |
| } |
| |
| // When the DigitalGoods flag is disabled: although this test requests a |
| // app-store billing methods, total is required. |
| TEST_F(PaymentRequestOptionalTotalTest, |
| AppStoreBillingFlagDisabledTotalIsRequiredWhenMixMethods) { |
| RuntimeEnabledFeatures::SetDigitalGoodsEnabled(false); |
| |
| PaymentRequestV8TestingScope scope; |
| // Intentionally leaves the total of details unset. |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| |
| HeapVector<Member<PaymentMethodData>> method_data(1); |
| method_data[0] = PaymentMethodData::Create(); |
| method_data[0]->setSupportedMethod("https://play.google.com/billing"); |
| |
| PaymentRequest::Create(scope.GetExecutionContext(), method_data, details, |
| scope.GetExceptionState()); |
| |
| EXPECT_TRUE(scope.GetExceptionState().HadException()); |
| EXPECT_EQ("required member details is undefined.", |
| scope.GetExceptionState().Message()); |
| EXPECT_FALSE(payment_provider_->GetDetails()); |
| } |
| |
| // When the DigitalGoods flag is enabled: undefined total gets a place holder |
| // when only requesting app-store billing methods. |
| TEST_F(PaymentRequestOptionalTotalTest, |
| AppStoreBillingFlagEnabledTotalGetPlaceHolder) { |
| RuntimeEnabledFeatures::SetDigitalGoodsEnabled(true); |
| |
| PaymentRequestV8TestingScope scope; |
| // Intentionally leaves the total of details unset. |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| |
| HeapVector<Member<PaymentMethodData>> method_data( |
| 1, PaymentMethodData::Create()); |
| method_data[0]->setSupportedMethod("https://play.google.com/billing"); |
| |
| MakeGarbageCollected<PaymentRequest>( |
| scope.GetExecutionContext(), method_data, details, |
| PaymentOptions::Create(), payment_provider_->CreatePendingRemoteAndBind(), |
| ASSERT_NO_EXCEPTION); |
| platform_->RunUntilIdle(); |
| EXPECT_FALSE(scope.GetExceptionState().HadException()); |
| EXPECT_EQ("0", payment_provider_->GetDetails()->total->amount->value); |
| EXPECT_EQ("ZZZ", payment_provider_->GetDetails()->total->amount->currency); |
| } |
| |
| // When the DigitalGoods flag is disabled: undefined total is rejected. |
| TEST_F(PaymentRequestOptionalTotalTest, |
| AppStoreBillingFlagDisabledTotalGetRejected) { |
| RuntimeEnabledFeatures::SetDigitalGoodsEnabled(false); |
| |
| PaymentRequestV8TestingScope scope; |
| // Intentionally leaves the total of details unset. |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| |
| HeapVector<Member<PaymentMethodData>> method_data( |
| 1, PaymentMethodData::Create()); |
| method_data[0]->setSupportedMethod("https://play.google.com/billing"); |
| |
| MakeGarbageCollected<PaymentRequest>( |
| scope.GetExecutionContext(), method_data, details, |
| PaymentOptions::Create(), payment_provider_->CreatePendingRemoteAndBind(), |
| scope.GetExceptionState()); |
| platform_->RunUntilIdle(); |
| // Verify that total is required. |
| EXPECT_TRUE(scope.GetExceptionState().HadException()); |
| EXPECT_EQ("required member details is undefined.", |
| scope.GetExceptionState().Message()); |
| EXPECT_FALSE(payment_provider_->GetDetails()); |
| } |
| |
| // When the DigitalGoods flag is enabled: total get overridden when only |
| // requesting app-store billing methods. |
| TEST_F(PaymentRequestOptionalTotalTest, |
| AppStoreBillingFlagEnabledTotalGetOverridden) { |
| RuntimeEnabledFeatures::SetDigitalGoodsEnabled(true); |
| |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| // Set a non-empty total. |
| details->setTotal((BuildPaymentItemForTest())); |
| |
| HeapVector<Member<PaymentMethodData>> method_data( |
| 1, PaymentMethodData::Create()); |
| method_data[0]->setSupportedMethod("https://play.google.com/billing"); |
| |
| MakeGarbageCollected<PaymentRequest>( |
| scope.GetExecutionContext(), method_data, details, |
| PaymentOptions::Create(), payment_provider_->CreatePendingRemoteAndBind(), |
| ASSERT_NO_EXCEPTION); |
| platform_->RunUntilIdle(); |
| EXPECT_FALSE(scope.GetExceptionState().HadException()); |
| // Verify that the total get overridden. |
| EXPECT_EQ("0", payment_provider_->GetDetails()->total->amount->value); |
| EXPECT_EQ("ZZZ", payment_provider_->GetDetails()->total->amount->currency); |
| } |
| |
| // When the DigitalGoods flag is disabled: total does not get overridden when |
| // only requesting app-store billing methods. |
| TEST_F(PaymentRequestOptionalTotalTest, |
| AppStoreBillingFlagDisabledTotalNotGetOverridden) { |
| RuntimeEnabledFeatures::SetDigitalGoodsEnabled(false); |
| |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| // Set a non-empty total. |
| details->setTotal(BuildPaymentItemForTest()); |
| |
| HeapVector<Member<PaymentMethodData>> method_data( |
| 1, PaymentMethodData::Create()); |
| method_data[0]->setSupportedMethod("https://play.google.com/billing"); |
| |
| MakeGarbageCollected<PaymentRequest>( |
| scope.GetExecutionContext(), method_data, details, |
| PaymentOptions::Create(), payment_provider_->CreatePendingRemoteAndBind(), |
| ASSERT_NO_EXCEPTION); |
| platform_->RunUntilIdle(); |
| // Verify that the total is set. |
| EXPECT_FALSE(scope.GetExceptionState().HadException()); |
| EXPECT_TRUE(payment_provider_->GetDetails()->total); |
| } |
| } // namespace |
| } // namespace blink |