| // Copyright 2016 The Chromium Authors |
| // 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 <memory> |
| |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/mojom/frame/user_activation_notification_type.mojom-blink.h" |
| #include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h" |
| #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.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/dom/events/native_event_listener.h" |
| #include "third_party/blink/renderer/core/event_type_names.h" |
| #include "third_party/blink/renderer/core/execution_context/execution_context.h" |
| #include "third_party/blink/renderer/core/frame/local_frame.h" |
| #include "third_party/blink/renderer/core/testing/dummy_page_holder.h" |
| #include "third_party/blink/renderer/modules/payments/payment_response.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/collection_support/heap_vector.h" |
| #include "third_party/blink/renderer/platform/testing/task_environment.h" |
| |
| namespace blink { |
| namespace { |
| |
| TEST(PaymentRequestTest, NoExceptionWithValidData) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), |
| BuildPaymentDetailsInitForTest(), scope.GetExceptionState()); |
| |
| EXPECT_FALSE(scope.GetExceptionState().HadException()); |
| } |
| |
| TEST(PaymentRequestTest, SupportedMethodListRequired) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentRequest::Create( |
| scope.GetExecutionContext(), HeapVector<Member<PaymentMethodData>>(), |
| BuildPaymentDetailsInitForTest(), scope.GetExceptionState()); |
| |
| EXPECT_TRUE(scope.GetExceptionState().HadException()); |
| EXPECT_EQ(ESErrorType::kTypeError, |
| scope.GetExceptionState().CodeAs<ESErrorType>()); |
| } |
| |
| TEST(PaymentRequestTest, NullShippingOptionWhenNoOptionsAvailable) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(true); |
| |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, |
| options, scope.GetExceptionState()); |
| |
| EXPECT_TRUE(request->shippingOption().IsNull()); |
| } |
| |
| TEST(PaymentRequestTest, NullShippingOptionWhenMultipleOptionsAvailable) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| HeapVector<Member<PaymentShippingOption>> shipping_options; |
| shipping_options.push_back(BuildShippingOptionForTest()); |
| shipping_options.push_back(BuildShippingOptionForTest()); |
| details->setShippingOptions(shipping_options); |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(true); |
| |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, |
| options, scope.GetExceptionState()); |
| |
| EXPECT_TRUE(request->shippingOption().IsNull()); |
| } |
| |
| TEST(PaymentRequestTest, DontSelectSingleAvailableShippingOptionByDefault) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| details->setShippingOptions(HeapVector<Member<PaymentShippingOption>>( |
| 1, BuildShippingOptionForTest(kPaymentTestDataId, |
| kPaymentTestOverwriteValue, "standard"))); |
| |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, |
| scope.GetExceptionState()); |
| |
| EXPECT_TRUE(request->shippingOption().IsNull()); |
| } |
| |
| TEST(PaymentRequestTest, |
| DontSelectSingleAvailableShippingOptionWhenShippingNotRequested) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| details->setShippingOptions(HeapVector<Member<PaymentShippingOption>>( |
| 1, BuildShippingOptionForTest())); |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(false); |
| |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, |
| options, scope.GetExceptionState()); |
| |
| EXPECT_TRUE(request->shippingOption().IsNull()); |
| } |
| |
| TEST(PaymentRequestTest, |
| DontSelectSingleUnselectedShippingOptionWhenShippingRequested) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| details->setShippingOptions(HeapVector<Member<PaymentShippingOption>>( |
| 1, BuildShippingOptionForTest())); |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(true); |
| |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, |
| options, scope.GetExceptionState()); |
| |
| EXPECT_TRUE(request->shippingOption().IsNull()); |
| } |
| |
| TEST(PaymentRequestTest, |
| SelectSingleSelectedShippingOptionWhenShippingRequested) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| HeapVector<Member<PaymentShippingOption>> shipping_options( |
| 1, BuildShippingOptionForTest(kPaymentTestDataId, |
| kPaymentTestOverwriteValue, "standard")); |
| shipping_options[0]->setSelected(true); |
| details->setShippingOptions(shipping_options); |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(true); |
| |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, |
| options, scope.GetExceptionState()); |
| |
| EXPECT_EQ("standard", request->shippingOption()); |
| } |
| |
| TEST(PaymentRequestTest, |
| SelectOnlySelectedShippingOptionWhenShippingRequested) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| HeapVector<Member<PaymentShippingOption>> shipping_options(2); |
| shipping_options[0] = BuildShippingOptionForTest( |
| kPaymentTestDataId, kPaymentTestOverwriteValue, "standard"); |
| shipping_options[0]->setSelected(true); |
| shipping_options[1] = BuildShippingOptionForTest( |
| kPaymentTestDataId, kPaymentTestOverwriteValue, "express"); |
| details->setShippingOptions(shipping_options); |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(true); |
| |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, |
| options, scope.GetExceptionState()); |
| |
| EXPECT_EQ("standard", request->shippingOption()); |
| } |
| |
| TEST(PaymentRequestTest, |
| SelectLastSelectedShippingOptionWhenShippingRequested) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| HeapVector<Member<PaymentShippingOption>> shipping_options(2); |
| shipping_options[0] = BuildShippingOptionForTest( |
| kPaymentTestDataId, kPaymentTestOverwriteValue, "standard"); |
| shipping_options[0]->setSelected(true); |
| shipping_options[1] = BuildShippingOptionForTest( |
| kPaymentTestDataId, kPaymentTestOverwriteValue, "express"); |
| shipping_options[1]->setSelected(true); |
| details->setShippingOptions(shipping_options); |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(true); |
| |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, |
| options, scope.GetExceptionState()); |
| |
| EXPECT_EQ("express", request->shippingOption()); |
| } |
| |
| TEST(PaymentRequestTest, NullShippingTypeWhenRequestShippingIsFalse) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(false); |
| |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, |
| options, scope.GetExceptionState()); |
| |
| EXPECT_FALSE(request->shippingType().has_value()); |
| } |
| |
| TEST(PaymentRequestTest, |
| DefaultShippingTypeWhenRequestShippingIsTrueWithNoSpecificType) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(true); |
| |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, |
| options, scope.GetExceptionState()); |
| |
| EXPECT_EQ(V8PaymentShippingType::Enum::kShipping, request->shippingType()); |
| } |
| |
| TEST(PaymentRequestTest, DeliveryShippingTypeWhenShippingTypeIsDelivery) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(true); |
| options->setShippingType(V8PaymentShippingType::Enum::kDelivery); |
| |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, |
| options, scope.GetExceptionState()); |
| |
| EXPECT_EQ(V8PaymentShippingType::Enum::kDelivery, request->shippingType()); |
| } |
| |
| TEST(PaymentRequestTest, PickupShippingTypeWhenShippingTypeIsPickup) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(true); |
| options->setShippingType(V8PaymentShippingType::Enum::kPickup); |
| |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, |
| options, scope.GetExceptionState()); |
| |
| EXPECT_EQ(V8PaymentShippingType::Enum::kPickup, request->shippingType()); |
| } |
| |
| TEST(PaymentRequestTest, RejectShowPromiseOnInvalidShippingAddress) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| &scope.GetFrame(), mojom::UserActivationNotificationType::kTest); |
| ScriptPromiseTester promise_tester( |
| scope.GetScriptState(), |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION)); |
| |
| static_cast<payments::mojom::blink::PaymentRequestClient*>(request) |
| ->OnShippingAddressChange(payments::mojom::blink::PaymentAddress::New()); |
| scope.PerformMicrotaskCheckpoint(); |
| EXPECT_TRUE(promise_tester.IsRejected()); |
| } |
| |
| TEST(PaymentRequestTest, OnShippingOptionChange) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| &scope.GetFrame(), mojom::UserActivationNotificationType::kTest); |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION); |
| |
| static_cast<payments::mojom::blink::PaymentRequestClient*>(request) |
| ->OnShippingOptionChange("standardShipping"); |
| } |
| |
| TEST(PaymentRequestTest, CannotCallShowTwice) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| LocalFrame::NotifyUserActivation( |
| &scope.GetFrame(), mojom::UserActivationNotificationType::kTest); |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION); |
| |
| // The second show() call will be rejected before user activation is checked, |
| // so there is no need to re-trigger user-activation here. |
| request->show(scope.GetScriptState(), scope.GetExceptionState()); |
| EXPECT_EQ(scope.GetExceptionState().Code(), |
| ToExceptionCode(DOMExceptionCode::kInvalidStateError)); |
| } |
| |
| TEST(PaymentRequestTest, CannotShowAfterAborted) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| &scope.GetFrame(), mojom::UserActivationNotificationType::kTest); |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION); |
| request->abort(scope.GetScriptState(), ASSERT_NO_EXCEPTION); |
| static_cast<payments::mojom::blink::PaymentRequestClient*>(request)->OnAbort( |
| true); |
| |
| // The second show() call will be rejected before user activation is checked, |
| // so there is no need to re-trigger user-activation here. |
| request->show(scope.GetScriptState(), scope.GetExceptionState()); |
| EXPECT_EQ(scope.GetExceptionState().Code(), |
| ToExceptionCode(DOMExceptionCode::kInvalidStateError)); |
| ; |
| } |
| |
| TEST(PaymentRequestTest, ShowConsumesUserActivation) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| &(scope.GetFrame()), mojom::UserActivationNotificationType::kTest); |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION); |
| EXPECT_FALSE(LocalFrame::HasTransientUserActivation(&(scope.GetFrame()))); |
| EXPECT_FALSE(scope.GetDocument().IsUseCounted( |
| WebFeature::kPaymentRequestShowWithoutGestureOrToken)); |
| } |
| |
| TEST(PaymentRequestTest, ActivationlessShow) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| |
| EXPECT_FALSE(LocalFrame::HasTransientUserActivation(&(scope.GetFrame()))); |
| EXPECT_FALSE(scope.GetDocument().IsUseCounted( |
| WebFeature::kPaymentRequestActivationlessShow)); |
| EXPECT_FALSE(scope.GetDocument().IsUseCounted( |
| WebFeature::kPaymentRequestShowWithoutGestureOrToken)); |
| |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION); |
| EXPECT_TRUE(scope.GetDocument().IsUseCounted( |
| WebFeature::kPaymentRequestActivationlessShow)); |
| EXPECT_TRUE(scope.GetDocument().IsUseCounted( |
| WebFeature::kPaymentRequestShowWithoutGestureOrToken)); |
| } |
| |
| TEST(PaymentRequestTest, RejectShowPromiseOnErrorPaymentMethodNotSupported) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| &scope.GetFrame(), mojom::UserActivationNotificationType::kTest); |
| ScriptPromiseTester promise_tester( |
| scope.GetScriptState(), |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION)); |
| |
| static_cast<payments::mojom::blink::PaymentRequestClient*>(request)->OnError( |
| payments::mojom::blink::PaymentErrorReason::NOT_SUPPORTED, |
| "The payment method \"foo\" is not supported"); |
| |
| scope.PerformMicrotaskCheckpoint(); |
| EXPECT_TRUE(promise_tester.IsRejected()); |
| EXPECT_EQ("NotSupportedError: The payment method \"foo\" is not supported", |
| promise_tester.ValueAsString()); |
| } |
| |
| TEST(PaymentRequestTest, RejectShowPromiseOnErrorCancelled) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| &scope.GetFrame(), mojom::UserActivationNotificationType::kTest); |
| ScriptPromiseTester promise_tester( |
| scope.GetScriptState(), |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION)); |
| |
| static_cast<payments::mojom::blink::PaymentRequestClient*>(request)->OnError( |
| payments::mojom::blink::PaymentErrorReason::USER_CANCEL, |
| "Request cancelled"); |
| |
| scope.PerformMicrotaskCheckpoint(); |
| EXPECT_TRUE(promise_tester.IsRejected()); |
| EXPECT_EQ("AbortError: Request cancelled", promise_tester.ValueAsString()); |
| } |
| |
| TEST(PaymentRequestTest, RejectShowPromiseOnUpdateDetailsFailure) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| &scope.GetFrame(), mojom::UserActivationNotificationType::kTest); |
| ScriptPromiseTester promise_tester( |
| scope.GetScriptState(), |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION)); |
| |
| static_cast<payments::mojom::blink::PaymentRequestClient*>(request) |
| ->OnShippingAddressChange(BuildPaymentAddressForTest()); |
| request->OnUpdatePaymentDetailsFailure("oops"); |
| |
| scope.PerformMicrotaskCheckpoint(); |
| EXPECT_TRUE(promise_tester.IsRejected()); |
| EXPECT_EQ("AbortError: oops", promise_tester.ValueAsString()); |
| } |
| |
| TEST(PaymentRequestTest, IgnoreUpdatePaymentDetailsAfterShowPromiseResolved) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| &scope.GetFrame(), mojom::UserActivationNotificationType::kTest); |
| ScriptPromiseTester promise_tester( |
| scope.GetScriptState(), |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION)); |
| static_cast<payments::mojom::blink::PaymentRequestClient*>(request) |
| ->OnPaymentResponse(BuildPaymentResponseForTest()); |
| |
| request->OnUpdatePaymentDetails(nullptr); |
| scope.PerformMicrotaskCheckpoint(); |
| EXPECT_TRUE(promise_tester.IsFulfilled()); |
| } |
| |
| TEST(PaymentRequestTest, |
| ClearShippingOptionOnPaymentDetailsUpdateWithoutShippingOptions) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(true); |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, |
| options, ASSERT_NO_EXCEPTION); |
| EXPECT_TRUE(request->shippingOption().IsNull()); |
| |
| LocalFrame::NotifyUserActivation( |
| &scope.GetFrame(), mojom::UserActivationNotificationType::kTest); |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION); |
| |
| static_cast<payments::mojom::blink::PaymentRequestClient*>(request) |
| ->OnShippingAddressChange(BuildPaymentAddressForTest()); |
| String detail_with_shipping_options = |
| "{\"total\": {\"label\": \"Total\", \"amount\": {\"currency\": \"USD\", " |
| "\"value\": \"5.00\"}}," |
| "\"shippingOptions\": [{\"id\": \"standardShippingOption\", \"label\": " |
| "\"Standard shipping\", \"amount\": {\"currency\": \"USD\", \"value\": " |
| "\"5.00\"}, \"selected\": true}]}"; |
| request->OnUpdatePaymentDetails(PaymentDetailsUpdate::Create( |
| scope.GetIsolate(), |
| FromJSONString(scope.GetScriptState(), detail_with_shipping_options), |
| ASSERT_NO_EXCEPTION)); |
| |
| EXPECT_EQ("standardShippingOption", request->shippingOption()); |
| static_cast<payments::mojom::blink::PaymentRequestClient*>(request) |
| ->OnShippingAddressChange(BuildPaymentAddressForTest()); |
| String detail_without_shipping_options = |
| "{\"total\": {\"label\": \"Total\", \"amount\": {\"currency\": \"USD\", " |
| "\"value\": \"5.00\"}}}"; |
| request->OnUpdatePaymentDetails(PaymentDetailsUpdate::Create( |
| scope.GetIsolate(), |
| FromJSONString(scope.GetScriptState(), detail_without_shipping_options), |
| ASSERT_NO_EXCEPTION)); |
| |
| EXPECT_TRUE(request->shippingOption().IsNull()); |
| } |
| |
| TEST( |
| PaymentRequestTest, |
| ClearShippingOptionOnPaymentDetailsUpdateWithMultipleUnselectedShippingOptions) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(true); |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), |
| BuildPaymentDetailsInitForTest(), options, ASSERT_NO_EXCEPTION); |
| LocalFrame::NotifyUserActivation( |
| &scope.GetFrame(), mojom::UserActivationNotificationType::kTest); |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION); |
| |
| String detail = |
| "{\"total\": {\"label\": \"Total\", \"amount\": {\"currency\": \"USD\", " |
| "\"value\": \"5.00\"}}," |
| "\"shippingOptions\": [{\"id\": \"slow\", \"label\": \"Slow\", " |
| "\"amount\": {\"currency\": \"USD\", \"value\": \"5.00\"}}," |
| "{\"id\": \"fast\", \"label\": \"Fast\", \"amount\": {\"currency\": " |
| "\"USD\", \"value\": \"50.00\"}}]}"; |
| |
| request->OnUpdatePaymentDetails(PaymentDetailsUpdate::Create( |
| scope.GetIsolate(), FromJSONString(scope.GetScriptState(), detail), |
| ASSERT_NO_EXCEPTION)); |
| |
| EXPECT_TRUE(request->shippingOption().IsNull()); |
| } |
| |
| TEST(PaymentRequestTest, UseTheSelectedShippingOptionFromPaymentDetailsUpdate) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(true); |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), |
| BuildPaymentDetailsInitForTest(), options, ASSERT_NO_EXCEPTION); |
| LocalFrame::NotifyUserActivation( |
| &scope.GetFrame(), mojom::UserActivationNotificationType::kTest); |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION); |
| static_cast<payments::mojom::blink::PaymentRequestClient*>(request) |
| ->OnShippingAddressChange(BuildPaymentAddressForTest()); |
| |
| String detail = |
| "{\"total\": {\"label\": \"Total\", \"amount\": {\"currency\": \"USD\", " |
| "\"value\": \"5.00\"}}," |
| "\"shippingOptions\": [{\"id\": \"slow\", \"label\": \"Slow\", " |
| "\"amount\": {\"currency\": \"USD\", \"value\": \"5.00\"}}," |
| "{\"id\": \"fast\", \"label\": \"Fast\", \"amount\": {\"currency\": " |
| "\"USD\", \"value\": \"50.00\"}, \"selected\": true}]}"; |
| |
| request->OnUpdatePaymentDetails(PaymentDetailsUpdate::Create( |
| scope.GetIsolate(), FromJSONString(scope.GetScriptState(), detail), |
| ASSERT_NO_EXCEPTION)); |
| |
| EXPECT_EQ("fast", request->shippingOption()); |
| } |
| |
| TEST(PaymentRequestTest, NoExceptionWithErrorMessageInUpdate) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| &scope.GetFrame(), mojom::UserActivationNotificationType::kTest); |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION); |
| String detail_with_error_msg = |
| "{\"total\": {\"label\": \"Total\", \"amount\": {\"currency\": \"USD\", " |
| "\"value\": \"5.00\"}}," |
| "\"error\": \"This is an error message.\"}"; |
| |
| request->OnUpdatePaymentDetails(PaymentDetailsUpdate::Create( |
| scope.GetIsolate(), |
| FromJSONString(scope.GetScriptState(), detail_with_error_msg), |
| ASSERT_NO_EXCEPTION)); |
| } |
| |
| TEST(PaymentRequestTest, |
| ShouldResolveWithExceptionIfIDsOfShippingOptionsAreDuplicated) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| HeapVector<Member<PaymentShippingOption>> shipping_options(2); |
| shipping_options[0] = BuildShippingOptionForTest( |
| kPaymentTestDataId, kPaymentTestOverwriteValue, "standard"); |
| shipping_options[0]->setSelected(true); |
| shipping_options[1] = BuildShippingOptionForTest( |
| kPaymentTestDataId, kPaymentTestOverwriteValue, "standard"); |
| details->setShippingOptions(shipping_options); |
| PaymentOptions* options = PaymentOptions::Create(); |
| options->setRequestShipping(true); |
| PaymentRequest::Create(scope.GetExecutionContext(), |
| BuildPaymentMethodDataForTest(), details, options, |
| scope.GetExceptionState()); |
| EXPECT_TRUE(scope.GetExceptionState().HadException()); |
| } |
| |
| TEST(PaymentRequestTest, DetailsIdIsSet) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| PaymentDetailsInit* details = PaymentDetailsInit::Create(); |
| details->setTotal(BuildPaymentItemForTest()); |
| details->setId("my_payment_id"); |
| |
| PaymentRequest* request = PaymentRequest::Create( |
| scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, |
| scope.GetExceptionState()); |
| |
| EXPECT_EQ("my_payment_id", request->id()); |
| } |
| |
| // An event listener that owns a page and destroys it when the event is invoked. |
| class PageDeleter final : public NativeEventListener { |
| public: |
| PageDeleter() |
| : holder_(DummyPageHolder::CreateAndCommitNavigation( |
| KURL("https://www.example.com"))) {} |
| ~PageDeleter() override = default; |
| |
| // NativeEventListener: |
| void Invoke(ExecutionContext*, Event*) override { holder_.reset(); } |
| |
| DummyPageHolder* page() { return holder_.get(); } |
| |
| private: |
| std::unique_ptr<DummyPageHolder> holder_; |
| }; |
| |
| TEST(PaymentRequestTest, NoCrashWhenPaymentMethodChangeEventDestroysContext) { |
| test::TaskEnvironment task_environment; |
| PageDeleter* page_deleter = MakeGarbageCollected<PageDeleter>(); |
| LocalFrame& frame = page_deleter->page()->GetFrame(); |
| auto* isolate = ToIsolate(&frame); |
| v8::HandleScope handle_scope(isolate); |
| ScriptState* script_state = ScriptState::From( |
| isolate, |
| ToV8ContextEvenIfDetached(&frame, DOMWrapperWorld::MainWorld(isolate))); |
| v8::Local<v8::Context> context(script_state->GetContext()); |
| v8::Context::Scope context_scope(context); |
| |
| HeapVector<Member<PaymentMethodData>> method_data = |
| BuildPaymentMethodDataForTest(); |
| PaymentRequest* request = PaymentRequest::Create( |
| ExecutionContext::From(script_state), method_data, |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| request->setOnpaymentmethodchange(page_deleter); |
| LocalFrame::NotifyUserActivation( |
| &frame, mojom::UserActivationNotificationType::kTest); |
| request->show(script_state, ASSERT_NO_EXCEPTION); |
| |
| // Trigger the event listener that deletes the execution context. |
| static_cast<payments::mojom::blink::PaymentRequestClient*>(request) |
| ->OnPaymentMethodChange(method_data.front()->supportedMethod(), |
| /*stringified_details=*/"{}"); |
| } |
| |
| TEST(PaymentRequestTest, SPCActivationlessShow) { |
| test::TaskEnvironment task_environment; |
| |
| PaymentRequestV8TestingScope scope; |
| |
| { |
| PaymentRequest* request = PaymentRequest::Create( |
| ExecutionContext::From(scope.GetScriptState()), |
| BuildSecurePaymentConfirmationMethodDataForTest(scope), |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| |
| EXPECT_FALSE(scope.GetDocument().IsUseCounted( |
| WebFeature::kSecurePaymentConfirmationActivationlessShow)); |
| EXPECT_FALSE(scope.GetDocument().IsUseCounted( |
| WebFeature::kPaymentRequestShowWithoutGestureOrToken)); |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION); |
| EXPECT_FALSE(LocalFrame::HasTransientUserActivation(&(scope.GetFrame()))); |
| EXPECT_TRUE(scope.GetDocument().IsUseCounted( |
| WebFeature::kSecurePaymentConfirmationActivationlessShow)); |
| EXPECT_TRUE(scope.GetDocument().IsUseCounted( |
| WebFeature::kPaymentRequestShowWithoutGestureOrToken)); |
| } |
| } |
| |
| TEST(PaymentRequestTest, SPCActivationlessNotConsumedWithActivation) { |
| test::TaskEnvironment task_environment; |
| |
| PaymentRequestV8TestingScope scope; |
| |
| // The first show call has an activation, so activationless SPC shouldn't be |
| // recorded or consumed. |
| { |
| PaymentRequest* request = PaymentRequest::Create( |
| ExecutionContext::From(scope.GetScriptState()), |
| BuildSecurePaymentConfirmationMethodDataForTest(scope), |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| &scope.GetFrame(), mojom::UserActivationNotificationType::kTest); |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION); |
| EXPECT_FALSE(scope.GetDocument().IsUseCounted( |
| WebFeature::kSecurePaymentConfirmationActivationlessShow)); |
| EXPECT_FALSE(scope.GetDocument().IsUseCounted( |
| WebFeature::kPaymentRequestShowWithoutGestureOrToken)); |
| } |
| |
| // A following activationless SPC show call should be allowed, since the first |
| // did not consume the one allowed activationless call. |
| { |
| PaymentRequest* request = PaymentRequest::Create( |
| ExecutionContext::From(scope.GetScriptState()), |
| BuildSecurePaymentConfirmationMethodDataForTest(scope), |
| BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); |
| |
| request->show(scope.GetScriptState(), ASSERT_NO_EXCEPTION); |
| EXPECT_TRUE(scope.GetDocument().IsUseCounted( |
| WebFeature::kSecurePaymentConfirmationActivationlessShow)); |
| EXPECT_TRUE(scope.GetDocument().IsUseCounted( |
| WebFeature::kPaymentRequestShowWithoutGestureOrToken)); |
| } |
| } |
| |
| TEST(PaymentRequestTest, DeprecatedPaymentMethod) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| HeapVector<Member<PaymentMethodData>> method_data( |
| 1, PaymentMethodData::Create()); |
| method_data[0]->setSupportedMethod("https://android.com/pay"); |
| |
| PaymentRequest::Create(ExecutionContext::From(scope.GetScriptState()), |
| method_data, BuildPaymentDetailsInitForTest(), |
| ASSERT_NO_EXCEPTION); |
| |
| EXPECT_TRUE(scope.GetDocument().IsUseCounted( |
| WebFeature::kPaymentRequestDeprecatedPaymentMethod)); |
| } |
| |
| TEST(PaymentRequestTest, NotDeprecatedPaymentMethod) { |
| test::TaskEnvironment task_environment; |
| PaymentRequestV8TestingScope scope; |
| HeapVector<Member<PaymentMethodData>> method_data( |
| 1, PaymentMethodData::Create()); |
| method_data[0]->setSupportedMethod("https://example.test/pay"); |
| |
| PaymentRequest::Create(ExecutionContext::From(scope.GetScriptState()), |
| method_data, BuildPaymentDetailsInitForTest(), |
| ASSERT_NO_EXCEPTION); |
| |
| EXPECT_FALSE(scope.GetDocument().IsUseCounted( |
| WebFeature::kPaymentRequestDeprecatedPaymentMethod)); |
| } |
| |
| } // namespace |
| } // namespace blink |