diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 794e0b310..000000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -language: php -os: linux -dist: xenial - -notifications: - email: false - -php: - - 7.0 - -branches: - only: - - master - - trunk - - compat/ppxo - -script: | - CHANGED_FILES=`git diff --name-only --diff-filter=ACMR $TRAVIS_COMMIT_RANGE | grep \\\\.php | awk '{print}' ORS=' '` - - if [ "$CHANGED_FILES" != "" ]; then - composer global require woocommerce/woocommerce-sniffs --update-with-all-dependencies - $HOME/.config/composer/vendor/bin/phpcs -p $CHANGED_FILES - fi diff --git a/bootstrap.php b/bootstrap.php new file mode 100644 index 000000000..a1f527a01 --- /dev/null +++ b/bootstrap.php @@ -0,0 +1,56 @@ +setup(); + }, + $modules + ); + + $provider = new CompositeCachingServiceProvider( $providers ); + $proxy_container = new ProxyContainer(); + // TODO: caching does not work currently, + // may want to consider fixing it later (pass proxy as parent to DelegatingContainer) + // for now not fixed since we were using this behavior for long time and fixing it now may break things. + $container = new DelegatingContainer( $provider ); + $app_container = new CachingContainer( + new CompositeContainer( + array_merge( + $additional_containers, + array( $container ) + ) + ) + ); + $proxy_container->setInnerContainer( $app_container ); + + foreach ( $modules as $module ) { + /* @var $module ModuleInterface module */ + $module->run( $app_container ); + } + + return $app_container; +}; diff --git a/modules.php b/modules.php new file mode 100644 index 000000000..8bffd9d34 --- /dev/null +++ b/modules.php @@ -0,0 +1,29 @@ + $this->email(), - ); + $data = array(); if ( $this->merchant_id ) { $data['merchant_id'] = $this->merchant_id(); + } else { + $data['email_address'] = $this->email(); } return $data; } diff --git a/modules/ppcp-api-client/src/Factory/class-payeefactory.php b/modules/ppcp-api-client/src/Factory/class-payeefactory.php index ddd489e1d..bb89d07b0 100644 --- a/modules/ppcp-api-client/src/Factory/class-payeefactory.php +++ b/modules/ppcp-api-client/src/Factory/class-payeefactory.php @@ -26,13 +26,8 @@ class PayeeFactory { * @throws RuntimeException When JSON object is malformed. */ public function from_paypal_response( \stdClass $data ) { - if ( ! isset( $data->email_address ) ) { - throw new RuntimeException( - __( 'No email for payee given.', 'woocommerce-paypal-payments' ) - ); - } - + $email = ( isset( $data->email_address ) ) ? $data->email_address : ''; $merchant_id = ( isset( $data->merchant_id ) ) ? $data->merchant_id : ''; - return new Payee( $data->email_address, $merchant_id ); + return new Payee( $email, $merchant_id ); } } diff --git a/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js b/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js index dc5035383..d506fadce 100644 --- a/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js +++ b/modules/ppcp-button/resources/js/modules/Renderer/CreditCardRenderer.js @@ -8,6 +8,8 @@ class CreditCardRenderer { this.spinner = spinner; this.cardValid = false; this.formValid = false; + this.currentHostedFieldsInstance = null; + this.formSubmissionSubscribed = false; } render(wrapper, contextConfig) { @@ -31,6 +33,12 @@ class CreditCardRenderer { return; } + if (this.currentHostedFieldsInstance) { + this.currentHostedFieldsInstance.teardown() + .catch(err => console.error(`Hosted fields teardown error: ${err}`)); + this.currentHostedFieldsInstance = null; + } + const gateWayBox = document.querySelector('.payment_box.payment_method_ppcp-credit-card-gateway'); const oldDisplayStyle = gateWayBox.style.display; gateWayBox.style.display = 'block'; @@ -92,36 +100,10 @@ class CreditCardRenderer { } } }).then(hostedFields => { - const submitEvent = (event) => { - this.spinner.block(); - if (event) { - event.preventDefault(); - } - this.errorHandler.clear(); - - if (this.formValid && this.cardValid) { - const save_card = this.defaultConfig.save_card ? true : false; - const vault = document.getElementById('ppcp-credit-card-vault') ? - document.getElementById('ppcp-credit-card-vault').checked : save_card; - hostedFields.submit({ - contingencies: ['SCA_WHEN_REQUIRED'], - vault: vault - }).then((payload) => { - payload.orderID = payload.orderId; - this.spinner.unblock(); - return contextConfig.onApprove(payload); - }).catch(() => { - this.errorHandler.genericError(); - this.spinner.unblock(); - }); - } else { - this.spinner.unblock(); - const message = ! this.cardValid ? this.defaultConfig.hosted_fields.labels.card_not_supported : this.defaultConfig.hosted_fields.labels.fields_not_valid; - this.errorHandler.message(message); - } - } - hostedFields.on('inputSubmitRequest', function () { - submitEvent(null); + this.currentHostedFieldsInstance = hostedFields; + + hostedFields.on('inputSubmitRequest', () => { + this._submit(contextConfig); }); hostedFields.on('cardTypeChange', (event) => { if ( ! event.cards.length ) { @@ -137,11 +119,18 @@ class CreditCardRenderer { }); this.formValid = formValid; - }) - document.querySelector(wrapper + ' button').addEventListener( - 'click', - submitEvent - ); + }); + + if (!this.formSubmissionSubscribed) { + document.querySelector(wrapper + ' button').addEventListener( + 'click', + event => { + event.preventDefault(); + this._submit(contextConfig); + } + ); + this.formSubmissionSubscribed = true; + } }); document.querySelector('#payment_method_ppcp-credit-card-gateway').addEventListener( @@ -151,5 +140,36 @@ class CreditCardRenderer { } ) } + + _submit(contextConfig) { + this.spinner.block(); + this.errorHandler.clear(); + + if (this.formValid && this.cardValid) { + const save_card = this.defaultConfig.save_card ? true : false; + const vault = document.getElementById('ppcp-credit-card-vault') ? + document.getElementById('ppcp-credit-card-vault').checked : save_card; + const contingency = this.defaultConfig.hosted_fields.contingency; + const hostedFieldsData = { + vault: vault + }; + if (contingency !== 'NO_3D_SECURE') { + hostedFieldsData.contingencies = [contingency]; + } + this.currentHostedFieldsInstance.submit(hostedFieldsData).then((payload) => { + payload.orderID = payload.orderId; + this.spinner.unblock(); + return contextConfig.onApprove(payload); + }).catch(err => { + console.error(err); + this.errorHandler.genericError(); + this.spinner.unblock(); + }); + } else { + this.spinner.unblock(); + const message = ! this.cardValid ? this.defaultConfig.hosted_fields.labels.card_not_supported : this.defaultConfig.hosted_fields.labels.fields_not_valid; + this.errorHandler.message(message); + } + } } export default CreditCardRenderer; diff --git a/modules/ppcp-button/src/Assets/class-smartbutton.php b/modules/ppcp-button/src/Assets/class-smartbutton.php index 5f3fc0244..f972574f5 100644 --- a/modules/ppcp-button/src/Assets/class-smartbutton.php +++ b/modules/ppcp-button/src/Assets/class-smartbutton.php @@ -601,6 +601,19 @@ private function has_subscriptions(): bool { return $this->subscription_helper->cart_contains_subscription(); } + /** + * Retrieves the 3D Secure contingency settings. + * + * @return string + */ + private function get_3ds_contingency(): string { + if ( $this->settings->has( '3d_secure_contingency' ) ) { + return $this->settings->get( '3d_secure_contingency' ); + } + + return 'SCA_WHEN_REQUIRED'; + } + /** * The localized data for the smart button. * @@ -677,6 +690,7 @@ private function localize_script(): array { ), ), 'valid_cards' => $this->dcc_applies->valid_cards(), + 'contingency' => $this->get_3ds_contingency(), ), 'messages' => $this->message_values(), 'labels' => array( @@ -729,8 +743,7 @@ private function url(): string { 'currency' => get_woocommerce_currency(), 'integration-date' => PAYPAL_INTEGRATION_DATE, 'components' => implode( ',', $this->components() ), - 'vault' => $this->can_save_vault_token() ? - 'true' : 'false', + 'vault' => $this->can_save_vault_token() ? 'true' : 'false', 'commit' => is_checkout() ? 'true' : 'false', 'intent' => ( $this->settings->has( 'intent' ) ) ? $this->settings->get( 'intent' ) : 'capture', @@ -743,11 +756,20 @@ private function url(): string { ) { $params['buyer-country'] = WC()->customer->get_billing_country(); } - $disable_funding = $this->settings->has( 'disable_funding' ) ? - $this->settings->get( 'disable_funding' ) : array(); + + $disable_funding = $this->settings->has( 'disable_funding' ) + ? $this->settings->get( 'disable_funding' ) + : array(); + if ( ! is_checkout() ) { $disable_funding[] = 'card'; } + if ( is_checkout() && $this->settings->has( 'dcc_enabled' ) && $this->settings->get( 'dcc_enabled' ) ) { + $key = array_search( 'card', $disable_funding, true ); + if ( false !== $key ) { + unset( $disable_funding[ $key ] ); + } + } if ( count( $disable_funding ) > 0 ) { $params['disable-funding'] = implode( ',', array_unique( $disable_funding ) ); diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index f072e347c..c977e588e 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -5,6 +5,8 @@ * @package WooCommerce\PayPalCommerce\WcGateway */ +// phpcs:disable WordPress.Security.NonceVerification.Recommended + declare(strict_types=1); namespace WooCommerce\PayPalCommerce\WcGateway; @@ -28,6 +30,7 @@ use Woocommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus; use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice; use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice; +use WooCommerce\PayPalCommerce\WcGateway\Notice\DccWithoutPayPalAdminNotice; use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor; use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor; use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor; @@ -48,6 +51,7 @@ $state = $container->get( 'onboarding.state' ); $transaction_url_provider = $container->get( 'wcgateway.transaction-url-provider' ); $subscription_helper = $container->get( 'subscription.helper' ); + $page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' ); return new PayPalGateway( $settings_renderer, $order_processor, @@ -58,7 +62,8 @@ $refund_processor, $state, $transaction_url_provider, - $subscription_helper + $subscription_helper, + $page_id ); }, 'wcgateway.credit-card-gateway' => static function ( $container ): CreditCardGateway { @@ -100,6 +105,33 @@ $settings = $container->get( 'wcgateway.settings' ); return new DisableGateways( $session_handler, $settings ); }, + + 'wcgateway.is-wc-payments-page' => static function ( $container ): bool { + $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; + $tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : ''; + return 'wc-settings' === $page && 'checkout' === $tab; + }, + + 'wcgateway.is-ppcp-settings-page' => static function ( $container ): bool { + if ( ! $container->get( 'wcgateway.is-wc-payments-page' ) ) { + return false; + } + + $section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : ''; + return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID ), true ); + }, + + 'wcgateway.current-ppcp-settings-page-id' => static function ( $container ): string { + if ( ! $container->get( 'wcgateway.is-ppcp-settings-page' ) ) { + return ''; + } + + $section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : ''; + $ppcp_tab = isset( $_GET[ SectionsRenderer::KEY ] ) ? sanitize_text_field( wp_unslash( $_GET[ SectionsRenderer::KEY ] ) ) : ''; + + return $ppcp_tab ? $ppcp_tab : $section; + }, + 'wcgateway.settings' => static function ( $container ): Settings { return new Settings(); }, @@ -108,12 +140,19 @@ $settings = $container->get( 'wcgateway.settings' ); return new ConnectAdminNotice( $state, $settings ); }, + 'wcgateway.notice.dcc-without-paypal' => static function ( $container ): DccWithoutPayPalAdminNotice { + $state = $container->get( 'onboarding.state' ); + $settings = $container->get( 'wcgateway.settings' ); + $is_payments_page = $container->get( 'wcgateway.is-wc-payments-page' ); + $is_ppcp_settings_page = $container->get( 'wcgateway.is-ppcp-settings-page' ); + return new DccWithoutPayPalAdminNotice( $state, $settings, $is_payments_page, $is_ppcp_settings_page ); + }, 'wcgateway.notice.authorize-order-action' => static function ( $container ): AuthorizeOrderActionNotice { return new AuthorizeOrderActionNotice(); }, 'wcgateway.settings.sections-renderer' => static function ( $container ): SectionsRenderer { - return new SectionsRenderer(); + return new SectionsRenderer( $container->get( 'wcgateway.current-ppcp-settings-page-id' ) ); }, 'wcgateway.settings.status' => static function ( $container ): SettingsStatus { $settings = $container->get( 'wcgateway.settings' ); @@ -127,6 +166,7 @@ static function ( $container ): AuthorizeOrderActionNotice { $messages_apply = $container->get( 'button.helper.messages-apply' ); $dcc_product_status = $container->get( 'wcgateway.helper.dcc-product-status' ); $settings_status = $container->get( 'wcgateway.settings.status' ); + $page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' ); return new SettingsRenderer( $settings, $state, @@ -134,7 +174,8 @@ static function ( $container ): AuthorizeOrderActionNotice { $dcc_applies, $messages_apply, $dcc_product_status, - $settings_status + $settings_status, + $page_id ); }, 'wcgateway.settings.listener' => static function ( $container ): SettingsListener { @@ -144,7 +185,8 @@ static function ( $container ): AuthorizeOrderActionNotice { $state = $container->get( 'onboarding.state' ); $cache = new Cache( 'ppcp-paypal-bearer' ); $bearer = $container->get( 'api.bearer' ); - return new SettingsListener( $settings, $fields, $webhook_registrar, $cache, $state, $bearer ); + $page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' ); + return new SettingsListener( $settings, $fields, $webhook_registrar, $cache, $state, $bearer, $page_id ); }, 'wcgateway.order-processor' => static function ( $container ): OrderProcessor { @@ -646,7 +688,7 @@ static function ( $container ): AuthorizeOrderActionNotice { 'label' => sprintf( // translators: %1$s and %2$s are the opening and closing of HTML tag. __( 'Enable saved cards and subscription features on your store. To use vaulting features, you must %1$senable vaulting on your account%2$s.', 'woocommerce-paypal-payments' ), - '', @@ -1804,6 +1846,62 @@ static function ( $container ): AuthorizeOrderActionNotice { ), 'gateway' => 'dcc', ), + '3d_secure_heading' => array( + 'heading' => __( '3D Secure', 'woocommerce-paypal-payments' ), + 'type' => 'ppcp-heading', + 'description' => wp_kses_post( + sprintf( + // translators: %1$s and %2$s is a link tag. + __( + '3D Secure benefits cardholders and merchants by providing + an additional layer of verification using Verified by Visa, + MasterCard SecureCode and American Express SafeKey. + %1$sLearn more about 3D Secure.%2$s', + 'woocommerce-paypal-payments' + ), + '', + '' + ) + ), + 'screens' => array( + State::STATE_ONBOARDED, + ), + 'requirements' => array( + 'dcc', + ), + 'gateway' => 'dcc', + ), + '3d_secure_contingency' => array( + 'title' => __( 'Contingency for 3D Secure', 'woocommerce-paypal-payments' ), + 'type' => 'select', + 'description' => sprintf( + // translators: %1$s and %2$s opening and closing ul tag, %3$s and %4$s opening and closing li tag. + __( '%1$s%3$sNo 3D Secure will cause transactions to be denied if 3D Secure is required by the bank of the cardholder.%4$s%3$sSCA_WHEN_REQUIRED returns a 3D Secure contingency when it is a mandate in the region where you operate.%4$s%3$sSCA_ALWAYS triggers 3D Secure for every transaction, regardless of SCA requirements.%4$s%2$s', 'woocommerce-paypal-payments' ), + '', + '
  • ', + '
  • ' + ), + 'class' => array(), + 'input_class' => array( 'wc-enhanced-select' ), + 'default' => 'SCA_WHEN_REQUIRED', + 'desc_tip' => true, + 'options' => array( + 'NO_3D_SECURE' => __( 'No 3D Secure (transaction will be denied if 3D Secure is required)', 'woocommerce-paypal-payments' ), + 'SCA_WHEN_REQUIRED' => __( '3D Secure when required', 'woocommerce-paypal-payments' ), + '3D_SECURE' => __( 'Always trigger 3D Secure', 'woocommerce-paypal-payments' ), + ), + 'screens' => array( + State::STATE_ONBOARDED, + ), + 'requirements' => array( + 'dcc', + ), + 'gateway' => 'dcc', + ), ); if ( ! defined( 'PPCP_FLAG_SUBSCRIPTION' ) || ! PPCP_FLAG_SUBSCRIPTION ) { unset( $fields['vault_enabled'] ); @@ -1820,15 +1918,6 @@ static function ( $container ): AuthorizeOrderActionNotice { unset( $fields['ppcp_disconnect_sandbox'] ); } - /** - * Disable card for UK. - */ - $region = wc_get_base_location(); - $country = $region['country']; - if ( 'GB' === $country ) { - unset( $fields['disable_funding']['options']['card'] ); - } - /** * Depending on your store location, some credit cards can't be used. * Here, we filter them out. diff --git a/modules/ppcp-wc-gateway/src/Gateway/class-creditcardgateway.php b/modules/ppcp-wc-gateway/src/Gateway/class-creditcardgateway.php index 86604af4b..a49d0ed39 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/class-creditcardgateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/class-creditcardgateway.php @@ -197,13 +197,7 @@ public function __construct( */ public function init_form_fields() { $this->form_fields = array( - 'enabled' => array( - 'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ), - 'type' => 'checkbox', - 'label' => __( 'Enable Credit Card Payments', 'woocommerce-paypal-payments' ), - 'default' => 'no', - ), - 'ppcp' => array( + 'ppcp' => array( 'type' => 'ppcp', ), ); @@ -218,6 +212,20 @@ public function form() { remove_action( 'gettext', 'replace_credit_card_cvv_label' ); } + /** + * Renders the settings. + * + * @return string + */ + public function generate_ppcp_html(): string { + + ob_start(); + $this->settings_renderer->render(); + $content = ob_get_contents(); + ob_end_clean(); + return $content; + } + /** * Replace WooCommerce credit card field label. * @@ -314,7 +322,7 @@ private function card_labels(): array { * @return bool */ public function is_available() : bool { - return $this->config->has( 'dcc_enabled' ) && $this->config->get( 'dcc_enabled' ); + return $this->is_enabled(); } @@ -349,4 +357,60 @@ public function get_transaction_url( $order ): string { return parent::get_transaction_url( $order ); } + + /** + * Initialize settings for WC. + * + * @return void + */ + public function init_settings() { + parent::init_settings(); + + // looks like in some cases WC uses this field instead of get_option. + $this->enabled = $this->is_enabled(); + } + + /** + * Get the option value for WC. + * + * @param string $key The option key. + * @param mixed $empty_value Value when empty. + * @return mixed + */ + public function get_option( $key, $empty_value = null ) { + if ( 'enabled' === $key ) { + return $this->is_enabled(); + } + + return parent::get_option( $key, $empty_value ); + } + + /** + * Handle update of WC settings. + * + * @param string $key The option key. + * @param string $value The option value. + * @return bool was anything saved? + */ + public function update_option( $key, $value = '' ) { + $ret = parent::update_option( $key, $value ); + + if ( 'enabled' === $key ) { + $this->config->set( 'dcc_enabled', 'yes' === $value ); + $this->config->persist(); + + return true; + } + + return $ret; + } + + /** + * Returns if the gateway is enabled. + * + * @return bool + */ + private function is_enabled(): bool { + return $this->config->has( 'dcc_enabled' ) && $this->config->get( 'dcc_enabled' ); + } } diff --git a/modules/ppcp-wc-gateway/src/Gateway/class-paypalgateway.php b/modules/ppcp-wc-gateway/src/Gateway/class-paypalgateway.php index e1aadeb83..da7597abb 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/class-paypalgateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/class-paypalgateway.php @@ -103,6 +103,13 @@ class PayPalGateway extends \WC_Payment_Gateway { */ private $onboarded; + /** + * ID of the current PPCP gateway settings page, or empty if it is not such page. + * + * @var string + */ + protected $page_id; + /** * PayPalGateway constructor. * @@ -116,6 +123,7 @@ class PayPalGateway extends \WC_Payment_Gateway { * @param State $state The state. * @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order. * @param SubscriptionHelper $subscription_helper The subscription helper. + * @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page. */ public function __construct( SettingsRenderer $settings_renderer, @@ -127,7 +135,8 @@ public function __construct( RefundProcessor $refund_processor, State $state, TransactionUrlProvider $transaction_url_provider, - SubscriptionHelper $subscription_helper + SubscriptionHelper $subscription_helper, + string $page_id ) { $this->id = self::ID; @@ -139,6 +148,7 @@ public function __construct( $this->session_handler = $session_handler; $this->refund_processor = $refund_processor; $this->transaction_url_provider = $transaction_url_provider; + $this->page_id = $page_id; $this->onboarded = $state->current_state() === State::STATE_ONBOARDED; if ( $this->onboarded ) { @@ -332,8 +342,7 @@ private function define_method_description(): string { */ private function is_credit_card_tab() : bool { return is_admin() - && isset( $_GET[ SectionsRenderer::KEY ] ) - && CreditCardGateway::ID === sanitize_text_field( wp_unslash( $_GET[ SectionsRenderer::KEY ] ) ); + && CreditCardGateway::ID === $this->page_id; } @@ -345,8 +354,7 @@ private function is_credit_card_tab() : bool { private function is_paypal_tab() : bool { return ! $this->is_credit_card_tab() && is_admin() - && isset( $_GET['section'] ) - && self::ID === sanitize_text_field( wp_unslash( $_GET['section'] ) ); + && self::ID === $this->page_id; } // phpcs:enable WordPress.Security.NonceVerification.Recommended @@ -387,14 +395,18 @@ public function get_transaction_url( $order ): string { * * @param string $key The option key. * @param string $value The option value. - * @return bool|void + * @return bool was anything saved? */ public function update_option( $key, $value = '' ) { - parent::update_option( $key, $value ); + $ret = parent::update_option( $key, $value ); if ( 'enabled' === $key ) { $this->config->set( 'enabled', 'yes' === $value ); $this->config->persist(); + + return true; } + + return $ret; } } diff --git a/modules/ppcp-wc-gateway/src/Notice/class-dccwithoutpaypaladminnotice.php b/modules/ppcp-wc-gateway/src/Notice/class-dccwithoutpaypaladminnotice.php new file mode 100644 index 000000000..2343c9e00 --- /dev/null +++ b/modules/ppcp-wc-gateway/src/Notice/class-dccwithoutpaypaladminnotice.php @@ -0,0 +1,101 @@ +state = $state; + $this->settings = $settings; + $this->is_payments_page = $is_payments_page; + $this->is_ppcp_settings_page = $is_ppcp_settings_page; + } + + /** + * Returns the message. + * + * @return Message|null + */ + public function message(): ?Message { + if ( ! $this->should_display() ) { + return null; + } + + $message = sprintf( + /* translators: %1$s the gateway name. */ + __( + 'PayPal Card Processing cannot be used without the PayPal gateway. Enable the PayPal Gateway.', + 'woocommerce-paypal-payments' + ), + admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway' ) + ); + return new Message( $message, 'warning' ); + } + + /** + * Whether the message should be displayed. + * + * @return bool + */ + protected function should_display(): bool { + return State::STATE_ONBOARDED === $this->state->current_state() + && ( $this->is_payments_page || $this->is_ppcp_settings_page ) + && ( $this->settings->has( 'dcc_enabled' ) && $this->settings->get( 'dcc_enabled' ) ) + && ( ! $this->settings->has( 'enabled' ) || ! $this->settings->get( 'enabled' ) ); + } +} diff --git a/modules/ppcp-wc-gateway/src/Settings/class-sectionsrenderer.php b/modules/ppcp-wc-gateway/src/Settings/class-sectionsrenderer.php index ee000f03d..ea9e693f5 100644 --- a/modules/ppcp-wc-gateway/src/Settings/class-sectionsrenderer.php +++ b/modules/ppcp-wc-gateway/src/Settings/class-sectionsrenderer.php @@ -19,15 +19,29 @@ class SectionsRenderer { const KEY = 'ppcp-tab'; + /** + * ID of the current PPCP gateway settings page, or empty if it is not such page. + * + * @var string + */ + protected $page_id; + + /** + * SectionsRenderer constructor. + * + * @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page. + */ + public function __construct( string $page_id ) { + $this->page_id = $page_id; + } + /** * Whether the sections tab should be rendered. * * @return bool */ public function should_render() : bool { - - global $current_section; - return PayPalGateway::ID === $current_section; + return ! empty( $this->page_id ); } /** @@ -38,8 +52,6 @@ public function render() { return; } - //phpcs:ignore WordPress.Security.NonceVerification.Recommended - $current = ! isset( $_GET[ self::KEY ] ) ? PayPalGateway::ID : sanitize_text_field( wp_unslash( $_GET[ self::KEY ] ) ); $sections = array( PayPalGateway::ID => __( 'PayPal Checkout', 'woocommerce-paypal-payments' ), CreditCardGateway::ID => __( 'PayPal Card Processing', 'woocommerce-paypal-payments' ), @@ -51,7 +63,7 @@ public function render() { foreach ( $sections as $id => $label ) { $url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&' . self::KEY . '=' . $id ); - echo '
  • ' . esc_html( $label ) . ' ' . ( end( $array_keys ) === $id ? '' : '|' ) . '
  • '; + echo '
  • ' . esc_html( $label ) . ' ' . ( end( $array_keys ) === $id ? '' : '|' ) . '
  • '; } echo '
    '; diff --git a/modules/ppcp-wc-gateway/src/Settings/class-settingslistener.php b/modules/ppcp-wc-gateway/src/Settings/class-settingslistener.php index 6c0f9463f..dd3e89aa1 100644 --- a/modules/ppcp-wc-gateway/src/Settings/class-settingslistener.php +++ b/modules/ppcp-wc-gateway/src/Settings/class-settingslistener.php @@ -67,6 +67,13 @@ class SettingsListener { */ private $bearer; + /** + * ID of the current PPCP gateway settings page, or empty if it is not such page. + * + * @var string + */ + protected $page_id; + /** * SettingsListener constructor. * @@ -76,6 +83,7 @@ class SettingsListener { * @param Cache $cache The Cache. * @param State $state The state. * @param Bearer $bearer The bearer. + * @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page. */ public function __construct( Settings $settings, @@ -83,7 +91,8 @@ public function __construct( WebhookRegistrar $webhook_registrar, Cache $cache, State $state, - Bearer $bearer + Bearer $bearer, + string $page_id ) { $this->settings = $settings; @@ -92,6 +101,7 @@ public function __construct( $this->cache = $cache; $this->state = $state; $this->bearer = $bearer; + $this->page_id = $page_id; } /** @@ -218,7 +228,7 @@ public function listen() { $settings = $this->read_active_credentials_from_settings( $settings ); - if ( ! isset( $_GET[ SectionsRenderer::KEY ] ) || PayPalGateway::ID === $_GET[ SectionsRenderer::KEY ] ) { + if ( PayPalGateway::ID === $this->page_id ) { $settings['enabled'] = isset( $_POST['woocommerce_ppcp-gateway_enabled'] ) && 1 === absint( $_POST['woocommerce_ppcp-gateway_enabled'] ); $this->maybe_register_webhooks( $settings ); @@ -313,17 +323,13 @@ private function retrieve_settings_from_raw_data( array $raw_data ): array { } if ( 'dcc' === $config['gateway'] - && ( - ! isset( $_GET[ SectionsRenderer::KEY ] ) - || sanitize_text_field( wp_unslash( $_GET[ SectionsRenderer::KEY ] ) ) !== CreditCardGateway::ID - ) + && CreditCardGateway::ID !== $this->page_id ) { continue; } if ( 'paypal' === $config['gateway'] - && isset( $_GET[ SectionsRenderer::KEY ] ) - && sanitize_text_field( wp_unslash( $_GET[ SectionsRenderer::KEY ] ) ) !== PayPalGateway::ID + && PayPalGateway::ID !== $this->page_id ) { continue; } @@ -406,14 +412,7 @@ private function is_valid_site_request() : bool { * phpcs:disable WordPress.Security.NonceVerification.Missing * phpcs:disable WordPress.Security.NonceVerification.Recommended */ - if ( - ! isset( $_REQUEST['section'] ) - || ! in_array( - sanitize_text_field( wp_unslash( $_REQUEST['section'] ) ), - array( 'ppcp-gateway', 'ppcp-credit-card-gateway' ), - true - ) - ) { + if ( empty( $this->page_id ) ) { return false; } diff --git a/modules/ppcp-wc-gateway/src/Settings/class-settingsrenderer.php b/modules/ppcp-wc-gateway/src/Settings/class-settingsrenderer.php index b08533e05..690c5d91f 100644 --- a/modules/ppcp-wc-gateway/src/Settings/class-settingsrenderer.php +++ b/modules/ppcp-wc-gateway/src/Settings/class-settingsrenderer.php @@ -15,6 +15,7 @@ use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use Psr\Container\ContainerInterface; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use Woocommerce\PayPalCommerce\WcGateway\Helper\DccProductStatus; use Woocommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus; @@ -72,6 +73,13 @@ class SettingsRenderer { */ private $dcc_product_status; + /** + * ID of the current PPCP gateway settings page, or empty if it is not such page. + * + * @var string + */ + protected $page_id; + /** * SettingsRenderer constructor. * @@ -82,6 +90,7 @@ class SettingsRenderer { * @param MessagesApply $messages_apply Whether messages can be shown. * @param DccProductStatus $dcc_product_status The product status. * @param SettingsStatus $settings_status The Settings status helper. + * @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page. */ public function __construct( ContainerInterface $settings, @@ -90,7 +99,8 @@ public function __construct( DccApplies $dcc_applies, MessagesApply $messages_apply, DccProductStatus $dcc_product_status, - SettingsStatus $settings_status + SettingsStatus $settings_status, + string $page_id ) { $this->settings = $settings; @@ -100,6 +110,7 @@ public function __construct( $this->messages_apply = $messages_apply; $this->dcc_product_status = $dcc_product_status; $this->settings_status = $settings_status; + $this->page_id = $page_id; } /** @@ -166,21 +177,7 @@ private function paypal_vaulting_is_enabled(): bool { * @return bool Whether is PayPal checkout screen or not. */ private function is_paypal_checkout_screen(): bool { - $current_screen = get_current_screen(); - //phpcs:disable WordPress.Security.NonceVerification.Recommended - //phpcs:disable WordPress.Security.NonceVerification.Missing - if ( isset( $current_screen->id ) && 'woocommerce_page_wc-settings' === $current_screen->id - && isset( $_GET['section'] ) && 'ppcp-gateway' === $_GET['section'] ) { - - if ( isset( $_GET['ppcp-tab'] ) && 'ppcp-gateway' !== $_GET['ppcp-tab'] ) { - return false; - } - - return true; - } - //phpcs:enable - - return false; + return PayPalGateway::ID === $this->page_id; } /** @@ -317,9 +314,7 @@ public function render_heading( $field, $key, $config, $value ): string { */ public function render() { - //phpcs:disable WordPress.Security.NonceVerification.Recommended - //phpcs:disable WordPress.Security.NonceVerification.Missing - $is_dcc = isset( $_GET[ SectionsRenderer::KEY ] ) && CreditCardGateway::ID === sanitize_text_field( wp_unslash( $_GET[ SectionsRenderer::KEY ] ) ); + $is_dcc = CreditCardGateway::ID === $this->page_id; //phpcs:enable WordPress.Security.NonceVerification.Recommended //phpcs:enable WordPress.Security.NonceVerification.Missing $nonce = wp_create_nonce( SettingsListener::NONCE ); @@ -399,8 +394,6 @@ class="woocommerce-help-tip" if ( $this->dcc_applies->for_country_currency() ) { if ( State::STATE_ONBOARDED > $this->state->current_state() ) { $this->render_dcc_onboarding_info(); - } elseif ( State::STATE_ONBOARDED === $this->state->current_state() && $this->dcc_product_status->dcc_is_active() ) { - $this->render_3d_secure_info(); } elseif ( ! $this->dcc_product_status->dcc_is_active() ) { $this->render_dcc_not_active_yet(); } @@ -450,45 +443,6 @@ private function render_dcc_not_active_yet() { - - - -

    - ', - '' - ) - ); - ?> -

    - - - is_paypal_checkout_screen() && $this->paypal_vaulting_is_enabled() - || $this->is_paypal_checkout_screen() && $this->settings_status->pay_later_messaging_is_enabled(); + return $this->is_paypal_checkout_screen() + && ( $this->paypal_vaulting_is_enabled() || $this->settings_status->pay_later_messaging_is_enabled() ); } } diff --git a/modules/ppcp-wc-gateway/src/class-wcgatewaymodule.php b/modules/ppcp-wc-gateway/src/class-wcgatewaymodule.php index 981491351..60ec5d7c1 100644 --- a/modules/ppcp-wc-gateway/src/class-wcgatewaymodule.php +++ b/modules/ppcp-wc-gateway/src/class-wcgatewaymodule.php @@ -24,6 +24,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice; +use WooCommerce\PayPalCommerce\WcGateway\Notice\DccWithoutPayPalAdminNotice; use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsListener; @@ -58,7 +59,6 @@ public function run( ContainerInterface $container ): void { $this->register_order_functionality( $container ); $this->register_columns( $container ); $this->register_checkout_paypal_address_preset( $container ); - $this->ajax_gateway_enabler( $container ); add_action( 'woocommerce_sections_checkout', @@ -86,15 +86,19 @@ function() use ( $container ) { Repository::NOTICES_FILTER, static function ( $notices ) use ( $container ): array { $notice = $container->get( 'wcgateway.notice.connect' ); - /** - * The Connect Admin Notice object. - * - * @var ConnectAdminNotice $notice - */ + assert( $notice instanceof ConnectAdminNotice ); $connect_message = $notice->connect_message(); if ( $connect_message ) { $notices[] = $connect_message; } + + $dcc_without_paypal_notice = $container->get( 'wcgateway.notice.dcc-without-paypal' ); + assert( $dcc_without_paypal_notice instanceof DccWithoutPayPalAdminNotice ); + $dcc_without_paypal_message = $dcc_without_paypal_notice->message(); + if ( $dcc_without_paypal_message ) { + $notices[] = $dcc_without_paypal_message; + } + $authorize_order_action = $container->get( 'wcgateway.notice.authorize-order-action' ); $authorized_message = $authorize_order_action->message(); if ( $authorized_message ) { @@ -102,11 +106,7 @@ static function ( $notices ) use ( $container ): array { } $settings_renderer = $container->get( 'wcgateway.settings.render' ); - /** - * The settings renderer. - * - * @var SettingsRenderer $settings_renderer - */ + assert( $settings_renderer instanceof SettingsRenderer ); $messages = $settings_renderer->messages(); $notices = array_merge( $notices, $messages ); @@ -149,50 +149,6 @@ function( $recipient, $order ) { ); } - /** - * Adds the functionality to listen to the ajax enable gateway switch. - * - * @param ContainerInterface $container The container. - */ - private function ajax_gateway_enabler( ContainerInterface $container ) { - add_action( - 'wp_ajax_woocommerce_toggle_gateway_enabled', - static function () use ( $container ) { - if ( - ! current_user_can( 'manage_woocommerce' ) - || ! check_ajax_referer( - 'woocommerce-toggle-payment-gateway-enabled', - 'security' - ) - || ! isset( $_POST['gateway_id'] ) - ) { - return; - } - - /** - * The settings. - * - * @var Settings $settings - */ - $settings = $container->get( 'wcgateway.settings' ); - $key = PayPalGateway::ID === $_POST['gateway_id'] ? 'enabled' : ''; - if ( CreditCardGateway::ID === $_POST['gateway_id'] ) { - $key = 'dcc_enabled'; - } - if ( ! $key ) { - return; - } - $enabled = $settings->has( $key ) ? $settings->get( $key ) : false; - if ( ! $enabled ) { - return; - } - $settings->set( $key, false ); - $settings->persist(); - }, - 9 - ); - } - /** * Registers the payment gateways. * @@ -206,16 +162,12 @@ static function ( $methods ) use ( $container ): array { $methods[] = $container->get( 'wcgateway.paypal-gateway' ); $dcc_applies = $container->get( 'api.helpers.dccapplies' ); - $screen = ! function_exists( 'get_current_screen' ) ? (object) array( 'id' => 'front' ) : get_current_screen(); - if ( ! $screen ) { - $screen = (object) array( 'id' => 'front' ); - } /** * The DCC Applies object. * * @var DccApplies $dcc_applies */ - if ( 'woocommerce_page_wc-settings' !== $screen->id && $dcc_applies->for_country_currency() ) { + if ( $dcc_applies->for_country_currency() ) { $methods[] = $container->get( 'wcgateway.credit-card-gateway' ); } return (array) $methods; diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 1a191505c..f0fdaf9f9 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -35,6 +35,8 @@ src modules woocommerce-paypal-payments.php + modules.php + bootstrap.php */node_modules/* */vendor/* diff --git a/tests/PHPUnit/Button/Endpoint/CreateOrderEndpointTest.php b/tests/PHPUnit/Button/Endpoint/CreateOrderEndpointTest.php index 2f4efbe8e..fa6f2f9e9 100644 --- a/tests/PHPUnit/Button/Endpoint/CreateOrderEndpointTest.php +++ b/tests/PHPUnit/Button/Endpoint/CreateOrderEndpointTest.php @@ -32,7 +32,7 @@ public function payerVerifiesPhoneNumber($data, $expectedResult) { list($payer_factory, $testee) = $this->mockTestee(); - $method = $this->testPrivateMethod(CreateOrderEndpoint::class, 'payer'); + $method = $this->makePrivateMethod(CreateOrderEndpoint::class, 'payer'); $dataString = wp_json_encode($expectedResult['payer']); $dataObj = json_decode(wp_json_encode($expectedResult['payer'])); @@ -173,11 +173,11 @@ protected function mockTestee() * @return \ReflectionMethod * @throws \ReflectionException */ - protected function testPrivateMethod($class, $method) + protected function makePrivateMethod($class, $method) { $reflector = new ReflectionClass($class); $method = $reflector->getMethod($method); $method->setAccessible(true); return $method; } -} \ No newline at end of file +} diff --git a/tests/PHPUnit/ModularTestCase.php b/tests/PHPUnit/ModularTestCase.php new file mode 100644 index 000000000..be813085f --- /dev/null +++ b/tests/PHPUnit/ModularTestCase.php @@ -0,0 +1,70 @@ +justReturn(null); + when('plugins_url')->returnArg(); + when('plugin_dir_path')->alias(function ($file) { return trailingslashit(dirname($file)); }); + when('get_current_blog_id')->justReturn(42); + when('get_site_url')->justReturn('example.com'); + when('get_bloginfo')->justReturn('My Shop'); + when('wc_get_base_location')->justReturn(['country' => 'US']); + when('get_woocommerce_currency')->justReturn('USD'); + when('WC')->justReturn((object) [ + 'session' => null, + ]); + + global $wpdb; + $wpdb = \Mockery::mock(\stdClass::class); + $wpdb->shouldReceive('get_var')->andReturn(null); + $wpdb->shouldReceive('prepare')->andReturn(null); + $wpdb->posts = ''; + $wpdb->postmeta = ''; + + !defined('PAYPAL_API_URL') && define('PAYPAL_API_URL', 'https://api.paypal.com'); + !defined('PAYPAL_SANDBOX_API_URL') && define('PAYPAL_SANDBOX_API_URL', 'https://api.sandbox.paypal.com'); + !defined('PAYPAL_INTEGRATION_DATE') && define('PAYPAL_INTEGRATION_DATE', '2020-10-15'); + + !defined('PPCP_FLAG_SUBSCRIPTION') && define('PPCP_FLAG_SUBSCRIPTION', true); + + !defined('CONNECT_WOO_CLIENT_ID') && define('CONNECT_WOO_CLIENT_ID', 'woo-id'); + !defined('CONNECT_WOO_SANDBOX_CLIENT_ID') && define('CONNECT_WOO_SANDBOX_CLIENT_ID', 'woo-id2'); + !defined('CONNECT_WOO_MERCHANT_ID') && define('CONNECT_WOO_MERCHANT_ID', 'merchant-id'); + !defined('CONNECT_WOO_SANDBOX_MERCHANT_ID') && define('CONNECT_WOO_SANDBOX_MERCHANT_ID', 'merchant-id2'); + !defined('CONNECT_WOO_URL') && define('CONNECT_WOO_URL', 'https://connect.woocommerce.com/ppc'); + !defined('CONNECT_WOO_SANDBOX_URL') && define('CONNECT_WOO_SANDBOX_URL', 'https://connect.woocommerce.com/ppcsandbox'); + } + + /** + * @param array $overriddenServices + * @return ContainerInterface + */ + protected function bootstrapModule(array $overriddenServices = []): ContainerInterface + { + $overridingContainer = new DelegatingContainer(new CompositeCachingServiceProvider([ + new ServiceProvider($overriddenServices, []), + ])); + + $rootDir = ROOT_DIR; + $bootstrap = require ("$rootDir/bootstrap.php"); + $appContainer = $bootstrap($rootDir, $overridingContainer); + + return $appContainer; + } +} diff --git a/tests/PHPUnit/TestCase.php b/tests/PHPUnit/TestCase.php index 4f4e6a532..8d7d821bd 100644 --- a/tests/PHPUnit/TestCase.php +++ b/tests/PHPUnit/TestCase.php @@ -3,26 +3,36 @@ namespace WooCommerce\PayPalCommerce; +use function Brain\Monkey\Functions\when; use function Brain\Monkey\setUp; use function Brain\Monkey\tearDown; -use function Brain\Monkey\Functions\expect; use Mockery; class TestCase extends \PHPUnit\Framework\TestCase { - public function setUp(): void - { - parent::setUp(); - expect('__')->andReturnUsing(function (string $text) { - return $text; - }); - setUp(); - } + public function setUp(): void + { + parent::setUp(); - public function tearDown(): void - { - tearDown(); - Mockery::close(); - parent::tearDown(); - } + when('__')->returnArg(); + when('_x')->returnArg(); + when('esc_url')->returnArg(); + when('esc_attr')->returnArg(); + when('esc_attr__')->returnArg(); + when('esc_html')->returnArg(); + when('esc_html__')->returnArg(); + when('esc_textarea')->returnArg(); + when('sanitize_text_field')->returnArg(); + when('wp_kses_post')->returnArg(); + when('wp_unslash')->returnArg(); + + setUp(); + } + + public function tearDown(): void + { + tearDown(); + Mockery::close(); + parent::tearDown(); + } } diff --git a/tests/PHPUnit/WcGateway/Gateway/WcGatewayTest.php b/tests/PHPUnit/WcGateway/Gateway/WcGatewayTest.php index 9cef49c38..65ed9776c 100644 --- a/tests/PHPUnit/WcGateway/Gateway/WcGatewayTest.php +++ b/tests/PHPUnit/WcGateway/Gateway/WcGatewayTest.php @@ -68,7 +68,8 @@ function(\WC_Order $order) use ($wcOrder) : bool { $refundProcessor, $state, $transactionUrlProvider, - $subscriptionHelper + $subscriptionHelper, + PayPalGateway::ID ); expect('wc_get_order') @@ -116,7 +117,8 @@ public function testProcessPaymentOrderNotFound() { $refundProcessor, $state, $transactionUrlProvider, - $subscriptionHelper + $subscriptionHelper, + PayPalGateway::ID ); expect('wc_get_order') @@ -181,7 +183,8 @@ public function testProcessPaymentFails() { $refundProcessor, $state, $transactionUrlProvider, - $subscriptionHelper + $subscriptionHelper, + PayPalGateway::ID ); expect('wc_get_order') @@ -254,7 +257,8 @@ public function testCaptureAuthorizedPayment() { $refundProcessor, $state, $transactionUrlProvider, - $subscriptionHelper + $subscriptionHelper, + PayPalGateway::ID ); $this->assertTrue($testee->capture_authorized_payment($wcOrder)); @@ -311,7 +315,8 @@ public function testCaptureAuthorizedPaymentHasAlreadyBeenCaptured() { $refundProcessor, $state, $transactionUrlProvider, - $subscriptionHelper + $subscriptionHelper, + PayPalGateway::ID ); $this->assertTrue($testee->capture_authorized_payment($wcOrder)); @@ -362,12 +367,13 @@ public function testCaptureAuthorizedPaymentNoActionableFailures($lastStatus, $e $refundProcessor, $state, $transactionUrlProvider, - $subscriptionHelper + $subscriptionHelper, + PayPalGateway::ID ); $this->assertFalse($testee->capture_authorized_payment($wcOrder)); } - + /** * @dataProvider dataForTestNeedsSetup */ @@ -390,7 +396,7 @@ public function testNeedsSetup($currentState, $needSetup) ->andReturn($currentState); $transactionUrlProvider = Mockery::mock(TransactionUrlProvider::class); $subscriptionHelper = Mockery::mock(SubscriptionHelper::class); - + $testee = new PayPalGateway( $settingsRenderer, $orderProcessor, @@ -401,9 +407,10 @@ public function testNeedsSetup($currentState, $needSetup) $refundProcessor, $onboardingState, $transactionUrlProvider, - $subscriptionHelper + $subscriptionHelper, + PayPalGateway::ID ); - + $this->assertSame($needSetup, $testee->needs_setup()); } @@ -424,7 +431,7 @@ public function dataForTestCaptureAuthorizedPaymentNoActionableFailures() : arra ], ]; } - + public function dataForTestNeedsSetup(): array { return [ diff --git a/tests/PHPUnit/WcGateway/Settings/SettingsListenerTest.php b/tests/PHPUnit/WcGateway/Settings/SettingsListenerTest.php index 11c48bcd5..050b87e40 100644 --- a/tests/PHPUnit/WcGateway/Settings/SettingsListenerTest.php +++ b/tests/PHPUnit/WcGateway/Settings/SettingsListenerTest.php @@ -4,63 +4,77 @@ use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer; use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache; +use WooCommerce\PayPalCommerce\ModularTestCase; use WooCommerce\PayPalCommerce\Onboarding\State; -use WooCommerce\PayPalCommerce\TestCase; use Mockery; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use WooCommerce\PayPalCommerce\Webhooks\WebhookRegistrar; use function Brain\Monkey\Functions\when; -use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; -class SettingsListenerTest extends TestCase +class SettingsListenerTest extends ModularTestCase { - use MockeryPHPUnitIntegration; + private $appContainer; - public function testListen() - { - $settings = Mockery::mock(Settings::class); - $setting_fields = []; - $webhook_registrar = Mockery::mock(WebhookRegistrar::class); - $cache = Mockery::mock(Cache::class); - $state = Mockery::mock(State::class); - $bearer = Mockery::mock(Bearer::class); + public function setUp(): void + { + parent::setUp(); - $testee = new SettingsListener( - $settings, - $setting_fields, - $webhook_registrar, - $cache, - $state, - $bearer - ); + $this->appContainer = $this->bootstrapModule(); + } - $_REQUEST['section'] = 'ppcp-gateway'; - $_POST['ppcp-nonce'] = 'foo'; - $_POST['ppcp'] = [ - 'client_id' => 'client_id', - ]; - $_GET['ppcp-tab'] = 'just-a-tab'; + public function testListen() + { + $settings = Mockery::mock(Settings::class); + $settings->shouldReceive('set'); - when('sanitize_text_field')->justReturn('ppcp-gateway'); - when('wp_unslash')->justReturn('ppcp-gateway'); - when('current_user_can')->justReturn(true); - when('wp_verify_nonce')->justReturn(true); + $setting_fields = $this->appContainer->get('wcgateway.settings.fields'); - $settings->shouldReceive('has') - ->with('client_id') - ->andReturn('client_id'); - $settings->shouldReceive('get') - ->with('client_id') - ->andReturn('client_id'); - $settings->shouldReceive('has') - ->with('client_secret') - ->andReturn('client_secret'); - $settings->shouldReceive('get') - ->with('client_secret') - ->andReturn('client_secret'); - $settings->shouldReceive('persist'); - $cache->shouldReceive('has') - ->andReturn(false); + $webhook_registrar = Mockery::mock(WebhookRegistrar::class); + $webhook_registrar->shouldReceive('unregister')->andReturnTrue(); + $webhook_registrar->shouldReceive('register')->andReturnTrue(); - $testee->listen(); - } + $cache = Mockery::mock(Cache::class); + + $state = Mockery::mock(State::class); + $state->shouldReceive('current_state')->andReturn(State::STATE_ONBOARDED); + $bearer = Mockery::mock(Bearer::class); + + $testee = new SettingsListener( + $settings, + $setting_fields, + $webhook_registrar, + $cache, + $state, + $bearer, + PayPalGateway::ID + ); + + $_GET['section'] = PayPalGateway::ID; + $_POST['ppcp-nonce'] = 'foo'; + $_POST['ppcp'] = [ + 'client_id' => 'client_id', + ]; + $_GET['ppcp-tab'] = PayPalGateway::ID; + + when('current_user_can')->justReturn(true); + when('wp_verify_nonce')->justReturn(true); + + $settings->shouldReceive('has') + ->with('client_id') + ->andReturn('client_id'); + $settings->shouldReceive('get') + ->with('client_id') + ->andReturn('client_id'); + $settings->shouldReceive('has') + ->with('client_secret') + ->andReturn('client_secret'); + $settings->shouldReceive('get') + ->with('client_secret') + ->andReturn('client_secret'); + $settings->shouldReceive('persist'); + $cache->shouldReceive('has') + ->andReturn(false); + + $testee->listen(); + } } diff --git a/tests/PHPUnit/bootstrap.php b/tests/PHPUnit/bootstrap.php index ba6ffb319..2e2b3350e 100644 --- a/tests/PHPUnit/bootstrap.php +++ b/tests/PHPUnit/bootstrap.php @@ -1,6 +1,10 @@ setup(); - } - $proxy = new ProxyContainer(); - $provider = new CompositeCachingServiceProvider( $providers ); - $container = new CachingContainer( new DelegatingContainer( $provider ) ); - $proxy->setInnerContainer( $container ); - foreach ( $modules as $module ) { - /* @var $module ModuleInterface module */ - $module->run( $container ); - } $initialized = true; - do_action( 'woocommerce_paypal_payments_built_container', $proxy ); + do_action( 'woocommerce_paypal_payments_built_container', $app_container ); } }