diff --git a/changelog/refactor-google-pay-apple-pay-settings-storage b/changelog/refactor-google-pay-apple-pay-settings-storage new file mode 100644 index 00000000000..8b614f78813 --- /dev/null +++ b/changelog/refactor-google-pay-apple-pay-settings-storage @@ -0,0 +1,4 @@ +Significance: patch +Type: update + +refactor: Google Pay/Apple Pay settings storage consistency diff --git a/includes/admin/class-wc-rest-payments-settings-controller.php b/includes/admin/class-wc-rest-payments-settings-controller.php index 0a1b2812121..2dbcf5b9164 100644 --- a/includes/admin/class-wc-rest-payments-settings-controller.php +++ b/includes/admin/class-wc-rest-payments-settings-controller.php @@ -509,7 +509,7 @@ public function get_settings(): WP_REST_Response { 'account_branding_primary_color' => $this->wcpay_gateway->get_option( 'account_branding_primary_color' ), 'account_branding_secondary_color' => $this->wcpay_gateway->get_option( 'account_branding_secondary_color' ), 'account_domestic_currency' => $this->wcpay_gateway->get_option( 'account_domestic_currency' ), - 'is_payment_request_enabled' => 'yes' === $this->wcpay_gateway->get_option( 'payment_request' ), + 'is_payment_request_enabled' => $this->wcpay_gateway->is_payment_request_enabled(), 'is_apple_google_pay_in_payment_methods_options_enabled' => 'yes' === $this->wcpay_gateway->get_option( 'apple_google_pay_in_payment_methods_options' ), 'is_debug_log_enabled' => 'yes' === $this->wcpay_gateway->get_option( 'enable_logging' ), 'payment_request_enabled_locations' => $this->wcpay_gateway->get_option( 'payment_request_button_locations' ), @@ -870,7 +870,24 @@ private function update_is_payment_request_enabled( WP_REST_Request $request ) { $is_payment_request_enabled = $request->get_param( 'is_payment_request_enabled' ); - $this->wcpay_gateway->update_option( 'payment_request', $is_payment_request_enabled ? 'yes' : 'no' ); + // Update Google Pay and Apple Pay enabled settings to keep them in sync. + $google_pay_gateway = WC_Payments::get_payment_gateway_by_id( \WCPay\PaymentMethods\Configs\Definitions\GooglePayDefinition::get_id() ); + $apple_pay_gateway = WC_Payments::get_payment_gateway_by_id( \WCPay\PaymentMethods\Configs\Definitions\ApplePayDefinition::get_id() ); + if ( $is_payment_request_enabled ) { + if ( $google_pay_gateway ) { + $google_pay_gateway->enable(); + } + if ( $apple_pay_gateway ) { + $apple_pay_gateway->enable(); + } + } else { + if ( $google_pay_gateway ) { + $google_pay_gateway->disable(); + } + if ( $apple_pay_gateway ) { + $apple_pay_gateway->disable(); + } + } } /** diff --git a/includes/class-duplicates-detection-service.php b/includes/class-duplicates-detection-service.php index d7ffb5c7a72..49d044e6aba 100644 --- a/includes/class-duplicates-detection-service.php +++ b/includes/class-duplicates-detection-service.php @@ -141,7 +141,10 @@ private function search_for_payment_request_buttons() { if ( strpos( $gateway->id, $keyword ) !== false ) { $this->gateways_qualified_by_duplicates_detector[ $prb_payment_method ][] = $gateway->id; break; - } elseif ( 'yes' === $gateway->get_option( 'payment_request' ) && in_array( $gateway->id, [ 'woocommerce_payments', 'stripe' ], true ) ) { + } elseif ( 'woocommerce_payments' === $gateway->id && method_exists( $gateway, 'is_payment_request_enabled' ) && $gateway->is_payment_request_enabled() ) { + $this->gateways_qualified_by_duplicates_detector[ $prb_payment_method ][] = $gateway->id; + break; + } elseif ( 'stripe' === $gateway->id && 'yes' === $gateway->get_option( 'payment_request' ) ) { $this->gateways_qualified_by_duplicates_detector[ $prb_payment_method ][] = $gateway->id; break; } elseif ( 'yes' === $gateway->get_option( 'express_checkout_enabled' ) ) { diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php index 1114c47152a..cef969c0ae6 100644 --- a/includes/class-wc-payment-gateway-wcpay.php +++ b/includes/class-wc-payment-gateway-wcpay.php @@ -441,20 +441,6 @@ public function get_form_fields() { 'type' => 'title', 'description' => '', ], - 'payment_request' => [ - 'title' => __( 'Enable/disable', 'woocommerce-payments' ), - 'label' => sprintf( - /* translators: 1) br tag 2) Stripe anchor tag 3) Apple anchor tag */ - __( 'Enable payment request buttons (Apple Pay, Google Pay, and more). %1$sBy using Apple Pay, you agree to %2$s and %3$s\'s Terms of Service.', 'woocommerce-payments' ), - '
', - 'Stripe', - 'Apple' - ), - 'type' => 'checkbox', - 'description' => __( 'If enabled, users will be able to pay using Apple Pay, Google Pay or the Payment Request API if supported by the browser.', 'woocommerce-payments' ), - 'default' => empty( get_option( 'woocommerce_woocommerce_payments_settings' ) ) ? 'yes' : 'no', // Enable by default for new installations only. - 'desc_tip' => true, - ], 'payment_request_button_type' => [ 'title' => __( 'Button type', 'woocommerce-payments' ), 'type' => 'select', @@ -959,7 +945,18 @@ public function is_saved_cards_enabled() { * @return bool Whether the setting to show the payment request buttons is enabled or not. */ public function is_payment_request_enabled() { - return 'yes' === $this->get_option( 'payment_request' ); + $google_pay_gateway = WC_Payments::get_payment_gateway_by_id( \WCPay\PaymentMethods\Configs\Definitions\GooglePayDefinition::get_id() ); + if ( $google_pay_gateway && $google_pay_gateway->is_enabled() ) { + return true; + } + + // Fallback, just in case. + $apple_pay_gateway = WC_Payments::get_payment_gateway_by_id( \WCPay\PaymentMethods\Configs\Definitions\ApplePayDefinition::get_id() ); + if ( $apple_pay_gateway && $apple_pay_gateway->is_enabled() ) { + return true; + } + + return false; } /** diff --git a/includes/class-wc-payments-account.php b/includes/class-wc-payments-account.php index af62d5e7f26..56c129a771f 100644 --- a/includes/class-wc-payments-account.php +++ b/includes/class-wc-payments-account.php @@ -2726,7 +2726,7 @@ private function get_store_setup_details(): array { 'debug_log_enabled' => 'yes' === $gateway->get_option( 'enable_logging' ), 'payment_request' => [ - 'enabled' => 'yes' === $gateway->get_option( 'payment_request' ), + 'enabled' => $gateway->is_payment_request_enabled(), 'enabled_locations' => $gateway->get_option( 'payment_request_button_locations' ), 'button_type' => $gateway->get_option( 'payment_request_button_type' ), 'button_size' => $gateway->get_option( 'payment_request_button_size' ), diff --git a/includes/class-wc-payments-apple-pay-registration.php b/includes/class-wc-payments-apple-pay-registration.php index 07ae5385881..3c8376b3f61 100644 --- a/includes/class-wc-payments-apple-pay-registration.php +++ b/includes/class-wc-payments-apple-pay-registration.php @@ -49,11 +49,11 @@ class WC_Payments_Apple_Pay_Registration { private $domain_name; /** - * Stores Apple Pay domain verification issues. + * Option name for storing Apple Pay domain verification errors. * * @var string */ - private $apple_pay_verify_notice; + const APPLE_PAY_DOMAIN_ERROR_OPTION = 'wcpay_apple_pay_domain_error'; /** * Initialize class actions. @@ -63,11 +63,10 @@ class WC_Payments_Apple_Pay_Registration { * @param WC_Payment_Gateway_WCPay $gateway WooCommerce Payments gateway. */ public function __construct( WC_Payments_API_Client $payments_api_client, WC_Payments_Account $account, WC_Payment_Gateway_WCPay $gateway ) { - $this->domain_name = wp_parse_url( get_site_url(), PHP_URL_HOST ); - $this->apple_pay_verify_notice = ''; - $this->payments_api_client = $payments_api_client; - $this->account = $account; - $this->gateway = $gateway; + $this->domain_name = wp_parse_url( get_site_url(), PHP_URL_HOST ); + $this->payments_api_client = $payments_api_client; + $this->account = $account; + $this->gateway = $gateway; } /** @@ -88,30 +87,47 @@ public function init() { add_action( 'admin_init', [ $this, 'verify_domain_on_domain_name_change' ] ); add_action( 'woocommerce_woocommerce_payments_admin_notices', [ $this, 'display_error_notice' ] ); - add_action( 'add_option_woocommerce_woocommerce_payments_settings', [ $this, 'verify_domain_on_new_settings' ], 10, 2 ); - add_action( 'update_option_woocommerce_woocommerce_payments_settings', [ $this, 'verify_domain_on_updated_settings' ], 10, 2 ); + + // Listen to Apple Pay gateway settings changes for domain verification. + add_action( 'add_option_woocommerce_woocommerce_payments_apple_pay_settings', [ $this, 'verify_domain_on_new_settings' ], 10, 2 ); + add_action( 'update_option_woocommerce_woocommerce_payments_apple_pay_settings', [ $this, 'verify_domain_on_updated_settings' ], 10, 2 ); + + // Also listen to main gateway settings changes, since it's a prerequisite for Apple Pay. + add_action( 'update_option_woocommerce_woocommerce_payments_settings', [ $this, 'verify_domain_on_updated_main_gateway_settings' ], 10, 2 ); } /** - * Whether the gateway and Express Checkout Buttons (prerequisites for Apple Pay) are enabled. + * Whether Apple Pay is enabled. + * + * Checks both the main gateway and the Apple Pay gateway are enabled. * - * @return bool Whether Apple Pay required settings are enabled. + * @return bool Whether Apple Pay is enabled. */ private function is_enabled() { - return $this->gateway->is_enabled() && 'yes' === $this->gateway->get_option( 'payment_request' ); + // Check if the main gateway is enabled. + if ( ! $this->gateway->is_enabled() ) { + return false; + } + + // Check if the Apple Pay gateway is enabled. + $apple_pay_gateway = WC_Payments::get_payment_gateway_by_id( 'apple_pay' ); + + if ( ! $apple_pay_gateway ) { + return false; + } + + return $apple_pay_gateway->is_enabled(); } /** - * Whether the gateway and Express Checkout Buttons were enabled in previous settings. + * Whether Apple Pay was enabled in previous settings. * - * @param array|null $prev_settings Gateway settings. + * @param array|null $prev_settings Apple Pay gateway settings. * - * @return bool Whether Apple Pay required settings are enabled. + * @return bool Whether Apple Pay was enabled. */ private function was_enabled( $prev_settings ) { - $gateway_enabled = 'yes' === ( $prev_settings['enabled'] ?? 'no' ); - $payment_request_enabled = 'yes' === ( $prev_settings['payment_request'] ?? 'no' ); - return $gateway_enabled && $payment_request_enabled; + return 'yes' === ( $prev_settings['enabled'] ?? 'no' ); } /** @@ -153,6 +169,7 @@ public function register_domain() { if ( isset( $registration_response['id'] ) && ( isset( $registration_response['apple_pay']['status'] ) && 'active' === $registration_response['apple_pay']['status'] ) ) { $this->gateway->update_option( 'apple_pay_verified_domain', $this->domain_name ); $this->gateway->update_option( 'apple_pay_domain_set', 'yes' ); + delete_option( self::APPLE_PAY_DOMAIN_ERROR_OPTION ); Logger::log( __( 'Your domain has been verified with Apple Pay!', 'woocommerce-payments' ) ); Tracker::track_admin( @@ -170,11 +187,10 @@ public function register_domain() { } catch ( API_Exception $e ) { $error = $e->getMessage(); } - // Display error message in notice. - $this->apple_pay_verify_notice = $error; $this->gateway->update_option( 'apple_pay_verified_domain', $this->domain_name ); $this->gateway->update_option( 'apple_pay_domain_set', 'no' ); + update_option( self::APPLE_PAY_DOMAIN_ERROR_OPTION, $error ); Logger::log( 'Error registering domain with Apple: ' . $error ); Tracker::track_admin( @@ -192,7 +208,7 @@ public function register_domain() { */ public function verify_domain_if_configured() { // If Express Checkout Buttons are not enabled, - // do not attempt to register domain. + // do not attempt to register the domain. if ( ! $this->is_enabled() ) { return; } @@ -218,12 +234,27 @@ public function verify_domain_on_new_settings( $option, $settings ) { * @param array $settings Settings after update. */ public function verify_domain_on_updated_settings( $prev_settings, $settings ) { - // If Gateway or Express Checkout Buttons weren't enabled, then might need to verify now. + // If Apple Pay wasn't enabled, then might need to verify now. if ( ! $this->was_enabled( $prev_settings ) ) { $this->verify_domain_if_configured(); } } + /** + * Conditionally process the Apple Pay domain verification after main gateway settings are updated. + * + * @param array $prev_settings Settings before update. + * @param array $settings Settings after update. + */ + public function verify_domain_on_updated_main_gateway_settings( $prev_settings, $settings ) { + $was_main_gateway_enabled = 'yes' === ( $prev_settings['enabled'] ?? 'no' ); + + // If main gateway wasn't enabled before, might need to verify now. + if ( ! $was_main_gateway_enabled ) { + $this->verify_domain_if_configured(); + } + } + /** * Display Apple Pay registration errors. */ @@ -232,29 +263,36 @@ public function display_error_notice() { return; } - $empty_notice = empty( $this->apple_pay_verify_notice ); $domain_set = $this->gateway->get_option( 'apple_pay_domain_set' ); + $error_notice = get_option( self::APPLE_PAY_DOMAIN_ERROR_OPTION, '' ); + $empty_notice = empty( $error_notice ); + // Don't display error notice if verification notice is empty and // apple_pay_domain_set option equals to '' or 'yes'. if ( $empty_notice && 'no' !== $domain_set ) { return; } + // Clear the error after retrieving it so it only displays once. + if ( ! $empty_notice ) { + delete_option( self::APPLE_PAY_DOMAIN_ERROR_OPTION ); + } + /** * Apple pay is enabled by default and domain verification initializes * when setting screen is displayed. So if domain verification is not set, * something went wrong so lets notify user. */ - $allowed_html = [ + $allowed_html = [ 'a' => [ 'href' => [], 'title' => [], ], ]; - $payment_request_button_text = __( 'Express checkouts:', 'woocommerce-payments' ); - $verification_failed_without_error = __( 'Apple Pay domain verification failed.', 'woocommerce-payments' ); - $verification_failed_with_error = __( 'Apple Pay domain verification failed with the following error:', 'woocommerce-payments' ); - $check_log_text = WC_Payments_Utils::esc_interpolated_html( + $verification_failed = $empty_notice + ? __( 'Apple Pay domain verification failed.', 'woocommerce-payments' ) + : __( 'Apple Pay domain verification failed with the following error:', 'woocommerce-payments' ); + $check_log_text = WC_Payments_Utils::esc_interpolated_html( /* translators: a: Link to the logs page */ __( 'Please check the logs for more details on this issue. Debug log must be enabled under Advanced settings to see recorded logs.', 'woocommerce-payments' ), [ @@ -271,20 +309,14 @@ public function display_error_notice() { ?>
- -

- - - -

- -

- - - -

-

apple_pay_verify_notice ) ), $allowed_html ); ?>

