diff --git a/changelog/add-7846-test-mode-confirm-modal b/changelog/add-7846-test-mode-confirm-modal new file mode 100644 index 00000000000..0725c55b1aa --- /dev/null +++ b/changelog/add-7846-test-mode-confirm-modal @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Display a Confirmaton Modal on enabling Test Mode diff --git a/changelog/cleanup-upe-checkout-class b/changelog/cleanup-upe-checkout-class new file mode 100644 index 00000000000..95cfa040bf5 --- /dev/null +++ b/changelog/cleanup-upe-checkout-class @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +Cleanup the deprecated payment gateway processing - part IV diff --git a/changelog/fix-test-support-phone b/changelog/fix-test-support-phone new file mode 100644 index 00000000000..97abae072f7 --- /dev/null +++ b/changelog/fix-test-support-phone @@ -0,0 +1,5 @@ +Significance: patch +Type: fix +Comment: Modified the test phone numbers supported by Stripe. + + diff --git a/client/settings/general-settings/index.js b/client/settings/general-settings/index.js index 23512d7a66c..b85e9e07632 100644 --- a/client/settings/general-settings/index.js +++ b/client/settings/general-settings/index.js @@ -13,12 +13,14 @@ import { useDevMode, useIsWCPayEnabled, useTestMode } from 'wcpay/data'; import CardBody from '../card-body'; import InlineNotice from 'wcpay/components/inline-notice'; import SetupLivePaymentsModal from 'wcpay/overview/modal/setup-live-payments'; +import TestModeConfirmationModal from './test-mode-confirm-modal'; const GeneralSettings = () => { const [ isWCPayEnabled, setIsWCPayEnabled ] = useIsWCPayEnabled(); const [ isEnabled, updateIsTestModeEnabled ] = useTestMode(); const [ modalVisible, setModalVisible ] = useState( false ); const isDevModeEnabled = useDevMode(); + const [ testModeModalVisible, setTestModeModalVisible ] = useState( false ); return ( <> @@ -48,7 +50,15 @@ const GeneralSettings = () => { { + if ( enableTestMode ) { + setTestModeModalVisible( true ); + } else { + updateIsTestModeEnabled( + enableTestMode + ); + } + } } label={ __( 'Enable test mode', 'woocommerce-payments' @@ -133,6 +143,17 @@ const GeneralSettings = () => { closeModal={ () => setModalVisible( false ) } /> ) } + { testModeModalVisible && ( + { + setTestModeModalVisible( false ); + } } + onConfirm={ () => { + updateIsTestModeEnabled( true ); + setTestModeModalVisible( false ); + } } + /> + ) } ); }; diff --git a/client/settings/general-settings/test-mode-confirm-modal.tsx b/client/settings/general-settings/test-mode-confirm-modal.tsx new file mode 100644 index 00000000000..21e62af1ac8 --- /dev/null +++ b/client/settings/general-settings/test-mode-confirm-modal.tsx @@ -0,0 +1,63 @@ +/** @format **/ + +/** + * External dependencies + */ +import React from 'react'; +import { Button, ExternalLink } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import ConfirmationModal from '../../components/confirmation-modal'; + +interface TestModeConfirmationModalProps { + onClose: () => void; + onConfirm: () => void; +} + +const TestModeConfirmationModal: React.FC< TestModeConfirmationModalProps > = ( { + onClose, + onConfirm, +} ) => { + return ( + + + + + } + > +

+ { __( + 'Are you sure you want to enable test mode?', + 'woocommerce-payments' + ) } +

+

+ { __( + "Test mode lets you try out payments, refunds, disputes and other such processes as you're working on your store " + + 'without handling live payment information. ' + + 'All incoming orders will be simulated, and test mode will have to be disabled before you can accept real orders.', + 'woocommerce-payments' + ) } +

+ + { __( 'Learn more about test mode', 'woocommerce-payments' ) } + +
+ ); +}; + +export default TestModeConfirmationModal; diff --git a/client/settings/general-settings/test/general-settings.test.js b/client/settings/general-settings/test/general-settings.test.js index 93f27d56b2a..2e9ae53fcf6 100644 --- a/client/settings/general-settings/test/general-settings.test.js +++ b/client/settings/general-settings/test/general-settings.test.js @@ -71,4 +71,43 @@ describe( 'GeneralSettings', () => { ); } ); + + it.each( [ [ true ], [ false ] ] )( + 'display of CheckBox when initial Test Mode = %s', + ( isEnabled ) => { + useTestMode.mockReturnValue( [ isEnabled, jest.fn() ] ); + render( ); + const enableTestModeCheckbox = screen.getByLabelText( + 'Enable test mode' + ); + + let expectation = expect( enableTestModeCheckbox ); + if ( ! isEnabled ) { + expectation = expectation.not; + } + expectation.toBeChecked(); + } + ); + + it.each( [ [ true ], [ false ] ] )( + 'Checks Confirmation Modal display when initial Test Mode = %s', + ( isEnabled ) => { + useTestMode.mockReturnValue( [ isEnabled, jest.fn() ] ); + render( ); + const enableTestModeCheckbox = screen.getByLabelText( + 'Enable test mode' + ); + fireEvent.click( enableTestModeCheckbox ); + + let expectation = expect( + screen.queryByText( + 'Are you sure you want to enable test mode?' + ) + ); + if ( isEnabled ) { + expectation = expectation.not; + } + expectation.toBeInTheDocument(); + } + ); } ); diff --git a/client/settings/general-settings/test/test-mode-confirm-modal.test.js b/client/settings/general-settings/test/test-mode-confirm-modal.test.js new file mode 100644 index 00000000000..df247142d81 --- /dev/null +++ b/client/settings/general-settings/test/test-mode-confirm-modal.test.js @@ -0,0 +1,50 @@ +/** @format */ + +/** + * External dependencies + */ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import user from '@testing-library/user-event'; + +/** + * Internal dependencies + */ +import TestModeConfirmationModal from '../test-mode-confirm-modal'; + +const mockOnClose = jest.fn(); +const mockOnConfirm = jest.fn(); + +describe( 'Dev Mode Confirmation Modal', () => { + const renderTestModeConfirmationModal = () => { + return render( + + ); + }; + + it( 'Dev mode confirmation modal asks confirmation', () => { + renderTestModeConfirmationModal(); + expect( + screen.queryByText( 'Are you sure you want to enable test mode?' ) + ).toBeInTheDocument(); + } ); + + it( 'triggers the onClose function on close button click', () => { + renderTestModeConfirmationModal(); + const closeButton = screen.queryByRole( 'button', { name: 'Cancel' } ); + expect( mockOnClose ).not.toBeCalled(); + user.click( closeButton ); + expect( mockOnClose ).toBeCalled(); + } ); + + it( 'triggers the onConfirm function on Enable button click', () => { + renderTestModeConfirmationModal(); + const enableButton = screen.queryByRole( 'button', { name: 'Enable' } ); + expect( mockOnConfirm ).not.toBeCalled(); + user.click( enableButton ); + expect( mockOnConfirm ).toBeCalled(); + } ); +} ); diff --git a/client/settings/support-phone-input/index.js b/client/settings/support-phone-input/index.js index 28a3015e747..4a9259b62d4 100644 --- a/client/settings/support-phone-input/index.js +++ b/client/settings/support-phone-input/index.js @@ -25,9 +25,7 @@ const SupportPhoneInput = ( { setInputVallid } ) => { const isEmptyPhoneValid = supportPhone === '' && currentPhone === ''; const isDevModeEnabled = useDevMode(); const isTestPhoneValid = - isDevModeEnabled && - ( supportPhone === '+1000-000-0000' || - supportPhone === '+10000000000' ); + isDevModeEnabled && supportPhone === '+10000000000'; const [ isPhoneValid, setPhoneValidity ] = useState( true ); if ( ! isTestPhoneValid && ! isPhoneValid && ! isEmptyPhoneValid ) { @@ -53,7 +51,7 @@ const SupportPhoneInput = ( { setInputVallid } ) => { let labelText = __( 'Support phone number', 'woocommerce-payments' ); if ( isDevModeEnabled ) { labelText += __( - ' (+1 000-000-0000 can be used in dev mode)', + ' (+1 0000000000 can be used in dev mode)', 'woocommerce-payments' ); } diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php index 02e41836255..678afa250a0 100644 --- a/includes/class-wc-payment-gateway-wcpay.php +++ b/includes/class-wc-payment-gateway-wcpay.php @@ -725,15 +725,6 @@ public function should_use_stripe_platform_on_checkout_page() { return false; } - /** - * Renders the credit card input fields needed to get the user's payment information on the checkout page. - * - * We also add the JavaScript which drives the UI. - */ - public function payment_fields() { - do_action( 'wc_payments_add_payment_fields' ); - } - /** * Checks whether the new payment process should be used to pay for a given order. * diff --git a/includes/class-wc-payments-checkout.php b/includes/class-wc-payments-checkout.php index 18198308323..9851a2ea0c2 100644 --- a/includes/class-wc-payments-checkout.php +++ b/includes/class-wc-payments-checkout.php @@ -7,18 +7,21 @@ namespace WCPay; +use Exception; use Jetpack_Options; use WC_AJAX; use WC_Checkout; -use WC_Payment_Gateway_WCPay; use WC_Payments; use WC_Payments_Account; use WC_Payments_Customer_Service; -use WC_Payments_Features; use WC_Payments_Fraud_Service; use WC_Payments_Utils; +use WC_Payments_Features; +use WCPay\Constants\Payment_Method; use WCPay\Fraud_Prevention\Fraud_Prevention_Service; +use WCPay\Payment_Methods\UPE_Payment_Gateway; use WCPay\WooPay\WooPay_Utilities; +use WCPay\Payment_Methods\UPE_Payment_Method; /** @@ -29,7 +32,7 @@ class WC_Payments_Checkout { /** * WC Payments Gateway. * - * @var WC_Payment_Gateway_WCPay + * @var UPE_Payment_Gateway */ protected $gateway; @@ -64,14 +67,14 @@ class WC_Payments_Checkout { /** * Construct. * - * @param WC_Payment_Gateway_WCPay $gateway WC Payment Gateway. - * @param WooPay_Utilities $woopay_util WooPay Utilities. - * @param WC_Payments_Account $account WC Payments Account. - * @param WC_Payments_Customer_Service $customer_service WC Payments Customer Service. - * @param WC_Payments_Fraud_Service $fraud_service Fraud service instance. + * @param UPE_Payment_Gateway $gateway WC Payment Gateway. + * @param WooPay_Utilities $woopay_util WooPay Utilities. + * @param WC_Payments_Account $account WC Payments Account. + * @param WC_Payments_Customer_Service $customer_service WC Payments Customer Service. + * @param WC_Payments_Fraud_Service $fraud_service Fraud service instance. */ public function __construct( - WC_Payment_Gateway_WCPay $gateway, + UPE_Payment_Gateway $gateway, WooPay_Utilities $woopay_util, WC_Payments_Account $account, WC_Payments_Customer_Service $customer_service, @@ -90,16 +93,51 @@ public function __construct( * @return void */ public function init_hooks() { - add_action( 'wc_payments_add_payment_fields', [ $this, 'payment_fields' ] ); + add_action( 'wc_payments_set_gateway', [ $this, 'set_gateway' ] ); + add_action( 'wc_payments_add_upe_payment_fields', [ $this, 'payment_fields' ] ); + add_action( 'woocommerce_after_account_payment_methods', [ $this->gateway, 'remove_upe_setup_intent_from_session' ], 10, 0 ); + add_action( 'woocommerce_subscription_payment_method_updated', [ $this->gateway, 'remove_upe_setup_intent_from_session' ], 10, 0 ); + add_action( 'woocommerce_order_payment_status_changed', [ get_class( $this->gateway ), 'remove_upe_payment_intent_from_session' ], 10, 0 ); + add_action( 'wp', [ $this->gateway, 'maybe_process_upe_redirect' ] ); + add_action( 'wc_ajax_wcpay_log_payment_error', [ $this->gateway, 'log_payment_error_ajax' ] ); + add_action( 'wp_ajax_save_upe_appearance', [ $this->gateway, 'save_upe_appearance_ajax' ] ); + add_action( 'wp_ajax_nopriv_save_upe_appearance', [ $this->gateway, 'save_upe_appearance_ajax' ] ); + add_action( 'switch_theme', [ $this->gateway, 'clear_upe_appearance_transient' ] ); + add_action( 'woocommerce_woocommerce_payments_updated', [ $this->gateway, 'clear_upe_appearance_transient' ] ); + add_action( 'wc_ajax_wcpay_init_setup_intent', [ $this->gateway, 'init_setup_intent_ajax' ] ); + add_action( 'wc_ajax_wcpay_log_payment_error', [ $this->gateway, 'log_payment_error_ajax' ] ); + + add_action( 'wp_enqueue_scripts', [ $this, 'register_scripts' ] ); add_action( 'wp_enqueue_scripts', [ $this, 'register_scripts_for_zero_order_total' ], 11 ); } /** - * Enqueues and localizes WCPay's checkout scripts. + * Registers all scripts, necessary for the gateway. */ - public function enqueue_payment_scripts() { - wp_localize_script( 'WCPAY_CHECKOUT', 'wcpayConfig', WC_Payments::get_wc_payments_checkout()->get_payment_fields_js_config() ); - wp_enqueue_script( 'WCPAY_CHECKOUT' ); + public function register_scripts() { + // Register Stripe's JavaScript using the same ID as the Stripe Gateway plugin. This prevents this JS being + // loaded twice in the event a site has both plugins enabled. We still run the risk of different plugins + // loading different versions however. If Stripe release a v4 of their JavaScript, we could consider + // changing the ID to stripe_v4. This would allow older plugins to keep using v3 while we used any new + // feature in v4. Stripe have allowed loading of 2 different versions of stripe.js in the past ( + // https://stripe.com/docs/stripe-js/elements/migrating). + wp_register_script( + 'stripe', + 'https://js.stripe.com/v3/', + [], + '3.0', + true + ); + + $script_dependencies = [ 'stripe', 'wc-checkout', 'wp-i18n' ]; + + if ( $this->gateway->supports( 'tokenization' ) ) { + $script_dependencies[] = 'woocommerce-tokenization-form'; + } + + $script = 'dist/checkout'; + + WC_Payments::register_script_with_dependencies( 'wcpay-upe-checkout', $script, $script_dependencies ); } /** @@ -132,7 +170,6 @@ public function register_scripts_for_zero_order_total() { * @return array */ public function get_payment_fields_js_config() { - // Needed to init the hooks. WC_Checkout::instance(); @@ -179,11 +216,140 @@ public function get_payment_fields_js_config() { * * @param array $js_config The JS config for the payment fields. */ - return apply_filters( 'wcpay_payment_fields_js_config', $js_config ); + $payment_fields = apply_filters( 'wcpay_payment_fields_js_config', $js_config ); + + $payment_fields['accountDescriptor'] = $this->gateway->get_account_statement_descriptor(); + $payment_fields['addPaymentReturnURL'] = wc_get_account_endpoint_url( 'payment-methods' ); + $payment_fields['gatewayId'] = UPE_Payment_Gateway::GATEWAY_ID; + $payment_fields['isCheckout'] = is_checkout(); + $payment_fields['paymentMethodsConfig'] = $this->get_enabled_payment_method_config(); + $payment_fields['testMode'] = WC_Payments::mode()->is_test(); + $payment_fields['upeAppearance'] = get_transient( UPE_Payment_Gateway::UPE_APPEARANCE_TRANSIENT ); + $payment_fields['wcBlocksUPEAppearance'] = get_transient( UPE_Payment_Gateway::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT ); + $payment_fields['cartContainsSubscription'] = $this->gateway->is_subscription_item_in_cart(); + $payment_fields['currency'] = get_woocommerce_currency(); + $cart_total = ( WC()->cart ? WC()->cart->get_total( '' ) : 0 ); + $payment_fields['cartTotal'] = WC_Payments_Utils::prepare_amount( $cart_total, get_woocommerce_currency() ); + + $enabled_billing_fields = []; + foreach ( WC()->checkout()->get_checkout_fields( 'billing' ) as $billing_field => $billing_field_options ) { + if ( ! isset( $billing_field_options['enabled'] ) || $billing_field_options['enabled'] ) { + $enabled_billing_fields[] = $billing_field; + } + } + $payment_fields['enabledBillingFields'] = $enabled_billing_fields; + + if ( is_wc_endpoint_url( 'order-pay' ) ) { + if ( $this->gateway->is_subscriptions_enabled() && $this->gateway->is_changing_payment_method_for_subscription() ) { + $payment_fields['isChangingPayment'] = true; + $payment_fields['addPaymentReturnURL'] = esc_url_raw( home_url( add_query_arg( [] ) ) ); + + if ( $this->gateway->is_setup_intent_success_creation_redirection() && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wc_clean( wp_unslash( $_GET['_wpnonce'] ) ) ) ) { + $setup_intent_id = isset( $_GET['setup_intent'] ) ? wc_clean( wp_unslash( $_GET['setup_intent'] ) ) : ''; + $token = $this->gateway->create_token_from_setup_intent( $setup_intent_id, wp_get_current_user() ); + if ( null !== $token ) { + $payment_fields['newTokenFormId'] = '#wc-' . $token->get_gateway_id() . '-payment-token-' . $token->get_id(); + } + } + return $payment_fields; // nosemgrep: audit.php.wp.security.xss.query-arg -- server generated url is passed in. + } + + $payment_fields['isOrderPay'] = true; + $order_id = absint( get_query_var( 'order-pay' ) ); + $payment_fields['orderId'] = $order_id; + $order = wc_get_order( $order_id ); + + if ( is_a( $order, 'WC_Order' ) ) { + $order_currency = $order->get_currency(); + $payment_fields['currency'] = $order_currency; + $payment_fields['cartTotal'] = WC_Payments_Utils::prepare_amount( $order->get_total(), $order_currency ); + $payment_fields['orderReturnURL'] = esc_url_raw( + add_query_arg( + [ + 'wc_payment_method' => UPE_Payment_Gateway::GATEWAY_ID, + '_wpnonce' => wp_create_nonce( 'wcpay_process_redirect_order_nonce' ), + ], + $this->gateway->get_return_url( $order ) + ) + ); + } + } + + /** + * Allows filtering for the payment fields. + * + * @param array $payment_fields The payment fields. + */ + return apply_filters( 'wcpay_payment_fields_js_config', $payment_fields ); // nosemgrep: audit.php.wp.security.xss.query-arg -- server generated url is passed in. } /** - * Renders the credit card input fields needed to get the user's payment information on the checkout page. + * Checks if WooPay is enabled. + * + * @return bool - True if WooPay enabled, false otherwise. + */ + private function is_woopay_enabled() { + return WC_Payments_Features::is_woopay_eligible() && 'yes' === $this->gateway->get_option( 'platform_checkout', 'no' ) && WC_Payments_Features::is_woopay_express_checkout_enabled(); + } + + /** + * Gets payment method settings to pass to client scripts + * + * @return array + */ + public function get_enabled_payment_method_config() { + $settings = []; + $enabled_payment_methods = $this->gateway->get_payment_method_ids_enabled_at_checkout(); + + foreach ( $enabled_payment_methods as $payment_method_id ) { + // Link by Stripe should be validated with available fees. + if ( Payment_Method::LINK === $payment_method_id ) { + if ( ! in_array( Payment_Method::LINK, array_keys( $this->account->get_fees() ), true ) ) { + continue; + } + } + + $payment_method = $this->gateway->wc_payments_get_payment_method_by_id( $payment_method_id ); + $settings[ $payment_method_id ] = [ + 'isReusable' => $payment_method->is_reusable(), + 'title' => $payment_method->get_title(), + 'icon' => $payment_method->get_icon(), + 'showSaveOption' => $this->should_upe_payment_method_show_save_option( $payment_method ), + 'countries' => $payment_method->get_countries(), + ]; + + $gateway_for_payment_method = $this->gateway->wc_payments_get_payment_gateway_by_id( $payment_method_id ); + $settings[ $payment_method_id ]['upePaymentIntentData'] = $this->gateway->get_payment_intent_data_from_session( $payment_method_id ); + $settings[ $payment_method_id ]['upeSetupIntentData'] = $this->gateway->get_setup_intent_data_from_session( $payment_method_id ); + $settings[ $payment_method_id ]['testingInstructions'] = WC_Payments_Utils::esc_interpolated_html( + /* translators: link to Stripe testing page */ + $payment_method->get_testing_instructions(), + [ + 'strong' => '', + 'a' => '', + ] + ); + $settings[ $payment_method_id ]['forceNetworkSavedCards'] = $gateway_for_payment_method->should_use_stripe_platform_on_checkout_page(); + } + + return $settings; + } + + /** + * Checks if the save option for a payment method should be displayed or not. + * + * @param UPE_Payment_Method $payment_method UPE Payment Method instance. + * @return bool - True if the payment method is reusable and the saved cards feature is enabled for the gateway and there is no subscription item in the cart, false otherwise. + */ + private function should_upe_payment_method_show_save_option( $payment_method ) { + if ( $payment_method->is_reusable() ) { + return $this->gateway->is_saved_cards_enabled() && ! $this->gateway->is_subscription_item_in_cart(); + } + return false; + } + + /** + * Renders the UPE input fields needed to get the user's payment information on the checkout page. * * We also add the JavaScript which drives the UI. */ @@ -191,15 +357,28 @@ public function payment_fields() { try { $display_tokenization = $this->gateway->supports( 'tokenization' ) && ( is_checkout() || is_add_payment_method_page() ); - add_action( 'wp_footer', [ $this, 'enqueue_payment_scripts' ] ); + /** + * Localizing scripts within shortcodes does not work in WP 5.9, + * but we need `$this->get_payment_fields_js_config` to be called + * before `$this->saved_payment_methods()`. + */ + $payment_fields = $this->get_payment_fields_js_config(); + $upe_object_name = 'wcpay_upe_config'; + wp_enqueue_script( 'wcpay-upe-checkout' ); + add_action( + 'wp_footer', + function() use ( $payment_fields, $upe_object_name ) { + wp_localize_script( 'wcpay-upe-checkout', $upe_object_name, $payment_fields ); + } + ); $prepared_customer_data = $this->customer_service->get_prepared_customer_data(); if ( ! empty( $prepared_customer_data ) ) { - wp_localize_script( 'WCPAY_CHECKOUT', 'wcpayCustomerData', $prepared_customer_data ); + wp_localize_script( 'wcpay-upe-checkout', 'wcpayCustomerData', $prepared_customer_data ); } WC_Payments_Utils::enqueue_style( - 'WCPAY_CHECKOUT', + 'wcpay-upe-checkout', plugins_url( 'dist/checkout.css', WCPAY_PLUGIN_FILE ), [], WC_Payments::get_file_version( 'dist/checkout.css' ), @@ -215,14 +394,17 @@ public function payment_fields() { is_test() ) : ?>

Test mode: use the test VISA card 4242424242424242 with any expiry date and CVC, or any test card numbers listed here.', 'woocommerce-payments' ), - [ - 'strong' => '', - 'a' => '', - ] - ); + $testing_instructions = $this->gateway->get_payment_method()->get_testing_instructions(); + if ( false !== $testing_instructions ) { + echo WC_Payments_Utils::esc_interpolated_html( + /* translators: link to Stripe testing page */ + $testing_instructions, + [ + 'strong' => '', + 'a' => '', + ] + ); + } ?>

@@ -238,13 +420,10 @@ public function payment_fields() { } ?> -
-
- - - +
gateway->is_saved_cards_enabled() ) { + $this->gateway->display_gateway_html(); + if ( $this->gateway->is_saved_cards_enabled() && $this->gateway->should_support_saved_payments() ) { $force_save_payment = ( $display_tokenization && ! apply_filters( 'wc_payments_display_save_payment_method_checkbox', $display_tokenization ) ) || is_add_payment_method_page(); if ( is_user_logged_in() || $force_save_payment ) { $this->gateway->save_payment_method_checkbox( $force_save_payment ); @@ -260,10 +439,11 @@ public function payment_fields() { gateway->id ); + do_action( 'wcpay_payment_fields_upe', $this->gateway->id ); } catch ( \Exception $e ) { // Output the error message. + Logger::log( 'Error: ' . $e->getMessage() ); ?>
gateway = $this->gateway->wc_payments_get_payment_gateway_by_id( $payment_method_id ); + } + } + } diff --git a/includes/class-wc-payments-upe-checkout.php b/includes/class-wc-payments-upe-checkout.php deleted file mode 100644 index 4096b0d068d..00000000000 --- a/includes/class-wc-payments-upe-checkout.php +++ /dev/null @@ -1,399 +0,0 @@ -gateway = $gateway; - $this->woopay_util = $woopay_util; - $this->account = $account; - $this->customer_service = $customer_service; - $this->fraud_service = $fraud_service; - } - - /** - * Initializes this class's WP hooks. - * - * @return void - */ - public function init_hooks() { - add_action( 'wc_payments_set_gateway', [ $this, 'set_gateway' ] ); - add_action( 'wc_payments_add_upe_payment_fields', [ $this, 'payment_fields' ] ); - add_action( 'woocommerce_after_account_payment_methods', [ $this->gateway, 'remove_upe_setup_intent_from_session' ], 10, 0 ); - add_action( 'woocommerce_subscription_payment_method_updated', [ $this->gateway, 'remove_upe_setup_intent_from_session' ], 10, 0 ); - add_action( 'woocommerce_order_payment_status_changed', [ get_class( $this->gateway ), 'remove_upe_payment_intent_from_session' ], 10, 0 ); - add_action( 'wp', [ $this->gateway, 'maybe_process_upe_redirect' ] ); - add_action( 'wc_ajax_wcpay_log_payment_error', [ $this->gateway, 'log_payment_error_ajax' ] ); - add_action( 'wp_ajax_save_upe_appearance', [ $this->gateway, 'save_upe_appearance_ajax' ] ); - add_action( 'wp_ajax_nopriv_save_upe_appearance', [ $this->gateway, 'save_upe_appearance_ajax' ] ); - add_action( 'switch_theme', [ $this->gateway, 'clear_upe_appearance_transient' ] ); - add_action( 'woocommerce_woocommerce_payments_updated', [ $this->gateway, 'clear_upe_appearance_transient' ] ); - add_action( 'wc_ajax_wcpay_init_setup_intent', [ $this->gateway, 'init_setup_intent_ajax' ] ); - add_action( 'wc_ajax_wcpay_log_payment_error', [ $this->gateway, 'log_payment_error_ajax' ] ); - - add_action( 'wp_enqueue_scripts', [ $this, 'register_scripts' ] ); - add_action( 'wp_enqueue_scripts', [ $this, 'register_scripts_for_zero_order_total' ], 11 ); - } - - /** - * Registers all scripts, necessary for the gateway. - */ - public function register_scripts() { - // Register Stripe's JavaScript using the same ID as the Stripe Gateway plugin. This prevents this JS being - // loaded twice in the event a site has both plugins enabled. We still run the risk of different plugins - // loading different versions however. If Stripe release a v4 of their JavaScript, we could consider - // changing the ID to stripe_v4. This would allow older plugins to keep using v3 while we used any new - // feature in v4. Stripe have allowed loading of 2 different versions of stripe.js in the past ( - // https://stripe.com/docs/stripe-js/elements/migrating). - wp_register_script( - 'stripe', - 'https://js.stripe.com/v3/', - [], - '3.0', - true - ); - - $script_dependencies = [ 'stripe', 'wc-checkout', 'wp-i18n' ]; - - if ( $this->gateway->supports( 'tokenization' ) ) { - $script_dependencies[] = 'woocommerce-tokenization-form'; - } - - $script = 'dist/checkout'; - - WC_Payments::register_script_with_dependencies( 'wcpay-upe-checkout', $script, $script_dependencies ); - } - - /** - * Generates the configuration values, needed for payment fields. - * - * Isolated as a separate method in order to be available both - * during the classic checkout, as well as the checkout block. - * - * @return array - */ - public function get_payment_fields_js_config() { - - $payment_fields = parent::get_payment_fields_js_config(); - $payment_fields['accountDescriptor'] = $this->gateway->get_account_statement_descriptor(); - $payment_fields['addPaymentReturnURL'] = wc_get_account_endpoint_url( 'payment-methods' ); - $payment_fields['gatewayId'] = UPE_Payment_Gateway::GATEWAY_ID; - $payment_fields['isCheckout'] = is_checkout(); - $payment_fields['paymentMethodsConfig'] = $this->get_enabled_payment_method_config(); - $payment_fields['testMode'] = WC_Payments::mode()->is_test(); - $payment_fields['upeAppearance'] = get_transient( UPE_Payment_Gateway::UPE_APPEARANCE_TRANSIENT ); - $payment_fields['wcBlocksUPEAppearance'] = get_transient( UPE_Payment_Gateway::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT ); - $payment_fields['cartContainsSubscription'] = $this->gateway->is_subscription_item_in_cart(); - $payment_fields['currency'] = get_woocommerce_currency(); - $cart_total = ( WC()->cart ? WC()->cart->get_total( '' ) : 0 ); - $payment_fields['cartTotal'] = WC_Payments_Utils::prepare_amount( $cart_total, get_woocommerce_currency() ); - - $enabled_billing_fields = []; - foreach ( WC()->checkout()->get_checkout_fields( 'billing' ) as $billing_field => $billing_field_options ) { - if ( ! isset( $billing_field_options['enabled'] ) || $billing_field_options['enabled'] ) { - $enabled_billing_fields[] = $billing_field; - } - } - $payment_fields['enabledBillingFields'] = $enabled_billing_fields; - - if ( is_wc_endpoint_url( 'order-pay' ) ) { - if ( $this->gateway->is_subscriptions_enabled() && $this->gateway->is_changing_payment_method_for_subscription() ) { - $payment_fields['isChangingPayment'] = true; - $payment_fields['addPaymentReturnURL'] = esc_url_raw( home_url( add_query_arg( [] ) ) ); - - if ( $this->gateway->is_setup_intent_success_creation_redirection() && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wc_clean( wp_unslash( $_GET['_wpnonce'] ) ) ) ) { - $setup_intent_id = isset( $_GET['setup_intent'] ) ? wc_clean( wp_unslash( $_GET['setup_intent'] ) ) : ''; - $token = $this->gateway->create_token_from_setup_intent( $setup_intent_id, wp_get_current_user() ); - if ( null !== $token ) { - $payment_fields['newTokenFormId'] = '#wc-' . $token->get_gateway_id() . '-payment-token-' . $token->get_id(); - } - } - return $payment_fields; // nosemgrep: audit.php.wp.security.xss.query-arg -- server generated url is passed in. - } - - $payment_fields['isOrderPay'] = true; - $order_id = absint( get_query_var( 'order-pay' ) ); - $payment_fields['orderId'] = $order_id; - $order = wc_get_order( $order_id ); - - if ( is_a( $order, 'WC_Order' ) ) { - $order_currency = $order->get_currency(); - $payment_fields['currency'] = $order_currency; - $payment_fields['cartTotal'] = WC_Payments_Utils::prepare_amount( $order->get_total(), $order_currency ); - $payment_fields['orderReturnURL'] = esc_url_raw( - add_query_arg( - [ - 'wc_payment_method' => UPE_Payment_Gateway::GATEWAY_ID, - '_wpnonce' => wp_create_nonce( 'wcpay_process_redirect_order_nonce' ), - ], - $this->gateway->get_return_url( $order ) - ) - ); - } - } - - /** - * Allows filtering for the payment fields. - * - * @param array $payment_fields The payment fields. - */ - return apply_filters( 'wcpay_payment_fields_js_config', $payment_fields ); // nosemgrep: audit.php.wp.security.xss.query-arg -- server generated url is passed in. - } - - /** - * Checks if WooPay is enabled. - * - * @return bool - True if WooPay enabled, false otherwise. - */ - private function is_woopay_enabled() { - return WC_Payments_Features::is_woopay_eligible() && 'yes' === $this->gateway->get_option( 'platform_checkout', 'no' ) && WC_Payments_Features::is_woopay_express_checkout_enabled(); - } - - /** - * Gets payment method settings to pass to client scripts - * - * @return array - */ - public function get_enabled_payment_method_config() { - $settings = []; - $enabled_payment_methods = $this->gateway->get_payment_method_ids_enabled_at_checkout(); - - foreach ( $enabled_payment_methods as $payment_method_id ) { - // Link by Stripe should be validated with available fees. - if ( Payment_Method::LINK === $payment_method_id ) { - if ( ! in_array( Payment_Method::LINK, array_keys( $this->account->get_fees() ), true ) ) { - continue; - } - } - - $payment_method = $this->gateway->wc_payments_get_payment_method_by_id( $payment_method_id ); - $settings[ $payment_method_id ] = [ - 'isReusable' => $payment_method->is_reusable(), - 'title' => $payment_method->get_title(), - 'icon' => $payment_method->get_icon(), - 'showSaveOption' => $this->should_upe_payment_method_show_save_option( $payment_method ), - 'countries' => $payment_method->get_countries(), - ]; - - $gateway_for_payment_method = $this->gateway->wc_payments_get_payment_gateway_by_id( $payment_method_id ); - $settings[ $payment_method_id ]['upePaymentIntentData'] = $this->gateway->get_payment_intent_data_from_session( $payment_method_id ); - $settings[ $payment_method_id ]['upeSetupIntentData'] = $this->gateway->get_setup_intent_data_from_session( $payment_method_id ); - $settings[ $payment_method_id ]['testingInstructions'] = WC_Payments_Utils::esc_interpolated_html( - /* translators: link to Stripe testing page */ - $payment_method->get_testing_instructions(), - [ - 'strong' => '', - 'a' => '', - ] - ); - $settings[ $payment_method_id ]['forceNetworkSavedCards'] = $gateway_for_payment_method->should_use_stripe_platform_on_checkout_page(); - } - - return $settings; - } - - /** - * Checks if the save option for a payment method should be displayed or not. - * - * @param UPE_Payment_Method $payment_method UPE Payment Method instance. - * @return bool - True if the payment method is reusable and the saved cards feature is enabled for the gateway and there is no subscription item in the cart, false otherwise. - */ - private function should_upe_payment_method_show_save_option( $payment_method ) { - if ( $payment_method->is_reusable() ) { - return $this->gateway->is_saved_cards_enabled() && ! $this->gateway->is_subscription_item_in_cart(); - } - return false; - } - - /** - * Renders the UPE input fields needed to get the user's payment information on the checkout page. - * - * We also add the JavaScript which drives the UI. - */ - public function payment_fields() { - try { - $display_tokenization = $this->gateway->supports( 'tokenization' ) && ( is_checkout() || is_add_payment_method_page() ); - - /** - * Localizing scripts within shortcodes does not work in WP 5.9, - * but we need `$this->get_payment_fields_js_config` to be called - * before `$this->saved_payment_methods()`. - */ - $payment_fields = $this->get_payment_fields_js_config(); - $upe_object_name = 'wcpay_upe_config'; - wp_enqueue_script( 'wcpay-upe-checkout' ); - add_action( - 'wp_footer', - function() use ( $payment_fields, $upe_object_name ) { - wp_localize_script( 'wcpay-upe-checkout', $upe_object_name, $payment_fields ); - } - ); - - $prepared_customer_data = $this->customer_service->get_prepared_customer_data(); - if ( ! empty( $prepared_customer_data ) ) { - wp_localize_script( 'wcpay-upe-checkout', 'wcpayCustomerData', $prepared_customer_data ); - } - - WC_Payments_Utils::enqueue_style( - 'wcpay-upe-checkout', - plugins_url( 'dist/checkout.css', WCPAY_PLUGIN_FILE ), - [], - WC_Payments::get_file_version( 'dist/checkout.css' ), - 'all' - ); - - // Output the form HTML. - ?> - gateway->get_description() ) ) : ?> -

gateway->get_description() ); ?>

- - - is_test() ) : ?> -

- gateway->get_payment_method()->get_testing_instructions(); - if ( false !== $testing_instructions ) { - echo WC_Payments_Utils::esc_interpolated_html( - /* translators: link to Stripe testing page */ - $testing_instructions, - [ - 'strong' => '', - 'a' => '', - ] - ); - } - ?> -

- - - gateway->tokenization_script(); - // avoid showing saved payment methods on my-accounts add payment method page. - if ( ! is_add_payment_method_page() ) { - $this->gateway->saved_payment_methods(); - } - } - ?> - -
- gateway->display_gateway_html(); - if ( $this->gateway->is_saved_cards_enabled() && $this->gateway->should_support_saved_payments() ) { - $force_save_payment = ( $display_tokenization && ! apply_filters( 'wc_payments_display_save_payment_method_checkbox', $display_tokenization ) ) || is_add_payment_method_page(); - if ( is_user_logged_in() || $force_save_payment ) { - $this->gateway->save_payment_method_checkbox( $force_save_payment ); - } - } - ?> - -
- - session && Fraud_Prevention_Service::get_instance()->is_enabled() ) : ?> - - - - gateway->id ); - - } catch ( \Exception $e ) { - // Output the error message. - Logger::log( 'Error: ' . $e->getMessage() ); - ?> -
- -
- gateway = $this->gateway->wc_payments_get_payment_gateway_by_id( $payment_method_id ); - } - } - -} diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php index 006f2deef2a..baf1ea9a8ca 100644 --- a/includes/class-wc-payments.php +++ b/includes/class-wc-payments.php @@ -35,7 +35,6 @@ use WCPay\Session_Rate_Limiter; use WCPay\Database_Cache; use WCPay\WC_Payments_Checkout; -use WCPay\WC_Payments_UPE_Checkout; use WCPay\WooPay\Service\Checkout_Service; use WCPay\Core\WC_Payments_Customer_Service_API; use WCPay\Constants\Payment_Method; @@ -264,7 +263,7 @@ class WC_Payments { /** * WC Payments Checkout * - * @var WC_Payments_Checkout|WC_Payments_UPE_Checkout + * @var WC_Payments_Checkout */ private static $wc_payments_checkout; @@ -399,7 +398,6 @@ public static function init() { include_once __DIR__ . '/class-session-rate-limiter.php'; include_once __DIR__ . '/class-wc-payment-gateway-wcpay.php'; include_once __DIR__ . '/class-wc-payments-checkout.php'; - include_once __DIR__ . '/class-wc-payments-upe-checkout.php'; include_once __DIR__ . '/payment-methods/class-cc-payment-gateway.php'; include_once __DIR__ . '/payment-methods/class-upe-payment-gateway.php'; include_once __DIR__ . '/payment-methods/class-upe-split-payment-gateway.php'; @@ -555,7 +553,7 @@ public static function init() { } self::$card_gateway = self::get_payment_gateway_by_id( 'card' ); - self::$wc_payments_checkout = new WC_Payments_UPE_Checkout( self::get_gateway(), self::$woopay_util, self::$account, self::$customer_service, self::$fraud_service ); + self::$wc_payments_checkout = new WC_Payments_Checkout( self::get_gateway(), self::$woopay_util, self::$account, self::$customer_service, self::$fraud_service ); self::$card_gateway->init_hooks(); self::$wc_payments_checkout->init_hooks(); @@ -1191,7 +1189,7 @@ public static function get_gateway() { /** * Returns the WC_Payments_Checkout instance * - * @return WC_Payments_Checkout|WC_Payments_UPE_Checkout gateway instance + * @return WC_Payments_Checkout gateway instance */ public static function get_wc_payments_checkout() { return self::$wc_payments_checkout; diff --git a/includes/payment-methods/class-upe-payment-gateway.php b/includes/payment-methods/class-upe-payment-gateway.php index a8cfbbfced1..b1ba28589b6 100644 --- a/includes/payment-methods/class-upe-payment-gateway.php +++ b/includes/payment-methods/class-upe-payment-gateway.php @@ -854,7 +854,7 @@ public function is_proper_intent_used_with_order( $order, $intent_id_from_reques * @return array */ public function get_payment_fields_js_config() { - wc_deprecated_function( __FUNCTION__, '5.0.0', 'WC_Payments_UPE_Checkout::get_payment_fields_js_config' ); + wc_deprecated_function( __FUNCTION__, '5.0.0', 'WC_Payments_Checkout::get_payment_fields_js_config' ); return WC_Payments::get_wc_payments_checkout()->get_payment_fields_js_config(); } @@ -1111,7 +1111,7 @@ private function validate_order_id_received_vs_intent_meta_order_id( WC_Order $o * @return array */ private function get_enabled_payment_method_config() { - wc_deprecated_function( __FUNCTION__, '5.0.0', 'WC_Payments_UPE_Checkout::get_enabled_payment_method_config' ); + wc_deprecated_function( __FUNCTION__, '5.0.0', 'WC_Payments_Checkout::get_enabled_payment_method_config' ); return WC_Payments::get_wc_payments_checkout()->get_enabled_payment_method_config(); } diff --git a/tests/unit/payment-methods/test-class-upe-payment-gateway.php b/tests/unit/payment-methods/test-class-upe-payment-gateway.php index 7ca31052a47..fded27349c0 100644 --- a/tests/unit/payment-methods/test-class-upe-payment-gateway.php +++ b/tests/unit/payment-methods/test-class-upe-payment-gateway.php @@ -21,7 +21,6 @@ use WCPay\Exceptions\Process_Payment_Exception; use WCPay\WooPay\WooPay_Utilities; use WCPay\Session_Rate_Limiter; -use WCPay\WC_Payments_UPE_Checkout; use WCPAY_UnitTestCase; use WC_Helper_Order; use WC_Helper_Intention; @@ -345,23 +344,9 @@ public function tear_down() { wcpay_get_test_container()->reset_all_replacements(); } - public function test_payment_fields_outputs_fields() { - $this->set_cart_contains_subscription_items( false ); - $this->set_get_upe_enabled_payment_method_statuses_return_value(); - - // Add the UPE Checkout action. - $checkout = new WC_Payments_UPE_Checkout( - $this->mock_upe_gateway, - $this->mock_woopay_utilities, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_fraud_service - ); - $checkout->init_hooks(); - - $this->mock_upe_gateway->payment_fields(); - + public function test_display_gateway_html() { $this->expectOutputRegex( '/
<\/div>/' ); + $this->mock_upe_gateway->display_gateway_html(); } public function test_update_payment_intent_adds_customer_save_payment_and_level3_data() { @@ -1799,145 +1784,16 @@ function( $argument ) { } public function test_remove_link_payment_method_if_card_disabled() { + $this->mock_upe_gateway->settings['upe_enabled_payment_method_ids'] = [ 'link' ]; - $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->mock_order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service, - ] - ) - ->setMethods( - [ - 'get_upe_enabled_payment_method_statuses', - 'get_upe_enabled_payment_method_ids', - ] - ) - ->getMock(); - - $mock_upe_gateway - ->expects( $this->once() ) - ->method( 'get_upe_enabled_payment_method_ids' ) - ->will( - $this->returnValue( [ 'link' ] ) - ); - $mock_upe_gateway + $this->mock_upe_gateway ->expects( $this->once() ) ->method( 'get_upe_enabled_payment_method_statuses' ) ->will( $this->returnValue( [ 'link_payments' => [ 'status' => 'active' ] ] ) ); - $upe_checkout = new WC_Payments_UPE_Checkout( - $mock_upe_gateway, - $this->mock_woopay_utilities, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_fraud_service - ); - - $this->assertSame( $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'], [] ); - } - - public function test_link_payment_method_if_card_enabled() { - WC_Helper_Site_Currency::$mock_site_currency = 'USD'; - - $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->mock_order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service, - ] - ) - ->setMethods( - [ - 'get_upe_enabled_payment_method_statuses', - 'get_upe_enabled_payment_method_ids', - ] - ) - ->getMock(); - $mock_upe_gateway - ->expects( $this->once() ) - ->method( 'get_upe_enabled_payment_method_ids' ) - ->will( - $this->returnValue( [ 'card', 'link' ] ) - ); - $mock_upe_gateway - ->expects( $this->once() ) - ->method( 'get_upe_enabled_payment_method_statuses' ) - ->will( - $this->returnValue( - [ - 'link_payments' => [ 'status' => 'active' ], - 'card_payments' => [ 'status' => 'active' ], - ] - ) - ); - - $this->mock_payment_methods[ Payment_Method::LINK ]->expects( $this->any() ) - ->method( 'get_icon' ) - ->will( - $this->returnValue( $this->icon_url ) - ); - $this->mock_payment_methods[ Payment_Method::CARD ]->expects( $this->any() ) - ->method( 'get_icon' ) - ->will( - $this->returnValue( $this->icon_url ) - ); - - $upe_checkout = new WC_Payments_UPE_Checkout( - $mock_upe_gateway, - $this->mock_woopay_utilities, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_fraud_service - ); - - $this->assertSame( - $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'], - [ - 'card' => [ - 'isReusable' => true, - 'title' => 'Credit card / debit card', - 'icon' => $this->icon_url, - 'showSaveOption' => true, - 'countries' => [], - 'upePaymentIntentData' => null, - 'upeSetupIntentData' => null, - 'testingInstructions' => 'Test mode: use the test VISA card 4242424242424242 with any expiry date and CVC. Other payment methods may redirect to a Stripe test page to authorize payment. More test card numbers are listed here.', - 'forceNetworkSavedCards' => false, - ], - 'link' => [ - 'isReusable' => true, - 'title' => 'Link', - 'icon' => $this->icon_url, - 'showSaveOption' => true, - 'countries' => [], - 'upePaymentIntentData' => null, - 'upeSetupIntentData' => null, - 'testingInstructions' => '', - 'forceNetworkSavedCards' => false, - ], - ] - ); + $this->assertSame( $this->mock_upe_gateway->get_payment_method_ids_enabled_at_checkout(), [] ); } /** diff --git a/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php b/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php index 2d6e888229e..40cc78eda7d 100644 --- a/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php +++ b/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php @@ -16,7 +16,6 @@ use WCPay\Exceptions\Amount_Too_Small_Exception; use WCPay\WooPay\WooPay_Utilities; use WCPay\Session_Rate_Limiter; -use WCPay\WC_Payments_UPE_Checkout; use WCPAY_UnitTestCase; use WC_Helper_Order; use WC_Helper_Intention; @@ -34,7 +33,6 @@ use WCPay\Core\Server\Request\Get_Intention; use WCPay\Core\Server\Request\Update_Intention; use WCPay\Duplicate_Payment_Prevention_Service; -use WCPay\WC_Payments_Checkout; use WCPay\Payment_Information; use WC_Payments; use WC_Payments_Localization_Service; @@ -102,13 +100,6 @@ class UPE_Split_Payment_Gateway_Test extends WCPAY_UnitTestCase { */ private $mock_payment_gateways; - /** - * WC_Payments_Checkout - * - * @var WC_Payments_Checkout|MockObject - */ - private $mock_legacy_checkout; - /** * WC_Payments_Account instance. * @@ -253,10 +244,6 @@ public function set_up() { ->disableOriginalConstructor() ->getMock(); - $this->mock_legacy_checkout = $this->getMockBuilder( WC_Payments_Checkout::class ) - ->disableOriginalConstructor() - ->getMock(); - $this->mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class ); $this->order_service = new WC_Payments_Order_Service( $this->mock_api_client ); @@ -373,36 +360,19 @@ public function tear_down() { * * @return void */ - public function test_payment_fields_outputs_fields() { - $checkout = new WC_Payments_UPE_Checkout( - $this->mock_payment_gateways[ Payment_Method::CARD ], - $this->mock_woopay_utilities, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_fraud_service - ); - $checkout->init_hooks(); - - $registered_card_gateway = WC_Payments::get_registered_card_gateway(); - WC_Payments::set_registered_card_gateway( $this->mock_payment_gateways[ Payment_Method::CARD ] ); - + public function test_display_gateway_html_for_multiple_gateways() { foreach ( $this->mock_payment_gateways as $payment_method_id => $mock_payment_gateway ) { - $mock_payment_gateway - ->method( 'get_payment_method_ids_enabled_at_checkout' ) - ->willReturn( [] ); /** * This tests each payment method output separately without concatenating the output * into 1 single buffer. Each iteration has 1 assertion. */ ob_start(); - $mock_payment_gateway->payment_fields(); + $mock_payment_gateway->display_gateway_html(); $actual_output = ob_get_contents(); ob_end_clean(); $this->assertStringContainsString( '
', $actual_output ); } - - WC_Payments::set_registered_card_gateway( $registered_card_gateway ); } public function test_should_not_use_stripe_platform_on_checkout_page_for_upe() { @@ -1727,438 +1697,6 @@ public function test_process_payment_caches_mimimum_amount_and_displays_error_up } } - public function test_no_save_option_for_non_sepa_upe() { - $payment_methods_with_no_save_option = [ - Payment_Method::BANCONTACT, - Payment_Method::EPS, - Payment_Method::GIROPAY, - Payment_Method::IDEAL, - Payment_Method::P24, - Payment_Method::SOFORT, - ]; - - foreach ( $payment_methods_with_no_save_option as $payment_method ) { - $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_methods[ $payment_method ], - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service, - ] - ) - ->setMethods( - [ - 'get_payment_method_ids_enabled_at_checkout', - 'wc_payments_get_payment_method_by_id', - 'wc_payments_get_payment_gateway_by_id', - 'is_saved_cards_enabled', - 'is_subscription_item_in_cart', - ] - ) - ->getMock(); - - $mock_upe_gateway->method( 'get_payment_method_ids_enabled_at_checkout' ) - ->willReturn( [ $payment_method ] ); - - $mock_upe_gateway - ->method( 'wc_payments_get_payment_method_by_id' ) - ->with( $payment_method ) - ->willReturn( $this->mock_payment_methods[ $payment_method ] ); - - $mock_upe_gateway - ->method( 'wc_payments_get_payment_gateway_by_id' ) - ->with( $payment_method ) - ->willReturn( $this->mock_payment_gateways[ $payment_method ] ); - - $upe_checkout = new WC_Payments_UPE_Checkout( - $mock_upe_gateway, - $this->mock_woopay_utilities, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_fraud_service - ); - - $this->assertSame( $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'][ $payment_method ]['showSaveOption'], false ); - } - } - - public function test_no_save_option_for_sepa_due_to_subscription_cart() { - $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_methods[ Payment_Method::SEPA ], - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service, - ] - ) - ->setMethods( - [ - 'get_payment_method_ids_enabled_at_checkout', - 'wc_payments_get_payment_method_by_id', - 'wc_payments_get_payment_gateway_by_id', - 'is_saved_cards_enabled', - 'is_subscription_item_in_cart', - ] - ) - ->getMock(); - - // saved cards enabled. - $mock_upe_gateway - ->method( 'is_saved_cards_enabled' ) - ->will( - $this->returnValue( true ) - ); - - // there is a subscription item in cart, which should disable the save option checkbox for a payment method. - $mock_upe_gateway - ->method( 'is_subscription_item_in_cart' ) - ->will( - $this->returnValue( true ) - ); - - $mock_upe_gateway->method( 'get_payment_method_ids_enabled_at_checkout' ) - ->willReturn( [ Payment_Method::SEPA ] ); - - $mock_upe_gateway - ->method( 'wc_payments_get_payment_method_by_id' ) - ->with( Payment_Method::SEPA ) - ->willReturn( $this->mock_payment_methods[ Payment_Method::SEPA ] ); - - $mock_upe_gateway - ->method( 'wc_payments_get_payment_gateway_by_id' ) - ->with( Payment_Method::SEPA ) - ->willReturn( $this->mock_payment_gateways[ Payment_Method::SEPA ] ); - - $upe_checkout = new WC_Payments_UPE_Checkout( - $mock_upe_gateway, - $this->mock_woopay_utilities, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_fraud_service - ); - - $this->assertSame( $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'][ Payment_Method::SEPA ]['showSaveOption'], false ); - } - - public function test_no_save_option_for_sepa_due_to_saved_cards_disabled() { - $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_methods[ Payment_Method::SEPA ], - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service, - ] - ) - ->setMethods( - [ - 'get_payment_method_ids_enabled_at_checkout', - 'wc_payments_get_payment_method_by_id', - 'wc_payments_get_payment_gateway_by_id', - 'is_saved_cards_enabled', - 'is_subscription_item_in_cart', - ] - ) - ->getMock(); - - // saved cards disabled. - $mock_upe_gateway - ->method( 'is_saved_cards_enabled' ) - ->will( - $this->returnValue( false ) - ); - - // no subscription item in cart. - $mock_upe_gateway - ->method( 'is_subscription_item_in_cart' ) - ->will( - $this->returnValue( false ) - ); - - $mock_upe_gateway->method( 'get_payment_method_ids_enabled_at_checkout' ) - ->willReturn( [ Payment_Method::SEPA ] ); - - $mock_upe_gateway - ->method( 'wc_payments_get_payment_method_by_id' ) - ->with( Payment_Method::SEPA ) - ->willReturn( $this->mock_payment_methods[ Payment_Method::SEPA ] ); - - $mock_upe_gateway - ->method( 'wc_payments_get_payment_gateway_by_id' ) - ->with( Payment_Method::SEPA ) - ->willReturn( $this->mock_payment_gateways[ Payment_Method::SEPA ] ); - - $upe_checkout = new WC_Payments_UPE_Checkout( - $mock_upe_gateway, - $this->mock_woopay_utilities, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_fraud_service - ); - - $this->assertSame( $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'][ Payment_Method::SEPA ]['showSaveOption'], false ); - } - - public function test_save_option_for_sepa_debit() { - $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_methods[ Payment_Method::SEPA ], - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service, - ] - ) - ->setMethods( - [ - 'get_payment_method_ids_enabled_at_checkout', - 'wc_payments_get_payment_method_by_id', - 'wc_payments_get_payment_gateway_by_id', - 'is_saved_cards_enabled', - 'is_subscription_item_in_cart', - ] - ) - ->getMock(); - - $mock_upe_gateway->method( 'get_payment_method_ids_enabled_at_checkout' ) - ->willReturn( [ Payment_Method::SEPA ] ); - - $mock_upe_gateway - ->method( 'wc_payments_get_payment_method_by_id' ) - ->with( Payment_Method::SEPA ) - ->willReturn( $this->mock_payment_methods[ Payment_Method::SEPA ] ); - - $mock_upe_gateway - ->method( 'wc_payments_get_payment_gateway_by_id' ) - ->with( Payment_Method::SEPA ) - ->willReturn( $this->mock_payment_gateways[ Payment_Method::SEPA ] ); - - // saved cards enabled. - $mock_upe_gateway - ->method( 'is_saved_cards_enabled' ) - ->will( - $this->returnValue( true ) - ); - - // no subscription items in cart. - $mock_upe_gateway - ->method( 'is_subscription_item_in_cart' ) - ->will( - $this->returnValue( false ) - ); - - $upe_checkout = new WC_Payments_UPE_Checkout( - $mock_upe_gateway, - $this->mock_woopay_utilities, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_fraud_service - ); - - $this->assertSame( $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'][ Payment_Method::SEPA ]['showSaveOption'], false ); - } - - public function test_remove_link_payment_method_if_card_disabled() { - $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_methods[ Payment_Method::LINK ], - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service, - ] - ) - ->setMethods( - [ - 'get_upe_enabled_payment_method_statuses', - 'get_upe_enabled_payment_method_ids', - 'wc_payments_get_payment_method_by_id', - ] - ) - ->getMock(); - - $mock_upe_gateway - ->expects( $this->once() ) - ->method( 'get_upe_enabled_payment_method_ids' ) - ->will( - $this->returnValue( [ 'link' ] ) - ); - $mock_upe_gateway - ->expects( $this->once() ) - ->method( 'get_upe_enabled_payment_method_statuses' ) - ->will( - $this->returnValue( [ 'link_payments' => [ 'status' => 'active' ] ] ) - ); - $mock_upe_gateway - ->method( 'wc_payments_get_payment_method_by_id' ) - ->with( Payment_Method::LINK ) - ->willReturn( $this->mock_payment_methods[ Payment_Method::LINK ] ); - - $upe_checkout = new WC_Payments_UPE_Checkout( - $mock_upe_gateway, - $this->mock_woopay_utilities, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_fraud_service - ); - - $this->assertSame( $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'], [] ); - } - - public function test_link_payment_method_if_card_enabled() { - $this->mock_cache->method( 'get' )->willReturn( [ 'is_deferred_intent_creation_upe_enabled' => true ] ); - WC_Helper_Site_Currency::$mock_site_currency = 'USD'; - - $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class ) - ->setConstructorArgs( - [ - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_methods[ Payment_Method::CARD ], - $this->mock_payment_methods, - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service, - ] - ) - ->setMethods( - [ - 'get_upe_enabled_payment_method_statuses', - 'get_upe_enabled_payment_method_ids', - 'wc_payments_get_payment_method_by_id', - 'wc_payments_get_payment_gateway_by_id', - ] - ) - ->getMock(); - $mock_upe_gateway - ->expects( $this->once() ) - ->method( 'get_upe_enabled_payment_method_ids' ) - ->will( - $this->returnValue( [ 'card', 'link' ] ) - ); - $mock_upe_gateway - ->expects( $this->once() ) - ->method( 'get_upe_enabled_payment_method_statuses' ) - ->will( - $this->returnValue( - [ - 'link_payments' => [ 'status' => 'active' ], - 'card_payments' => [ 'status' => 'active' ], - ] - ) - ); - - $this->mock_payment_methods[ Payment_Method::LINK ]->expects( $this->any() ) - ->method( 'get_icon' ) - ->will( - $this->returnValue( $this->icon_url ) - ); - - $mock_upe_gateway - ->method( 'wc_payments_get_payment_method_by_id' ) - ->willReturnMap( - [ - [ Payment_Method::CARD, $this->mock_payment_methods[ Payment_Method::CARD ] ], - [ Payment_Method::LINK, $this->mock_payment_methods[ Payment_Method::LINK ] ], - ] - ); - - $mock_upe_gateway - ->method( 'wc_payments_get_payment_gateway_by_id' ) - ->willReturnCallback( - function ( $payment_method ) { - if ( Payment_Method::CARD === $payment_method ) { - return $this->mock_payment_gateways[ Payment_Method::CARD ]; - } elseif ( Payment_Method::LINK === $payment_method ) { - return $this->mock_payment_gateways[ Payment_Method::LINK ]; - } - } - ); - - $upe_checkout = new WC_Payments_UPE_Checkout( - $mock_upe_gateway, - $this->mock_woopay_utilities, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_fraud_service - ); - - $this->assertSame( - $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'], - [ - 'card' => [ - 'isReusable' => true, - 'title' => 'Credit card / debit card', - 'icon' => null, - 'showSaveOption' => true, - 'countries' => [], - 'upePaymentIntentData' => null, - 'upeSetupIntentData' => null, - 'testingInstructions' => 'Test mode: use the test VISA card 4242424242424242 with any expiry date and CVC. Other payment methods may redirect to a Stripe test page to authorize payment. More test card numbers are listed here.', - 'forceNetworkSavedCards' => false, - ], - 'link' => [ - 'isReusable' => true, - 'title' => 'Link', - 'icon' => $this->icon_url, - 'showSaveOption' => true, - 'countries' => [], - 'upePaymentIntentData' => null, - 'upeSetupIntentData' => null, - 'testingInstructions' => '', - 'forceNetworkSavedCards' => false, - ], - ] - ); - } - public function test_remove_upe_setup_intent_from_session() { // Two payment methods (SEPA and giropay) are enabled. $sepa_setup_intent_key = UPE_Split_Payment_Gateway::KEY_UPE_SETUP_INTENT . '_sepa_debit'; diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay.php b/tests/unit/test-class-wc-payment-gateway-wcpay.php index c1bb486f296..8efcc4ccb0e 100644 --- a/tests/unit/test-class-wc-payment-gateway-wcpay.php +++ b/tests/unit/test-class-wc-payment-gateway-wcpay.php @@ -33,7 +33,6 @@ use WCPay\Payment_Methods\UPE_Split_Payment_Gateway; use WCPay\WooPay\WooPay_Utilities; use WCPay\Session_Rate_Limiter; -use WCPay\WC_Payments_Checkout; // Need to use WC_Mock_Data_Store. require_once dirname( __FILE__ ) . '/helpers/class-wc-mock-wc-data-store.php'; @@ -49,7 +48,7 @@ class WC_Payment_Gateway_WCPay_Test extends WCPAY_UnitTestCase { /** * System under test. * - * @var WC_Payment_Gateway_WCPay + * @var UPE_Split_Payment_Gateway */ private $wcpay_gateway; @@ -95,6 +94,13 @@ class WC_Payment_Gateway_WCPay_Test extends WCPAY_UnitTestCase { */ private $mock_rate_limiter; + /** + * UPE_Payment_Method instance. + * + * @var UPE_Payment_Method|MockObject + */ + private $mock_payment_method; + /** * WC_Payments_Order_Service instance. * @@ -109,12 +115,6 @@ class WC_Payment_Gateway_WCPay_Test extends WCPAY_UnitTestCase { */ private $woopay_utilities; - /** - * WC_Payments_Checkout instance. - * @var WC_Payments_Checkout - */ - private $payments_checkout; - /** * Duplicate_Payment_Prevention_Service instance. * @var Duplicate_Payment_Prevention_Service|MockObject @@ -171,6 +171,16 @@ public function set_up() { $this->mock_api_client->expects( $this->any() )->method( 'get_blog_id' )->willReturn( 1234567 ); $this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class ); + $this->mock_wcpay_account + ->expects( $this->any() ) + ->method( 'get_fees' ) + ->willReturn( + [ + 'card' => [ + 'base' => 0.1, + ], + ] + ); // Mock the main class's cache service. $this->_cache = WC_Payments::get_database_cache(); @@ -190,32 +200,39 @@ public function set_up() { $this->mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class ); $this->mock_localization_service = $this->createMock( WC_Payments_Localization_Service::class ); - $this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class ); + $this->mock_localization_service->expects( $this->any() ) + ->method( 'get_country_locale_data' ) + ->willReturn( + [ + 'currency_code' => 'usd', + ] + ); + $this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class ); - $this->wcpay_gateway = new WC_Payment_Gateway_WCPay( + $this->mock_payment_method = $this->getMockBuilder( CC_Payment_Method::class ) + ->setConstructorArgs( [ $this->mock_token_service ] ) + ->setMethods( [ 'is_subscription_item_in_cart' ] ) + ->getMock(); + + $this->wcpay_gateway = new UPE_Split_Payment_Gateway( $this->mock_api_client, $this->mock_wcpay_account, $this->mock_customer_service, $this->mock_token_service, $this->mock_action_scheduler_service, + $this->mock_payment_method, + [ 'card' => $this->mock_payment_method ], $this->mock_rate_limiter, $this->order_service, $this->mock_dpps, $this->mock_localization_service, $this->mock_fraud_service ); + WC_Payments::set_gateway( $this->wcpay_gateway ); $this->woopay_utilities = new WooPay_Utilities(); - $this->payments_checkout = new WC_Payments_Checkout( - $this->wcpay_gateway, - $this->woopay_utilities, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_fraud_service - ); - // Mock the level3 service to always return an empty array. $mock_level3_service = $this->createMock( Level3Service::class ); $mock_level3_service->expects( $this->any() ) @@ -368,83 +385,58 @@ public function test_attach_exchange_info_to_order_with_different_order_currency $this->assertEquals( 0.853, $order->get_meta( '_wcpay_multi_currency_stripe_exchange_rate' ) ); } - public function test_save_card_checkbox_not_displayed_when_saved_cards_disabled() { - $this->wcpay_gateway->update_option( 'saved_cards', 'no' ); - - $this->refresh_payments_checkout(); - + public function test_save_payment_method_checkbox_displayed() { // Use a callback to get and test the output (also suppresses the output buffering being printed to the CLI). $this->setOutputCallback( function ( $output ) { - $result = preg_match_all( '/.*.*/', $output ); + $input_element = preg_match_all( '/.*.*/', $output ); + $parent_div = preg_match_all( '/
.*<\/div>/s', $output ); - $this->assertSame( 0, $result ); + $this->assertSame( 1, $input_element ); + $this->assertSame( 1, $parent_div ); } ); - $this->wcpay_gateway->payment_fields(); + $this->wcpay_gateway->save_payment_method_checkbox(); } - public function test_save_card_checkbox_not_displayed_for_non_logged_in_users() { - $this->wcpay_gateway->update_option( 'saved_cards', 'yes' ); - wp_set_current_user( 0 ); - - $this->refresh_payments_checkout(); - - // Use a callback to get and test the output (also suppresses the output buffering being printed to the CLI). + public function test_save_payment_method_checkbox_not_displayed_when_force_checked() { $this->setOutputCallback( function ( $output ) { - $result = preg_match_all( '/.*.*/', $output ); + $input_element = preg_match_all( '/.*.*/', $output ); + $parent_div = preg_match_all( '/
.*<\/div>/s', $output ); - $this->assertSame( 0, $result ); + $this->assertSame( 1, $input_element ); + $this->assertSame( 1, $parent_div ); } ); - $this->wcpay_gateway->payment_fields(); + $this->wcpay_gateway->save_payment_method_checkbox( true ); } - public function test_save_card_checkbox_displayed_for_logged_in_users() { - $this->wcpay_gateway->update_option( 'saved_cards', 'yes' ); - wp_set_current_user( 1 ); - - $this->refresh_payments_checkout(); + public function test_save_payment_method_checkbox_not_displayed_when_stripe_platform_account_used() { + // Setup the test so that should_use_stripe_platform_on_checkout_page returns true. + $this->mock_cache->method( 'get' )->willReturn( [ 'platform_checkout_eligible' => true ] ); + $this->wcpay_gateway->update_option( 'platform_checkout', 'yes' ); + add_filter( 'woocommerce_is_checkout', '__return_true' ); + WC()->session->init(); + WC()->cart->add_to_cart( WC_Helper_Product::create_simple_product()->get_id(), 1 ); + WC()->cart->calculate_totals(); - // Use a callback to get and test the output (also suppresses the output buffering being printed to the CLI). $this->setOutputCallback( function ( $output ) { - $result = preg_match_all( '/.*.*/', $output ); + $input_element = preg_match_all( '/.*.*/', $output ); + $parent_div = preg_match_all( '/
.*<\/div>/s', $output ); - $this->assertSame( 1, $result ); + $this->assertSame( 1, $input_element ); + $this->assertSame( 1, $parent_div ); } ); - $this->wcpay_gateway->payment_fields(); - } + $this->wcpay_gateway->save_payment_method_checkbox( false ); - public function test_fraud_prevention_token_added_when_enabled() { - $token_value = 'test-token'; - $fraud_prevention_service_mock = $this->get_fraud_prevention_service_mock(); - $fraud_prevention_service_mock - ->expects( $this->once() ) - ->method( 'is_enabled' ) - ->willReturn( true ); - $fraud_prevention_service_mock - ->expects( $this->once() ) - ->method( 'get_token' ) - ->willReturn( $token_value ); - - $this->refresh_payments_checkout(); - - // Use a callback to get and test the output (also suppresses the output buffering being printed to the CLI). - $this->setOutputCallback( - function ( $output ) use ( $token_value ) { - $result = preg_match_all( '/.*.*/', $output ); - - $this->assertSame( 0, $result ); - } - ); - - $this->wcpay_gateway->payment_fields(); + remove_filter( 'woocommerce_is_checkout', '__return_true' ); + WC()->cart->empty_cart(); } public function test_capture_charge_success() { @@ -466,7 +458,7 @@ public function test_capture_charge_success() { ->with( $mock_intent->get_amount() ); $capture_intent_request->expects( $this->once() ) ->method( 'set_metadata' ) - ->with( [ 'gateway_type' => 'legacy_card' ] ); + ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] ); $capture_intent_request->expects( $this->once() ) ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention() ); @@ -521,7 +513,7 @@ public function test_capture_charge_success_non_usd() { ->with( $mock_intent->get_amount() ); $capture_intent_request->expects( $this->once() ) ->method( 'set_metadata' ) - ->with( [ 'gateway_type' => 'legacy_card' ] ); + ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] ); $capture_intent_request->expects( $this->once() ) ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention( [ 'currency' => 'eur' ] ) ); @@ -573,7 +565,7 @@ public function test_capture_charge_failure() { ->with( $mock_intent->get_amount() ); $capture_intent_request->expects( $this->once() ) ->method( 'set_metadata' ) - ->with( [ 'gateway_type' => 'legacy_card' ] ); + ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] ); $capture_intent_request->expects( $this->once() ) ->method( 'format_response' ) ->willReturn( $mock_intent ); @@ -628,7 +620,7 @@ public function test_capture_charge_failure_non_usd() { ->with( $mock_intent->get_amount() ); $capture_intent_request->expects( $this->once() ) ->method( 'set_metadata' ) - ->with( [ 'gateway_type' => 'legacy_card' ] ); + ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] ); $capture_intent_request->expects( $this->once() ) ->method( 'format_response' ) ->willReturn( $mock_intent ); @@ -685,7 +677,7 @@ public function test_capture_charge_api_failure() { ->with( $mock_intent->get_amount() ); $capture_intent_request->expects( $this->once() ) ->method( 'set_metadata' ) - ->with( [ 'gateway_type' => 'legacy_card' ] ); + ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] ); $capture_intent_request->expects( $this->once() ) ->method( 'format_response' ) ->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) ); @@ -747,7 +739,7 @@ public function test_capture_charge_api_failure_non_usd() { ->with( $mock_intent->get_amount() ); $capture_intent_request->expects( $this->once() ) ->method( 'set_metadata' ) - ->with( [ 'gateway_type' => 'legacy_card' ] ); + ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] ); $capture_intent_request->expects( $this->once() ) ->method( 'format_response' ) ->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) ); @@ -805,7 +797,7 @@ public function test_capture_charge_expired() { ->with( $mock_intent->get_amount() ); $capture_intent_request->expects( $this->once() ) ->method( 'set_metadata' ) - ->with( [ 'gateway_type' => 'legacy_card' ] ); + ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] ); $capture_intent_request->expects( $this->once() ) ->method( 'format_response' ) ->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) ); @@ -863,7 +855,7 @@ public function test_capture_charge_metadata() { ->with( $mock_intent->get_amount() ); $capture_intent_request->expects( $this->once() ) ->method( 'set_metadata' ) - ->with( [ 'gateway_type' => 'legacy_card' ] ); + ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] ); $capture_intent_request->expects( $this->once() ) ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention() ); @@ -912,7 +904,7 @@ public function test_capture_charge_without_level3() { ->with( $mock_intent->get_amount() ); $capture_intent_request->expects( $this->once() ) ->method( 'set_metadata' ) - ->with( [ 'gateway_type' => 'legacy_card' ] ); + ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] ); $capture_intent_request->expects( $this->once() ) ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention() ); @@ -1284,7 +1276,7 @@ public function test_add_payment_method_no_customer() { $this->assertEquals( 'error', $result['result'] ); } - public function test_add_payment_method_canceled_intent() { + public function test_add_payment_method_cancelled_intent() { $_POST = [ 'wcpay-setup-intent' => 'sti_mock' ]; $this->mock_customer_service @@ -1576,22 +1568,6 @@ public function test_process_payment_for_order_rejects_with_cached_minimum_amoun } public function test_mandate_data_not_added_to_payment_intent_if_not_required() { - // Mandate data is required for SEPA and Stripe Link only, hence initializing the gateway with a CC payment method should not add mandate data. - $gateway = new UPE_Split_Payment_Gateway( - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - new CC_Payment_Method( $this->mock_token_service ), - [], - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service - ); - WC_Payments::set_gateway( $gateway ); $payment_method = 'woocommerce_payments_sepa_debit'; $order = WC_Helper_Order::create_order(); $order->set_currency( 'USD' ); @@ -1609,27 +1585,13 @@ public function test_mandate_data_not_added_to_payment_intent_if_not_required() $request->expects( $this->never() ) ->method( 'set_mandate_data' ); - $gateway->process_payment_for_order( WC()->cart, $pi ); - WC_Payments::set_gateway( $this->wcpay_gateway ); + // Mandate data is required for SEPA and Stripe Link only, $this->wcpay_gateway is created with card hence mandate data should not be added. + $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); } public function test_mandate_data_added_to_payment_intent_if_required() { - // Mandate data is required for SEPA and Stripe Link, hence initializing the gateway with a SEPA payment method should add mandate data. - $gateway = new UPE_Split_Payment_Gateway( - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - new Sepa_Payment_Method( $this->mock_token_service ), - [], - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service - ); - WC_Payments::set_gateway( $gateway ); + // Mandate data is required for SEPA and Stripe Link, hence creating the gateway with a SEPA payment method should add mandate data. + $gateway = $this->create_gateway_with( new Sepa_Payment_Method( $this->mock_token_service ) ); $payment_method = 'woocommerce_payments_sepa_debit'; $order = WC_Helper_Order::create_order(); $order->set_currency( 'USD' ); @@ -1659,26 +1621,11 @@ function ( $data ) { ); $gateway->process_payment_for_order( WC()->cart, $pi ); - WC_Payments::set_gateway( $this->wcpay_gateway ); } public function test_mandate_data_not_added_to_setup_intent_request_when_link_is_disabled() { - $gateway = new UPE_Split_Payment_Gateway( - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - new CC_Payment_Method( $this->mock_token_service ), - [], - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service - ); - WC_Payments::set_gateway( $gateway ); - $gateway->settings['upe_enabled_payment_method_ids'] = [ 'card' ]; + // Disabled link is reflected in upe_enabled_payment_method_ids: when link is disabled, the array contains only card. + $this->wcpay_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card' ]; $payment_method = 'woocommerce_payments'; $order = WC_Helper_Order::create_order(); @@ -1714,27 +1661,11 @@ public function test_mandate_data_not_added_to_setup_intent_request_when_link_is $request->expects( $this->never() ) ->method( 'set_mandate_data' ); - $gateway->process_payment_for_order( WC()->cart, $pi ); - WC_Payments::set_gateway( $this->wcpay_gateway ); + $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); } public function test_mandate_data_added_to_setup_intent_request_when_link_is_enabled() { - $gateway = new UPE_Split_Payment_Gateway( - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - new CC_Payment_Method( $this->mock_token_service ), - [], - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service - ); - WC_Payments::set_gateway( $gateway ); - $gateway->settings['upe_enabled_payment_method_ids'] = [ 'card', 'link' ]; + $this->wcpay_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card', 'link' ]; $payment_method = 'woocommerce_payments'; $order = WC_Helper_Order::create_order(); @@ -1780,8 +1711,8 @@ function ( $data ) { ) ); - $gateway->process_payment_for_order( WC()->cart, $pi ); - WC_Payments::set_gateway( $this->wcpay_gateway ); + $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); + $this->wcpay_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card' ]; } public function test_process_payment_for_order_cc_payment_method() { @@ -1872,7 +1803,7 @@ public function test_process_payment_caches_mimimum_amount_and_displays_error_up $request->expects( $this->once() ) ->method( 'set_metadata' ) - ->with( [ 'gateway_type' => 'legacy_card' ] ); + ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] ); $request->expects( $this->once() ) ->method( 'format_response' ) @@ -2039,7 +1970,6 @@ public function test_is_woopay_enabled_returns_true() { add_filter( 'woocommerce_is_checkout', '__return_true' ); $this->assertTrue( $this->woopay_utilities->should_enable_woopay( $this->wcpay_gateway ) ); - $this->assertTrue( $this->payments_checkout->get_payment_fields_js_config()['isWooPayEnabled'] ); remove_filter( 'woocommerce_is_checkout', '__return_true' ); } @@ -2056,90 +1986,6 @@ public function test_should_use_stripe_platform_on_checkout_page_not_woopay() { $this->assertFalse( $this->wcpay_gateway->should_use_stripe_platform_on_checkout_page() ); } - public function test_force_network_saved_cards_is_returned_as_true_if_should_use_stripe_platform() { - $mock_wcpay_gateway = $this->get_partial_mock_for_gateway( [ 'should_use_stripe_platform_on_checkout_page' ] ); - - $mock_wcpay_gateway - ->expects( $this->once() ) - ->method( 'should_use_stripe_platform_on_checkout_page' ) - ->willReturn( true ); - - $registered_card_gateway = WC_Payments::get_registered_card_gateway(); - WC_Payments::set_registered_card_gateway( $mock_wcpay_gateway ); - - $payments_checkout = new WC_Payments_Checkout( - $mock_wcpay_gateway, - $this->woopay_utilities, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_fraud_service - ); - - $this->assertTrue( $payments_checkout->get_payment_fields_js_config()['forceNetworkSavedCards'] ); - WC_Payments::set_registered_card_gateway( $registered_card_gateway ); - } - - public function test_registered_gateway_replaced_by_gateway_if_not_initialized() { - // Set the registered gateway to null to simulate the case where the gateway is not initialized and thus should be replaced by $mock_wcpay_gateway. - WC_Payments::set_registered_card_gateway( null ); - - $mock_wcpay_gateway = $this->get_partial_mock_for_gateway( [ 'should_use_stripe_platform_on_checkout_page' ] ); - - $mock_wcpay_gateway - ->expects( $this->once() ) - ->method( 'should_use_stripe_platform_on_checkout_page' ) - ->willReturn( true ); - - $payments_checkout = new WC_Payments_Checkout( - $mock_wcpay_gateway, - $this->woopay_utilities, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_fraud_service - ); - - $this->assertTrue( $payments_checkout->get_payment_fields_js_config()['forceNetworkSavedCards'] ); - } - - public function test_force_network_saved_cards_is_returned_as_false_if_should_not_use_stripe_platform() { - $mock_wcpay_gateway = $this->get_partial_mock_for_gateway( [ 'should_use_stripe_platform_on_checkout_page' ] ); - - $mock_wcpay_gateway - ->expects( $this->once() ) - ->method( 'should_use_stripe_platform_on_checkout_page' ) - ->willReturn( false ); - - $registered_card_gateway = WC_Payments::get_registered_card_gateway(); - WC_Payments::set_registered_card_gateway( $mock_wcpay_gateway ); - - $payments_checkout = new WC_Payments_Checkout( - $mock_wcpay_gateway, - $this->woopay_utilities, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_fraud_service - ); - - $this->assertFalse( $payments_checkout->get_payment_fields_js_config()['forceNetworkSavedCards'] ); - WC_Payments::set_registered_card_gateway( $registered_card_gateway ); - } - - public function test_is_woopay_enabled_returns_false_if_ineligible() { - $this->mock_cache->method( 'get' )->willReturn( [ 'platform_checkout_eligible' => false ] ); - $this->assertFalse( $this->payments_checkout->get_payment_fields_js_config()['isWooPayEnabled'] ); - } - - public function test_is_woopay_enabled_returns_false_if_ineligible_and_enabled() { - $this->wcpay_gateway->update_option( 'platform_checkout', 'yes' ); - $this->assertFalse( $this->payments_checkout->get_payment_fields_js_config()['isWooPayEnabled'] ); - } - - public function test_return_icon_url() { - $returned_icon = $this->payments_checkout->get_payment_fields_js_config()['icon']; - $this->assertNotNull( $returned_icon ); - $this->assertStringContainsString( 'assets/images/payment-methods/cc.svg', $returned_icon ); - } - public function is_woopay_falsy_value_provider() { return [ [ '0' ], @@ -2191,7 +2037,7 @@ public function test_is_in_test_mode() { * @return MockObject|WC_Payment_Gateway_WCPay */ private function get_partial_mock_for_gateway( array $methods = [] ) { - return $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) + return $this->getMockBuilder( UPE_Split_Payment_Gateway::class ) ->setConstructorArgs( [ $this->mock_api_client, @@ -2199,6 +2045,8 @@ private function get_partial_mock_for_gateway( array $methods = [] ) { $this->mock_customer_service, $this->mock_token_service, $this->mock_action_scheduler_service, + $this->mock_payment_method, + [ $this->mock_payment_method ], $this->mock_rate_limiter, $this->order_service, $this->mock_dpps, @@ -2545,17 +2393,20 @@ private function create_charge_object() { return new WC_Payments_API_Charge( $this->mock_charge_id, 1500, $created ); } - private function refresh_payments_checkout() { - remove_all_actions( 'wc_payments_add_payment_fields' ); - - $this->payments_checkout = new WC_Payments_Checkout( - $this->wcpay_gateway, - $this->woopay_utilities, + private function create_gateway_with( $payment_method ) { + return new UPE_Split_Payment_Gateway( + $this->mock_api_client, $this->mock_wcpay_account, $this->mock_customer_service, + $this->mock_token_service, + $this->mock_action_scheduler_service, + $payment_method, + [ $payment_method ], + $this->mock_rate_limiter, + $this->order_service, + $this->mock_dpps, + $this->mock_localization_service, $this->mock_fraud_service ); - - $this->payments_checkout->init_hooks(); } } diff --git a/tests/unit/test-class-wc-payments-checkout.php b/tests/unit/test-class-wc-payments-checkout.php new file mode 100644 index 00000000000..49906d2edea --- /dev/null +++ b/tests/unit/test-class-wc-payments-checkout.php @@ -0,0 +1,569 @@ +mock_wcpay_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class ) + ->onlyMethods( [ 'get_account_domestic_currency', 'get_payment_method_ids_enabled_at_checkout', 'should_use_stripe_platform_on_checkout_page', 'should_support_saved_payments', 'is_saved_cards_enabled', 'save_payment_method_checkbox', 'get_account_statement_descriptor', 'get_icon_url', 'get_payment_method_ids_enabled_at_checkout_filtered_by_fees', 'is_subscription_item_in_cart', 'wc_payments_get_payment_method_by_id', 'display_gateway_html' ] ) + ->disableOriginalConstructor() + ->getMock(); + $this->mock_wcpay_gateway->id = 'woocommerce_payments'; + $this->mock_wcpay_gateway + ->method( 'get_account_domestic_currency' ) + ->willReturn( 'USD' ); + + $this->mock_woopay_utilities = $this->createMock( WooPay_Utilities::class ); + $this->mock_woopay_utilities = $this->getMockBuilder( WooPay_Utilities::class ) + ->onlyMethods( [ 'should_enable_woopay', 'should_enable_woopay_on_cart_or_checkout' ] ) + ->disableOriginalConstructor() + ->getMock(); + $this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class ); + $this->mock_customer_service = $this->createMock( WC_Payments_Customer_Service::class ); + $this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class ); + + $this->mock_wcpay_gateway + ->method( 'get_account_statement_descriptor' ) + ->willReturn( 'localhost' ); + + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout_filtered_by_fees' ) + ->willReturn( [] ); + + $this->mock_token_service = $this->createMock( WC_Payments_Token_Service::class ); + + // This is needed to ensure that only the mocked gateway is always used by the checkout class. + $this->default_gateway = WC_Payments::get_registered_card_gateway(); + WC_Payments::set_registered_card_gateway( $this->mock_wcpay_gateway ); + WC_Payments::set_gateway( $this->mock_wcpay_gateway ); + + // Use a callback to suppresses the output buffering being printed to the CLI. + $this->setOutputCallback( + function ( $output ) { + preg_match_all( '/.*.*/s', $output ); + } + ); + + $this->system_under_test = new WC_Payments_Checkout( $this->mock_wcpay_gateway, $this->mock_woopay_utilities, $this->mock_wcpay_account, $this->mock_customer_service, $this->mock_fraud_service ); + } + + public function tear_down() { + parent::tear_down(); + WC_Payments::set_registered_card_gateway( $this->default_gateway ); + WC_Payments::set_gateway( $this->default_gateway ); + } + + public function test_fraud_prevention_token_added_when_prevention_service_enabled() { + $token_value = 'test-token'; + $fraud_prevention_service_mock = $this->getMockBuilder( Fraud_Prevention_Service::class ) + ->disableOriginalConstructor() + ->getMock(); + + $fraud_prevention_service_mock + ->expects( $this->once() ) + ->method( 'is_enabled' ) + ->willReturn( true ); + + $fraud_prevention_service_mock + ->expects( $this->once() ) + ->method( 'get_token' ) + ->willReturn( $token_value ); + + Fraud_Prevention_Service::set_instance( $fraud_prevention_service_mock ); + + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( [] ); + + // Use a callback to get and test the output (also suppresses the output buffering being printed to the CLI). + $this->setOutputCallback( + function ( $output ) use ( $token_value ) { + $result = preg_match_all( '/]*type="hidden"[^>]*name="wcpay-fraud-prevention-token"[^>]*value="' . preg_quote( $token_value, '/' ) . '"[^>]*>/', $output ); + + $this->assertSame( 1, $result ); + } + ); + + $this->system_under_test->payment_fields(); + } + + public function test_fraud_prevention_token_not_added_when_prevention_service_disabled() { + $token_value = 'test-token'; + $fraud_prevention_service_mock = $this->getMockBuilder( Fraud_Prevention_Service::class ) + ->disableOriginalConstructor() + ->getMock(); + + $fraud_prevention_service_mock + ->expects( $this->once() ) + ->method( 'is_enabled' ) + ->willReturn( true ); + + Fraud_Prevention_Service::set_instance( $fraud_prevention_service_mock ); + + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( [] ); + + // Use a callback to get and test the output (also suppresses the output buffering being printed to the CLI). + $this->setOutputCallback( + function ( $output ) use ( $token_value ) { + $result = preg_match_all( '/]*type="hidden"[^>]*name="wcpay-fraud-prevention-token"[^>]*value="' . preg_quote( $token_value, '/' ) . '"[^>]*>/', $output ); + + $this->assertSame( 0, $result ); + } + ); + + $this->system_under_test->payment_fields(); + } + + public function test_save_payment_method_checkbox_not_called_when_saved_cards_disabled() { + // given: prepare the dependencies. + wp_set_current_user( 1 ); + + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( [] ); + + $this->mock_wcpay_gateway + ->method( 'is_saved_cards_enabled' ) + ->willReturn( false ); + + // then: check that the save_payment_method_checkbox method was called. + $this->mock_wcpay_gateway + ->expects( $this->never() ) + ->method( 'save_payment_method_checkbox' ); + + $this->system_under_test->payment_fields(); + } + + public function test_save_payment_method_checkbox_not_called_for_non_logged_in_user() { + // given: prepare the dependencies. + wp_set_current_user( 0 ); + + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( [] ); + + $this->mock_wcpay_gateway + ->method( 'is_saved_cards_enabled' ) + ->willReturn( true ); + + $this->mock_wcpay_gateway + ->expects( $this->once() ) + ->method( 'should_support_saved_payments' ) + ->willReturn( true ); + + // then: check that the save_payment_method_checkbox method was called. + $this->mock_wcpay_gateway + ->expects( $this->never() ) + ->method( 'save_payment_method_checkbox' ); + + $this->system_under_test->payment_fields(); + } + + public function test_save_payment_method_checkbox_called() { + // given: prepare the dependencies. + wp_set_current_user( 1 ); + + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( [] ); + + $this->mock_wcpay_gateway + ->method( 'is_saved_cards_enabled' ) + ->willReturn( true ); + + $this->mock_wcpay_gateway + ->expects( $this->once() ) + ->method( 'should_support_saved_payments' ) + ->willReturn( true ); + + // then: check that the save_payment_method_checkbox method was called. + $this->mock_wcpay_gateway + ->expects( $this->once() ) + ->method( 'save_payment_method_checkbox' ); + + $this->system_under_test->payment_fields(); + } + + public function test_display_gateway_html_called() { + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( [] ); + + $this->mock_wcpay_gateway + ->expects( $this->once() ) + ->method( 'display_gateway_html' ); + + $this->system_under_test->payment_fields(); + } + + public function test_is_woopay_enabled_when_should_enable_woopay_and_enable_it_on_cart_or_checkout() { + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( [] ); + + $this->mock_woopay_utilities->method( 'should_enable_woopay' )->willReturn( true ); + $this->mock_woopay_utilities->method( 'should_enable_woopay_on_cart_or_checkout' )->willReturn( true ); + + $is_woopay_enabled = $this->system_under_test->get_payment_fields_js_config()['isWooPayEnabled']; + $this->assertTrue( $is_woopay_enabled ); + } + + public function test_is_woopay_enabled_false_when_should_not_enable_woopay() { + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( [] ); + + $this->mock_woopay_utilities->method( 'should_enable_woopay' )->willReturn( false ); + $this->mock_woopay_utilities->method( 'should_enable_woopay_on_cart_or_checkout' )->willReturn( true ); + + $is_woopay_enabled = $this->system_under_test->get_payment_fields_js_config()['isWooPayEnabled']; + $this->assertFalse( $is_woopay_enabled ); + } + + public function test_is_woopay_enabled_false_when_should_enable_woopay_but_not_enable_it_on_cart_or_checkout() { + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( [] ); + + $this->mock_woopay_utilities->method( 'should_enable_woopay' )->willReturn( true ); + $this->mock_woopay_utilities->method( 'should_enable_woopay_on_cart_or_checkout' )->willReturn( false ); + + $is_woopay_enabled = $this->system_under_test->get_payment_fields_js_config()['isWooPayEnabled']; + $this->assertFalse( $is_woopay_enabled ); + } + + public function test_return_icon_url() { + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( [] ); + + $this->mock_wcpay_gateway + ->method( 'get_icon_url' ) + ->willReturn( 'assets/images/payment-methods/cc.svg' ); + + $returned_icon = $this->system_under_test->get_payment_fields_js_config()['icon']; + + $this->assertNotNull( $returned_icon ); + $this->assertStringContainsString( 'assets/images/payment-methods/cc.svg', $returned_icon ); + } + + public function test_force_network_saved_cards_enabled_when_should_use_stripe_platform() { + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( [] ); + + $this->mock_wcpay_gateway + ->method( 'should_use_stripe_platform_on_checkout_page' ) + ->willReturn( true ); + + $force_network_saved_cards = $this->system_under_test->get_payment_fields_js_config()['forceNetworkSavedCards']; + $this->assertTrue( $force_network_saved_cards ); + } + + public function test_force_network_saved_cards_disabled_when_should_not_use_stripe_platform() { + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( [] ); + + $this->mock_wcpay_gateway + ->method( 'should_use_stripe_platform_on_checkout_page' ) + ->willReturn( false ); + + $force_network_saved_cards = $this->system_under_test->get_payment_fields_js_config()['forceNetworkSavedCards']; + $this->assertFalse( $force_network_saved_cards ); + } + + public function test_link_payment_method_provided_when_card_enabled() { + $icon_url = 'test-icon-url'; + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( [ 'card', 'link' ] ); + + $this->mock_wcpay_gateway + ->method( 'is_saved_cards_enabled' ) + ->willReturn( true ); + + $this->mock_wcpay_gateway + ->method( 'is_subscription_item_in_cart' ) + ->willReturn( false ); + + $payment_methods = [ + 'card' => [ 'base' => 0.1 ], + 'link' => [ + 'base' => 0.1, + ], + ]; + + $card_pm = $this->getMockBuilder( CC_Payment_Method::class ) + ->setConstructorArgs( [ $this->mock_token_service ] ) + ->onlyMethods( [ 'get_icon' ] ) + ->getMock(); + + $link_pm = $this->getMockBuilder( Link_Payment_Method::class ) + ->setConstructorArgs( [ $this->mock_token_service ] ) + ->onlyMethods( [ 'get_icon' ] ) + ->getMock(); + + $card_pm->expects( $this->any() ) + ->method( 'get_icon' ) + ->will( + $this->returnValue( $icon_url ) + ); + + $link_pm->expects( $this->any() ) + ->method( 'get_icon' ) + ->will( + $this->returnValue( $icon_url ) + ); + + $this->mock_wcpay_gateway + ->method( 'wc_payments_get_payment_method_by_id' ) + ->withConsecutive( [ 'card' ], [ 'link' ] ) + ->willReturnOnConsecutiveCalls( $card_pm, $link_pm ); + + $this->mock_wcpay_account + ->expects( $this->any() ) + ->method( 'get_fees' ) + ->willReturn( $payment_methods ); + + $this->assertSame( + $this->system_under_test->get_payment_fields_js_config()['paymentMethodsConfig'], + [ + 'card' => [ + 'isReusable' => true, + 'title' => 'Credit card / debit card', + 'icon' => $icon_url, + 'showSaveOption' => true, + 'countries' => [], + 'upePaymentIntentData' => null, + 'upeSetupIntentData' => null, + 'testingInstructions' => 'Test mode: use the test VISA card 4242424242424242 with any expiry date and CVC. Other payment methods may redirect to a Stripe test page to authorize payment. More test card numbers are listed here.', + 'forceNetworkSavedCards' => false, + ], + 'link' => [ + 'isReusable' => true, + 'title' => 'Link', + 'icon' => $icon_url, + 'showSaveOption' => true, + 'countries' => [], + 'upePaymentIntentData' => null, + 'upeSetupIntentData' => null, + 'testingInstructions' => '', + 'forceNetworkSavedCards' => false, + ], + ] + ); + } + + /** + * @dataProvider non_reusable_payment_method_provider + */ + public function test_no_save_option_for_non_reusable_payment_method( $payment_method_id, $payment_method_class ) { + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( + [ + $payment_method_id, + ] + ); + + $this->mock_wcpay_gateway + ->method( 'wc_payments_get_payment_method_by_id' ) + ->willReturn( + new $payment_method_class( $this->mock_token_service ) + ); + + $this->assertSame( false, $this->system_under_test->get_payment_fields_js_config()['paymentMethodsConfig'][ $payment_method_id ]['showSaveOption'] ); + } + + public function non_reusable_payment_method_provider() { + return [ + [ Payment_Method::BANCONTACT, Bancontact_Payment_Method::class ], + [ Payment_Method::EPS, Eps_Payment_Method::class ], + [ Payment_Method::GIROPAY, Giropay_Payment_Method::class ], + [ Payment_Method::IDEAL, Ideal_Payment_Method::class ], + [ Payment_Method::P24, P24_Payment_Method::class ], + [ Payment_Method::SOFORT, Sofort_Payment_Method::class ], + ]; + } + + public function test_no_save_option_for_reusable_payment_payment_with_subscription_in_cart() { + $this->mock_wcpay_gateway + ->method( 'is_subscription_item_in_cart' ) + ->willReturn( true ); + + $this->mock_wcpay_gateway + ->method( 'is_saved_cards_enabled' ) + ->willReturn( true ); + + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( + [ + Payment_Method::CARD, + ] + ); + + $this->mock_wcpay_gateway + ->method( 'wc_payments_get_payment_method_by_id' ) + ->willReturn( + new CC_Payment_Method( $this->mock_token_service ) + ); + $this->assertSame( false, $this->system_under_test->get_payment_fields_js_config()['paymentMethodsConfig'][ Payment_Method::CARD ]['showSaveOption'] ); + } + + public function test_no_save_option_for_reusable_payment_payment_but_with_saved_cards_disabled() { + $this->mock_wcpay_gateway + ->method( 'is_subscription_item_in_cart' ) + ->willReturn( false ); + + $this->mock_wcpay_gateway + ->method( 'is_saved_cards_enabled' ) + ->willReturn( false ); + + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( + [ + Payment_Method::CARD, + ] + ); + + $this->mock_wcpay_gateway + ->method( 'wc_payments_get_payment_method_by_id' ) + ->willReturn( + new CC_Payment_Method( $this->mock_token_service ) + ); + $this->assertSame( false, $this->system_under_test->get_payment_fields_js_config()['paymentMethodsConfig'][ Payment_Method::CARD ]['showSaveOption'] ); + } + + public function test_save_option_for_reusable_payment_payment() { + $this->mock_wcpay_gateway + ->method( 'is_subscription_item_in_cart' ) + ->willReturn( false ); + + $this->mock_wcpay_gateway + ->method( 'is_saved_cards_enabled' ) + ->willReturn( true ); + + $this->mock_wcpay_gateway + ->expects( $this->any() ) + ->method( 'get_payment_method_ids_enabled_at_checkout' ) + ->willReturn( + [ + Payment_Method::CARD, + ] + ); + + $this->mock_wcpay_gateway + ->method( 'wc_payments_get_payment_method_by_id' ) + ->willReturn( + new CC_Payment_Method( $this->mock_token_service ) + ); + $this->assertSame( true, $this->system_under_test->get_payment_fields_js_config()['paymentMethodsConfig'][ Payment_Method::CARD ]['showSaveOption'] ); + } +}