- +

+ + + +

+ +

+

update_is_woopay_enabled( false ); } - // Update gateway option with the Apple/Google Pay capability. + // Update Apple/Google Pay gateway enabled state. + $google_pay_gateway = WC_Payments::get_payment_gateway_by_id( \WCPay\PaymentMethods\Configs\Definitions\GooglePayDefinition::get_id() ); + $apple_pay_gateway = WC_Payments::get_payment_gateway_by_id( \WCPay\PaymentMethods\Configs\Definitions\ApplePayDefinition::get_id() ); if ( ! empty( $capabilities['apple_google'] ) || ( ! empty( $capabilities['apple_pay'] ) || ! empty( $capabilities['google_pay'] ) ) ) { - $gateway->update_option( 'payment_request', 'yes' ); + if ( $apple_pay_gateway ) { + $apple_pay_gateway->enable(); + } + if ( $google_pay_gateway ) { + $google_pay_gateway->enable(); + } } else { - $gateway->update_option( 'payment_request', 'no' ); + if ( $apple_pay_gateway ) { + $apple_pay_gateway->disable(); + } + if ( $google_pay_gateway ) { + $google_pay_gateway->disable(); + } } } diff --git a/includes/class-wc-payments-status.php b/includes/class-wc-payments-status.php index b9b7d5222f0..027ccfb055c 100644 --- a/includes/class-wc-payments-status.php +++ b/includes/class-wc-payments-status.php @@ -255,7 +255,7 @@ public function render_status_report_section() { gateway->get_option( 'payment_request' ); + $payment_request_enabled = $this->gateway->is_payment_request_enabled(); $payment_request_enabled_locations = $this->gateway->get_option( 'payment_request_button_locations', [] ); $payment_request_enabled_locations = empty( $payment_request_enabled_locations ) ? 'no locations enabled' : implode( ',', $payment_request_enabled_locations ); echo esc_html( $payment_request_enabled ? __( 'Enabled', 'woocommerce-payments' ) . ' (' . $payment_request_enabled_locations . ')' : __( 'Disabled', 'woocommerce-payments' ) ); diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php index 4fc36802462..91ec2504d63 100644 --- a/includes/class-wc-payments.php +++ b/includes/class-wc-payments.php @@ -702,6 +702,7 @@ function () { require_once __DIR__ . '/migrations/class-erase-bnpl-announcement-meta.php'; require_once __DIR__ . '/migrations/class-erase-deprecated-flags-and-options.php'; require_once __DIR__ . '/migrations/class-manual-capture-payment-method-settings-update.php'; + require_once __DIR__ . '/migrations/class-migrate-payment-request-to-express-checkout-enabled.php'; add_action( 'woocommerce_woocommerce_payments_updated', [ new Allowed_Payment_Request_Button_Types_Update( self::get_gateway() ), 'maybe_migrate' ] ); add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Allowed_Payment_Request_Button_Sizes_Update( self::get_gateway() ), 'maybe_migrate' ] ); add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Update_Service_Data_From_Server( self::get_account_service() ), 'maybe_migrate' ] ); @@ -714,6 +715,7 @@ function () { add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Erase_Bnpl_Announcement_Meta(), 'maybe_migrate' ] ); add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Erase_Deprecated_Flags_And_Options(), 'maybe_migrate' ] ); add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Manual_Capture_Payment_Method_Settings_Update( self::get_gateway(), self::get_payment_gateway_map() ), 'maybe_migrate' ] ); + add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Migrate_Payment_Request_To_Express_Checkout_Enabled(), 'maybe_migrate' ] ); include_once WCPAY_ABSPATH . '/includes/class-wc-payments-explicit-price-formatter.php'; WC_Payments_Explicit_Price_Formatter::init(); diff --git a/includes/express-checkout/class-wc-payments-express-checkout-button-display-handler.php b/includes/express-checkout/class-wc-payments-express-checkout-button-display-handler.php index fce76ee008d..aab7cdba567 100644 --- a/includes/express-checkout/class-wc-payments-express-checkout-button-display-handler.php +++ b/includes/express-checkout/class-wc-payments-express-checkout-button-display-handler.php @@ -82,7 +82,7 @@ public function init() { $this->express_checkout_button_handler->init(); $is_woopay_enabled = WC_Payments_Features::is_woopay_enabled(); - $is_payment_request_enabled = 'yes' === $this->gateway->get_option( 'payment_request' ); + $is_payment_request_enabled = $this->gateway->is_payment_request_enabled(); if ( $is_woopay_enabled ) { add_action( 'wc_ajax_wcpay_add_to_cart', [ $this->express_checkout_ajax_handler, 'ajax_add_to_cart' ] ); diff --git a/includes/express-checkout/class-wc-payments-express-checkout-button-handler.php b/includes/express-checkout/class-wc-payments-express-checkout-button-handler.php index 2004e5e6261..6fba3ec6883 100644 --- a/includes/express-checkout/class-wc-payments-express-checkout-button-handler.php +++ b/includes/express-checkout/class-wc-payments-express-checkout-button-handler.php @@ -76,8 +76,8 @@ public function init() { return; } - // Checks if Payment Request is enabled. - if ( 'yes' !== $this->gateway->get_option( 'payment_request' ) ) { + // Checks if Google Pay or Apple Pay are enabled. + if ( ! $this->gateway->is_payment_request_enabled() ) { return; } diff --git a/includes/migrations/class-migrate-payment-request-to-express-checkout-enabled.php b/includes/migrations/class-migrate-payment-request-to-express-checkout-enabled.php new file mode 100644 index 00000000000..fbaf1970654 --- /dev/null +++ b/includes/migrations/class-migrate-payment-request-to-express-checkout-enabled.php @@ -0,0 +1,69 @@ +migrate( $card_settings ); + } + + /** + * Does the actual migration as described in the class docblock. + * + * @param array $card_settings The card gateway settings. + */ + private function migrate( $card_settings ) { + $payment_request_enabled = ( $card_settings['payment_request'] ?? 'no' ) === 'yes' ? 'yes' : 'no'; + + update_option( 'woocommerce_woocommerce_payments_apple_pay_settings', [ 'enabled' => $payment_request_enabled ], true ); + update_option( 'woocommerce_woocommerce_payments_google_pay_settings', [ 'enabled' => $payment_request_enabled ], true ); + + unset( $card_settings['payment_request'] ); + update_option( 'woocommerce_woocommerce_payments_settings', $card_settings ); + } +} diff --git a/tests/WCPAY_UnitTestCase.php b/tests/WCPAY_UnitTestCase.php index d7f38e3b5d0..7ad81e522f7 100644 --- a/tests/WCPAY_UnitTestCase.php +++ b/tests/WCPAY_UnitTestCase.php @@ -173,4 +173,31 @@ function ( $argument ) use ( $request_class, $request ) { return $request; } + + /** + * Gets the current payment_gateway_map from WC_Payments. + * + * @return array|null The current payment_gateway_map. + */ + protected function get_payment_gateway_map() { + $reflection = new \ReflectionClass( WC_Payments::class ); + $property = $reflection->getProperty( 'payment_gateway_map' ); + $property->setAccessible( true ); + $value = $property->getValue( null ); + $property->setAccessible( false ); + return $value; + } + + /** + * Sets the payment_gateway_map in WC_Payments. + * + * @param array $gateway_map Associative array of gateway_id => gateway_instance. + */ + protected function set_payment_gateway_map( $gateway_map ) { + $reflection = new \ReflectionClass( WC_Payments::class ); + $property = $reflection->getProperty( 'payment_gateway_map' ); + $property->setAccessible( true ); + $property->setValue( null, $gateway_map ); + $property->setAccessible( false ); + } } diff --git a/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php b/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php index 255da0f3970..b185ca59931 100644 --- a/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php +++ b/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php @@ -115,21 +115,28 @@ class WC_REST_Payments_Settings_Controller_Test extends WCPAY_UnitTestCase { */ private $domestic_currency = 'usd'; + /** + * Backup of the original payment_gateway_map + * + * @var array + */ + private $original_payment_gateway_map; + /** * Pre-test setup */ public function set_up() { parent::set_up(); + $this->original_payment_gateway_map = $this->get_payment_gateway_map(); + self::$settings_route = '/wc/v3/' . ( $this->is_wpcom() ? 'sites/3/' : '' ) . 'payments/settings'; require_once __DIR__ . '/../helpers/class-wc-blocks-rest-api-registration-preventer.php'; WC_Blocks_REST_API_Registration_Preventer::prevent(); - // Set the user so that we can pass the authentication. wp_set_current_user( 1 ); - // Mock the main class's cache service. $this->_cache = WC_Payments::get_database_cache(); $this->mock_cache = $this->createMock( Database_Cache::class ); WC_Payments::set_database_cache( $this->mock_cache ); @@ -254,10 +261,9 @@ public function set_up() { public function tear_down() { parent::tear_down(); WC_Blocks_REST_API_Registration_Preventer::stop_preventing(); - // Restore the cache service in the main class. WC_Payments::set_database_cache( $this->_cache ); + $this->set_payment_gateway_map( $this->original_payment_gateway_map ); - // resetting to prevent test pollution. $reflection = new \ReflectionClass( PaymentMethodDefinitionRegistry::class ); $instance_property = $reflection->getProperty( 'instance' ); $instance_property->setAccessible( true ); @@ -1112,4 +1118,84 @@ public function account_business_support_phone_validation_provider() { ], ]; } + + public function test_update_is_payment_request_enabled_updates_google_pay_and_apple_pay() { + $google_pay_gateway = $this->createMock( WC_Payment_Gateway_WCPay::class ); + $google_pay_gateway->expects( $this->once() )->method( 'enable' ); + + $apple_pay_gateway = $this->createMock( WC_Payment_Gateway_WCPay::class ); + $apple_pay_gateway->expects( $this->once() )->method( 'enable' ); + + $this->set_payment_gateway_map( + [ + 'google_pay' => $google_pay_gateway, + 'apple_pay' => $apple_pay_gateway, + ] + ); + + $request = new WP_REST_Request(); + $request->set_param( 'is_payment_request_enabled', true ); + + $this->controller->update_settings( $request ); + } + + public function test_update_is_payment_request_disabled_updates_google_pay_and_apple_pay() { + $google_pay_gateway = $this->createMock( WC_Payment_Gateway_WCPay::class ); + $google_pay_gateway->expects( $this->once() )->method( 'disable' ); + + $apple_pay_gateway = $this->createMock( WC_Payment_Gateway_WCPay::class ); + $apple_pay_gateway->expects( $this->once() )->method( 'disable' ); + + $this->set_payment_gateway_map( + [ + 'google_pay' => $google_pay_gateway, + 'apple_pay' => $apple_pay_gateway, + ] + ); + + $request = new WP_REST_Request(); + $request->set_param( 'is_payment_request_enabled', false ); + + $this->controller->update_settings( $request ); + } + + public function test_get_is_payment_request_enabled_reads_from_google_pay() { + $google_pay_gateway = $this->createMock( WC_Payment_Gateway_WCPay::class ); + $google_pay_gateway->expects( $this->once() ) + ->method( 'is_enabled' ) + ->willReturn( true ); + + $this->set_payment_gateway_map( [ 'google_pay' => $google_pay_gateway ] ); + + $request = new WP_REST_Request(); + $response = $this->controller->get_settings( $request ); + $data = $response->get_data(); + + $this->assertTrue( $data['is_payment_request_enabled'] ); + } + + public function test_get_is_payment_request_enabled_falls_back_to_apple_pay() { + $apple_pay_gateway = $this->createMock( WC_Payment_Gateway_WCPay::class ); + $apple_pay_gateway->expects( $this->once() ) + ->method( 'is_enabled' ) + ->willReturn( true ); + + $this->set_payment_gateway_map( [ 'apple_pay' => $apple_pay_gateway ] ); + + $request = new WP_REST_Request(); + $response = $this->controller->get_settings( $request ); + $data = $response->get_data(); + + $this->assertTrue( $data['is_payment_request_enabled'] ); + } + + public function test_get_is_payment_request_enabled_returns_false_when_both_unavailable() { + $this->set_payment_gateway_map( [] ); + + $request = new WP_REST_Request(); + $response = $this->controller->get_settings( $request ); + $data = $response->get_data(); + + $this->assertFalse( $data['is_payment_request_enabled'] ); + } } diff --git a/tests/unit/duplicate-detection/class-test-gateway.php b/tests/unit/duplicate-detection/class-test-gateway.php index 99735fb8a7a..4f4818fe6e8 100644 --- a/tests/unit/duplicate-detection/class-test-gateway.php +++ b/tests/unit/duplicate-detection/class-test-gateway.php @@ -17,6 +17,13 @@ class Test_Gateway extends WC_Payment_Gateway { */ public $enabled = 'no'; + /** + * Value returned by is_payment_request_enabled(). + * + * @var bool + */ + public $is_payment_request_enabled_value = false; + public function __construct() { $this->form_fields = [ 'payment_request' => [ @@ -24,4 +31,13 @@ public function __construct() { ], ]; } + + /** + * Returns whether payment request is enabled. + * + * @return bool + */ + public function is_payment_request_enabled() { + return $this->is_payment_request_enabled_value; + } } diff --git a/tests/unit/duplicate-detection/test-class-duplicates-detection-service.php b/tests/unit/duplicate-detection/test-class-duplicates-detection-service.php index 50454ae8560..4f0ee2ad4e9 100644 --- a/tests/unit/duplicate-detection/test-class-duplicates-detection-service.php +++ b/tests/unit/duplicate-detection/test-class-duplicates-detection-service.php @@ -108,9 +108,9 @@ public function test_two_bnpls_enabled() { public function test_two_prbs_enabled() { $this->set_duplicates( CC_Payment_Method::PAYMENT_METHOD_STRIPE_ID, 'yes', 'yes' ); - $this->woopayments_gateway->update_option( 'payment_request', 'yes' ); - $this->woopayments_gateway->enabled = 'yes'; - $this->gateway_from_another_plugin->id = 'apple_pay'; + $this->woopayments_gateway->is_payment_request_enabled_value = true; + $this->woopayments_gateway->enabled = 'yes'; + $this->gateway_from_another_plugin->id = 'apple_pay'; $result = $this->service->find_duplicates(); diff --git a/tests/unit/migrations/test-class-migrate-payment-request-to-express-checkout-enabled.php b/tests/unit/migrations/test-class-migrate-payment-request-to-express-checkout-enabled.php new file mode 100644 index 00000000000..f851b1862c5 --- /dev/null +++ b/tests/unit/migrations/test-class-migrate-payment-request-to-express-checkout-enabled.php @@ -0,0 +1,141 @@ +migration = new Migrate_Payment_Request_To_Express_Checkout_Enabled(); + + delete_option( self::GOOGLE_PAY_OPTION_KEY ); + delete_option( self::APPLE_PAY_OPTION_KEY ); + update_option( 'woocommerce_woocommerce_payments_version', '10.3.0' ); + } + + public function tear_down() { + delete_option( 'woocommerce_woocommerce_payments_version' ); + delete_option( self::CARD_SETTINGS_OPTION_KEY ); + delete_option( self::GOOGLE_PAY_OPTION_KEY ); + delete_option( self::APPLE_PAY_OPTION_KEY ); + + parent::tear_down(); + } + + /** + * @dataProvider versions_that_should_skip_migration_provider + */ + public function test_it_does_nothing_if_version_is_10_4_0_or_higher( string $stored_version ) { + update_option( 'woocommerce_woocommerce_payments_version', $stored_version ); + update_option( self::CARD_SETTINGS_OPTION_KEY, [ 'payment_request' => 'yes' ] ); + + $this->migration->maybe_migrate(); + + $settings = get_option( self::CARD_SETTINGS_OPTION_KEY, [] ); + $this->assertArrayHasKey( 'payment_request', $settings ); + + $this->assertFalse( get_option( self::GOOGLE_PAY_OPTION_KEY ) ); + $this->assertFalse( get_option( self::APPLE_PAY_OPTION_KEY ) ); + } + + public function versions_that_should_skip_migration_provider(): array { + return [ + 'same version' => [ '10.4.0' ], + 'newer patch version' => [ '10.4.1' ], + 'newer minor version' => [ '10.5.0' ], + 'newer major version' => [ '11.0.0' ], + ]; + } + + public function test_it_does_nothing_if_payment_request_setting_does_not_exist() { + update_option( self::CARD_SETTINGS_OPTION_KEY, [] ); + + $this->migration->maybe_migrate(); + + $settings = get_option( self::CARD_SETTINGS_OPTION_KEY, [] ); + $this->assertArrayNotHasKey( 'payment_request', $settings ); + + $this->assertFalse( get_option( self::GOOGLE_PAY_OPTION_KEY ) ); + $this->assertFalse( get_option( self::APPLE_PAY_OPTION_KEY ) ); + } + + public function test_it_migrates_payment_request_enabled_to_google_pay_and_apple_pay() { + update_option( self::CARD_SETTINGS_OPTION_KEY, [ 'payment_request' => 'yes' ] ); + + $this->migration->maybe_migrate(); + + $settings = get_option( self::CARD_SETTINGS_OPTION_KEY, [] ); + $this->assertArrayNotHasKey( 'payment_request', $settings ); + + $google_pay_settings = get_option( self::GOOGLE_PAY_OPTION_KEY, [] ); + $apple_pay_settings = get_option( self::APPLE_PAY_OPTION_KEY, [] ); + $this->assertEquals( 'yes', $google_pay_settings['enabled'] ); + $this->assertEquals( 'yes', $apple_pay_settings['enabled'] ); + } + + public function test_it_migrates_payment_request_disabled_to_google_pay_and_apple_pay() { + update_option( self::CARD_SETTINGS_OPTION_KEY, [ 'payment_request' => 'no' ] ); + + $this->migration->maybe_migrate(); + + $settings = get_option( self::CARD_SETTINGS_OPTION_KEY, [] ); + $this->assertArrayNotHasKey( 'payment_request', $settings ); + + $google_pay_settings = get_option( self::GOOGLE_PAY_OPTION_KEY, [] ); + $apple_pay_settings = get_option( self::APPLE_PAY_OPTION_KEY, [] ); + $this->assertEquals( 'no', $google_pay_settings['enabled'] ); + $this->assertEquals( 'no', $apple_pay_settings['enabled'] ); + } + + public function test_it_handles_missing_payment_request_value_as_disabled() { + update_option( self::CARD_SETTINGS_OPTION_KEY, [ 'payment_request' => '' ] ); + + $this->migration->maybe_migrate(); + + $google_pay_settings = get_option( self::GOOGLE_PAY_OPTION_KEY, [] ); + $apple_pay_settings = get_option( self::APPLE_PAY_OPTION_KEY, [] ); + $this->assertEquals( 'no', $google_pay_settings['enabled'] ); + $this->assertEquals( 'no', $apple_pay_settings['enabled'] ); + } + + public function test_it_preserves_other_settings_in_card_gateway() { + update_option( + self::CARD_SETTINGS_OPTION_KEY, + [ + 'payment_request' => 'yes', + 'enabled' => 'yes', + 'test_mode' => 'no', + 'other_setting' => 'some_value', + ] + ); + + $this->migration->maybe_migrate(); + + $settings = get_option( self::CARD_SETTINGS_OPTION_KEY, [] ); + $this->assertArrayNotHasKey( 'payment_request', $settings ); + $this->assertEquals( 'yes', $settings['enabled'] ); + $this->assertEquals( 'no', $settings['test_mode'] ); + $this->assertEquals( 'some_value', $settings['other_setting'] ); + } +} diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay.php b/tests/unit/test-class-wc-payment-gateway-wcpay.php index 40d3a92c678..59b360fee13 100644 --- a/tests/unit/test-class-wc-payment-gateway-wcpay.php +++ b/tests/unit/test-class-wc-payment-gateway-wcpay.php @@ -200,12 +200,21 @@ class WC_Payment_Gateway_WCPay_Test extends WCPAY_UnitTestCase { */ private $wp_query_query_vars_backup; + /** + * Backup of the original payment_gateway_map + * + * @var array + */ + private $original_payment_gateway_map; + /** * Pre-test setup */ public function set_up() { parent::set_up(); + $this->original_payment_gateway_map = $this->get_payment_gateway_map(); + $this->mock_api_client = $this ->getMockBuilder( 'WC_Payments_API_Client' ) ->disableOriginalConstructor() @@ -301,6 +310,9 @@ public function tear_down() { // Restore the gateway in the main class. WC_Payments::set_gateway( $this->_gateway ); + // Restore the original payment gateway map to prevent test pollution. + $this->set_payment_gateway_map( $this->original_payment_gateway_map ); + // Fall back to an US store. update_option( 'woocommerce_store_postcode', '94110' ); $this->card_gateway->update_option( 'saved_cards', 'yes' ); @@ -4233,4 +4245,88 @@ function ( $gateway ) use ( $payment_method_id ) { ) ) )[0] ?? null; } + + public function test_is_payment_request_enabled_returns_true_when_google_pay_enabled() { + // Mock Google Pay gateway as enabled. + $google_pay_gateway = $this->createMock( WC_Payment_Gateway_WCPay::class ); + $google_pay_gateway->method( 'is_enabled' ) + ->willReturn( true ); + + // Mock WC_Payments::get_payment_gateway_by_id. + $this->set_payment_gateway_map( + [ + 'google_pay' => $google_pay_gateway, + ] + ); + + $this->assertTrue( $this->card_gateway->is_payment_request_enabled() ); + } + + public function test_is_payment_request_enabled_returns_true_when_apple_pay_enabled() { + // Mock Google Pay gateway as unavailable. + // Mock Apple Pay gateway as enabled. + $apple_pay_gateway = $this->createMock( WC_Payment_Gateway_WCPay::class ); + $apple_pay_gateway->method( 'is_enabled' ) + ->willReturn( true ); + + // Mock WC_Payments::get_payment_gateway_by_id. + $this->set_payment_gateway_map( + [ + 'apple_pay' => $apple_pay_gateway, + ] + ); + + $this->assertTrue( $this->card_gateway->is_payment_request_enabled() ); + } + + public function test_is_payment_request_enabled_returns_false_when_both_disabled() { + // Mock both gateways as disabled. + $google_pay_gateway = $this->createMock( WC_Payment_Gateway_WCPay::class ); + $google_pay_gateway->method( 'is_enabled' ) + ->willReturn( false ); + + $apple_pay_gateway = $this->createMock( WC_Payment_Gateway_WCPay::class ); + $apple_pay_gateway->method( 'is_enabled' ) + ->willReturn( false ); + + // Mock WC_Payments::get_payment_gateway_by_id. + $this->set_payment_gateway_map( + [ + 'google_pay' => $google_pay_gateway, + 'apple_pay' => $apple_pay_gateway, + ] + ); + + $this->assertFalse( $this->card_gateway->is_payment_request_enabled() ); + } + + public function test_is_payment_request_enabled_returns_false_when_both_unavailable() { + // Mock both gateways as unavailable by setting empty map. + $this->set_payment_gateway_map( [] ); + + $this->assertFalse( $this->card_gateway->is_payment_request_enabled() ); + } + + public function test_is_payment_request_enabled_prioritizes_google_pay() { + // Mock both gateways as enabled. + $google_pay_gateway = $this->createMock( WC_Payment_Gateway_WCPay::class ); + $google_pay_gateway->expects( $this->once() ) + ->method( 'is_enabled' ) + ->willReturn( true ); + + $apple_pay_gateway = $this->createMock( WC_Payment_Gateway_WCPay::class ); + // Apple Pay should not be checked since Google Pay returns true. + $apple_pay_gateway->expects( $this->never() ) + ->method( 'is_enabled' ); + + // Mock WC_Payments::get_payment_gateway_by_id. + $this->set_payment_gateway_map( + [ + 'google_pay' => $google_pay_gateway, + 'apple_pay' => $apple_pay_gateway, + ] + ); + + $this->assertTrue( $this->card_gateway->is_payment_request_enabled() ); + } } diff --git a/tests/unit/test-class-wc-payments-account.php b/tests/unit/test-class-wc-payments-account.php index 8223fbf311e..8f1b79067b9 100644 --- a/tests/unit/test-class-wc-payments-account.php +++ b/tests/unit/test-class-wc-payments-account.php @@ -3649,7 +3649,6 @@ function ( $key, $default = null ) { 'apple_google_pay_in_payment_methods_options' => 'yes', 'manual_capture' => 'no', 'enable_logging' => 'no', - 'payment_request' => 'yes', 'payment_request_button_locations' => [ 'product', 'cart' ], 'payment_request_button_type' => 'default', 'payment_request_button_size' => 'default', @@ -3663,6 +3662,7 @@ function ( $key, $default = null ) { } ); $mock_gateway->method( 'is_saved_cards_enabled' )->willReturn( true ); + $mock_gateway->method( 'is_payment_request_enabled' )->willReturn( true ); // Replace the real gateway with the mock. WC_Payments::set_gateway( $mock_gateway ); @@ -3699,7 +3699,6 @@ function ( $data ) use ( &$captured_data ) { $this->assertArrayHasKey( 'saved_cards_enabled', $captured_data ); $this->assertArrayHasKey( 'manual_capture_enabled', $captured_data ); $this->assertArrayHasKey( 'debug_log_enabled', $captured_data ); - $this->assertArrayHasKey( 'payment_request', $captured_data ); $this->assertArrayHasKey( 'woopay', $captured_data ); $this->assertArrayHasKey( 'multi_currency_enabled', $captured_data ); $this->assertArrayHasKey( 'stripe_billing_enabled', $captured_data ); diff --git a/tests/unit/test-class-wc-payments-apple-pay-registration.php b/tests/unit/test-class-wc-payments-apple-pay-registration.php index 46a375f88c1..6dce97454f4 100644 --- a/tests/unit/test-class-wc-payments-apple-pay-registration.php +++ b/tests/unit/test-class-wc-payments-apple-pay-registration.php @@ -35,12 +35,19 @@ class WC_Payments_Apple_Pay_Registration_Test extends WCPAY_UnitTestCase { private $mock_account; /** - * Mock Gateway. + * Mock Gateway (card gateway, passed to constructor). * * @var WC_Payment_Gateway_WCPay|PHPUnit_Framework_MockObject_MockObject */ private $mock_gateway; + /** + * Mock Apple Pay Gateway. + * + * @var WC_Payment_Gateway_WCPay|PHPUnit_Framework_MockObject_MockObject + */ + private $mock_apple_pay_gateway; + /** * Expected domain name for testing. * @@ -48,6 +55,13 @@ class WC_Payments_Apple_Pay_Registration_Test extends WCPAY_UnitTestCase { */ private $expected_domain; + /** + * Original payment_gateway_map. + * + * @var array + */ + private $original_payment_gateway_map; + /** * Pre-test setup */ @@ -68,17 +82,29 @@ public function set_up() { ->disableOriginalConstructor() ->getMock(); + $this->mock_apple_pay_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class ) + ->disableOriginalConstructor() + ->getMock(); + + $this->original_payment_gateway_map = $this->get_payment_gateway_map(); + $this->wc_apple_pay_registration = new WC_Payments_Apple_Pay_Registration( $this->mock_api_client, $this->mock_account, $this->mock_gateway ); $this->wc_apple_pay_registration->init_hooks(); } - public function test_verify_domain_on_new_settings_when_enabled() { - $this->mock_gateway->method( 'is_enabled' ) - ->willReturn( true ); + /** + * Tear down test. + */ + public function tear_down() { + $this->set_payment_gateway_map( $this->original_payment_gateway_map ); + delete_option( WC_Payments_Apple_Pay_Registration::APPLE_PAY_DOMAIN_ERROR_OPTION ); + parent::tear_down(); + } - $this->mock_gateway->method( 'get_option' ) - ->with( 'payment_request' ) - ->willReturn( 'yes' ); + public function test_verify_domain_on_new_settings_when_enabled() { + $this->mock_gateway->method( 'is_enabled' )->willReturn( true ); + $this->mock_apple_pay_gateway->method( 'is_enabled' )->willReturn( true ); + $this->set_payment_gateway_map( [ 'apple_pay' => $this->mock_apple_pay_gateway ] ); $this->mock_api_client->expects( $this->once() ) ->method( 'register_domain' ) @@ -99,61 +125,40 @@ public function test_verify_domain_on_new_settings_when_enabled() { $this->wc_apple_pay_registration->verify_domain_on_new_settings( 'option_name', - [ - 'enabled' => 'yes', - 'payment_request' => 'yes', - ] + [ 'enabled' => 'yes' ] ); } public function test_verify_domain_on_new_settings_when_not_enabled() { - $this->mock_gateway->method( 'is_enabled' ) - ->willReturn( false ); + $this->mock_apple_pay_gateway->method( 'is_enabled' )->willReturn( false ); + $this->set_payment_gateway_map( [ 'apple_pay' => $this->mock_apple_pay_gateway ] ); - $this->mock_api_client->expects( $this->never() ) - ->method( 'register_domain' ); - - $this->mock_gateway->expects( $this->never() ) - ->method( 'update_option' ); + $this->mock_api_client->expects( $this->never() )->method( 'register_domain' ); + $this->mock_gateway->expects( $this->never() )->method( 'update_option' ); $this->wc_apple_pay_registration->verify_domain_on_new_settings( 'option_name', - [ - 'enabled' => 'no', - 'payment_request' => 'yes', - ] + [ 'enabled' => 'no' ] ); } public function test_verify_domain_on_updated_settings_when_not_enabled() { - $this->mock_gateway->method( 'is_enabled' ) - ->willReturn( false ); - - $this->mock_api_client->expects( $this->never() ) - ->method( 'register_domain' ); + $this->mock_apple_pay_gateway->method( 'is_enabled' )->willReturn( false ); + $this->set_payment_gateway_map( [ 'apple_pay' => $this->mock_apple_pay_gateway ] ); - $this->mock_gateway->expects( $this->never() ) - ->method( 'update_option' ); + $this->mock_api_client->expects( $this->never() )->method( 'register_domain' ); + $this->mock_gateway->expects( $this->never() )->method( 'update_option' ); $this->wc_apple_pay_registration->verify_domain_on_updated_settings( - [ - 'enabled' => 'no', - 'payment_request' => 'yes', - ], - [ - 'enabled' => 'no', - 'payment_request' => 'yes', - ] + [ 'enabled' => 'no' ], + [ 'enabled' => 'no' ] ); } public function test_verify_domain_on_updated_settings_when_enabled() { - $this->mock_gateway->method( 'is_enabled' ) - ->willReturn( true ); - - $this->mock_gateway->method( 'get_option' ) - ->with( 'payment_request' ) - ->willReturn( 'yes' ); + $this->mock_gateway->method( 'is_enabled' )->willReturn( true ); + $this->mock_apple_pay_gateway->method( 'is_enabled' )->willReturn( true ); + $this->set_payment_gateway_map( [ 'apple_pay' => $this->mock_apple_pay_gateway ] ); $this->mock_api_client->expects( $this->once() ) ->method( 'register_domain' ) @@ -173,14 +178,109 @@ public function test_verify_domain_on_updated_settings_when_enabled() { ); $this->wc_apple_pay_registration->verify_domain_on_updated_settings( - [ - 'enabled' => 'no', - 'payment_request' => 'no', - ], - [ - 'enabled' => 'yes', - 'payment_request' => 'yes', - ] + [ 'enabled' => 'no' ], + [ 'enabled' => 'yes' ] + ); + } + + public function test_verify_domain_on_updated_settings_when_already_enabled() { + $this->mock_apple_pay_gateway->method( 'is_enabled' )->willReturn( true ); + $this->set_payment_gateway_map( [ 'apple_pay' => $this->mock_apple_pay_gateway ] ); + + $this->mock_api_client->expects( $this->never() )->method( 'register_domain' ); + $this->mock_gateway->expects( $this->never() )->method( 'update_option' ); + + $this->wc_apple_pay_registration->verify_domain_on_updated_settings( + [ 'enabled' => 'yes' ], + [ 'enabled' => 'yes' ] ); } + + public function test_register_domain_stores_error_on_failure() { + $this->mock_gateway->method( 'is_enabled' )->willReturn( true ); + $this->mock_apple_pay_gateway->method( 'is_enabled' )->willReturn( true ); + $this->set_payment_gateway_map( [ 'apple_pay' => $this->mock_apple_pay_gateway ] ); + + $error_message = 'Domain verification failed: invalid domain'; + + $this->mock_api_client->expects( $this->once() ) + ->method( 'register_domain' ) + ->with( $this->expected_domain ) + ->willReturn( + [ + 'id' => 'domain_123', + 'apple_pay' => [ + 'status' => 'failed', + 'status_details' => [ 'error_message' => $error_message ], + ], + ] + ); + + $this->wc_apple_pay_registration->verify_domain_on_new_settings( + 'option_name', + [ 'enabled' => 'yes' ] + ); + + $this->assertEquals( $error_message, get_option( WC_Payments_Apple_Pay_Registration::APPLE_PAY_DOMAIN_ERROR_OPTION ) ); + } + + public function test_register_domain_clears_error_on_success() { + $this->mock_gateway->method( 'is_enabled' )->willReturn( true ); + $this->mock_apple_pay_gateway->method( 'is_enabled' )->willReturn( true ); + $this->set_payment_gateway_map( [ 'apple_pay' => $this->mock_apple_pay_gateway ] ); + + update_option( WC_Payments_Apple_Pay_Registration::APPLE_PAY_DOMAIN_ERROR_OPTION, 'Previous error' ); + + $this->mock_api_client->expects( $this->once() ) + ->method( 'register_domain' ) + ->with( $this->expected_domain ) + ->willReturn( + [ + 'id' => 'domain_123', + 'apple_pay' => [ 'status' => 'active' ], + ] + ); + + $this->wc_apple_pay_registration->verify_domain_on_new_settings( + 'option_name', + [ 'enabled' => 'yes' ] + ); + + $this->assertFalse( get_option( WC_Payments_Apple_Pay_Registration::APPLE_PAY_DOMAIN_ERROR_OPTION ) ); + } + + public function test_display_error_notice_clears_error_after_display() { + $this->mock_gateway->method( 'is_enabled' )->willReturn( true ); + $this->mock_apple_pay_gateway->method( 'is_enabled' )->willReturn( true ); + $this->set_payment_gateway_map( [ 'apple_pay' => $this->mock_apple_pay_gateway ] ); + $this->mock_account->method( 'get_is_live' )->willReturn( true ); + $this->mock_gateway->method( 'get_option' ) + ->with( 'apple_pay_domain_set' ) + ->willReturn( 'no' ); + + update_option( WC_Payments_Apple_Pay_Registration::APPLE_PAY_DOMAIN_ERROR_OPTION, 'Test error message' ); + + ob_start(); + $this->wc_apple_pay_registration->display_error_notice(); + $output = ob_get_clean(); + + $this->assertStringContainsString( 'Test error message', $output ); + $this->assertFalse( get_option( WC_Payments_Apple_Pay_Registration::APPLE_PAY_DOMAIN_ERROR_OPTION ) ); + } + + public function test_display_error_notice_shows_generic_message_when_no_error_stored() { + $this->mock_gateway->method( 'is_enabled' )->willReturn( true ); + $this->mock_apple_pay_gateway->method( 'is_enabled' )->willReturn( true ); + $this->set_payment_gateway_map( [ 'apple_pay' => $this->mock_apple_pay_gateway ] ); + $this->mock_account->method( 'get_is_live' )->willReturn( true ); + $this->mock_gateway->method( 'get_option' ) + ->with( 'apple_pay_domain_set' ) + ->willReturn( 'no' ); + + ob_start(); + $this->wc_apple_pay_registration->display_error_notice(); + $output = ob_get_clean(); + + $this->assertStringContainsString( 'Apple Pay domain verification failed.', $output ); + } }