diff --git a/includes/payment-methods/class-affirm-payment-method.php b/includes/payment-methods/class-affirm-payment-method.php
index 4be64bf653d..5ae0cd453ac 100644
--- a/includes/payment-methods/class-affirm-payment-method.php
+++ b/includes/payment-methods/class-affirm-payment-method.php
@@ -10,6 +10,7 @@
use WC_Payments_Token_Service;
use WC_Payments_Utils;
use WCPay\Constants\Country_Code;
+use WCPay\Constants\Currency_Code;
use WCPay\MultiCurrency\MultiCurrency;
/**
@@ -30,16 +31,16 @@ public function __construct( $token_service ) {
$this->title = __( 'Affirm', 'woocommerce-payments' );
$this->is_reusable = false;
$this->icon_url = plugins_url( 'assets/images/payment-methods/affirm.svg', WCPAY_PLUGIN_FILE );
- $this->currencies = [ 'USD', 'CAD' ];
+ $this->currencies = [ Currency_Code::UNITED_STATES_DOLLAR, Currency_Code::CANADIAN_DOLLAR ];
$this->accept_only_domestic_payment = true;
$this->limits_per_currency = [
- 'CAD' => [
+ Currency_Code::CANADIAN_DOLLAR => [
Country_Code::CANADA => [
'min' => 5000,
'max' => 3000000,
], // Represents CAD 50 - 30,000 CAD.
],
- 'USD' => [
+ Currency_Code::UNITED_STATES_DOLLAR => [
Country_Code::UNITED_STATES => [
'min' => 5000,
'max' => 3000000,
diff --git a/includes/payment-methods/class-afterpay-payment-method.php b/includes/payment-methods/class-afterpay-payment-method.php
index 9984ae212b7..94aa1ec4f28 100644
--- a/includes/payment-methods/class-afterpay-payment-method.php
+++ b/includes/payment-methods/class-afterpay-payment-method.php
@@ -10,6 +10,7 @@
use WC_Payments_Token_Service;
use WC_Payments_Utils;
use WCPay\Constants\Country_Code;
+use WCPay\Constants\Currency_Code;
/**
* Afterpay Payment Method class extending UPE base class
@@ -29,34 +30,34 @@ public function __construct( $token_service ) {
$this->title = __( 'Afterpay', 'woocommerce-payments' );
$this->is_reusable = false;
$this->icon_url = plugins_url( 'assets/images/payment-methods/afterpay.svg', WCPAY_PLUGIN_FILE );
- $this->currencies = [ 'USD', 'CAD', 'AUD', 'NZD', 'GBP' ];
+ $this->currencies = [ Currency_Code::UNITED_STATES_DOLLAR, Currency_Code::CANADIAN_DOLLAR, Currency_Code::AUSTRALIAN_DOLLAR, Currency_Code::NEW_ZEALAND_DOLLAR, Currency_Code::POUND_STERLING ];
$this->accept_only_domestic_payment = true;
$this->limits_per_currency = [
- 'AUD' => [
+ Currency_Code::AUSTRALIAN_DOLLAR => [
Country_Code::AUSTRALIA => [
'min' => 100,
'max' => 200000,
], // Represents AUD 1 - 2,000 AUD.
],
- 'CAD' => [
+ Currency_Code::CANADIAN_DOLLAR => [
Country_Code::CANADA => [
'min' => 100,
'max' => 200000,
], // Represents CAD 1 - 2,000 CAD.
],
- 'NZD' => [
+ Currency_Code::NEW_ZEALAND_DOLLAR => [
Country_Code::NEW_ZEALAND => [
'min' => 100,
'max' => 200000,
], // Represents NZD 1 - 2,000 NZD.
],
- 'GBP' => [
+ Currency_Code::POUND_STERLING => [
Country_Code::UNITED_KINGDOM => [
'min' => 100,
'max' => 120000,
], // Represents GBP 1 - 1,200 GBP.
],
- 'USD' => [
+ Currency_Code::UNITED_STATES_DOLLAR => [
Country_Code::UNITED_STATES => [
'min' => 100,
'max' => 400000,
@@ -65,6 +66,35 @@ public function __construct( $token_service ) {
];
}
+ /**
+ * Returns payment method title.
+ *
+ * @param string|null $account_country Country of merchants account.
+ * @param array|false $payment_details Optional payment details from charge object.
+ * @return string|null
+ */
+ public function get_title( string $account_country = null, $payment_details = false ) {
+ if ( 'GB' === $account_country ) {
+ return __( 'Clearpay', 'woocommerce-payments' );
+ }
+
+ return __( 'Afterpay', 'woocommerce-payments' );
+ }
+
+ /**
+ * Returns payment method icon.
+ *
+ * @param string|null $account_country Country of merchants account.
+ * @return string|null
+ */
+ public function get_icon( string $account_country = null ) {
+ if ( 'GB' === $account_country ) {
+ return plugins_url( 'assets/images/payment-methods/clearpay.svg', WCPAY_PLUGIN_FILE );
+ }
+
+ return plugins_url( 'assets/images/payment-methods/afterpay.svg', WCPAY_PLUGIN_FILE );
+ }
+
/**
* Returns testing credentials to be printed at checkout in test mode.
*
diff --git a/includes/payment-methods/class-bancontact-payment-method.php b/includes/payment-methods/class-bancontact-payment-method.php
index aa936112f2a..af5d25f774e 100644
--- a/includes/payment-methods/class-bancontact-payment-method.php
+++ b/includes/payment-methods/class-bancontact-payment-method.php
@@ -8,6 +8,8 @@
namespace WCPay\Payment_Methods;
use WC_Payments_Token_Service;
+use WCPay\Constants\Country_Code;
+use WCPay\Constants\Currency_Code;
/**
* Bancontact Payment Method class extending UPE base class
@@ -26,8 +28,9 @@ public function __construct( $token_service ) {
$this->stripe_id = self::PAYMENT_METHOD_STRIPE_ID;
$this->title = 'Bancontact';
$this->is_reusable = false;
- $this->currencies = [ 'EUR' ];
+ $this->currencies = [ Currency_Code::EURO ];
$this->icon_url = plugins_url( 'assets/images/payment-methods/bancontact.svg', WCPAY_PLUGIN_FILE );
+ $this->countries = [ Country_Code::BELGIUM ];
}
/**
diff --git a/includes/payment-methods/class-becs-payment-method.php b/includes/payment-methods/class-becs-payment-method.php
index 69def13594a..88cfd9d8199 100644
--- a/includes/payment-methods/class-becs-payment-method.php
+++ b/includes/payment-methods/class-becs-payment-method.php
@@ -8,6 +8,8 @@
namespace WCPay\Payment_Methods;
use WC_Payments_Token_Service;
+use WCPay\Constants\Country_Code;
+use WCPay\Constants\Currency_Code;
/**
* Becs Payment Method class extending UPE base class
@@ -26,8 +28,9 @@ public function __construct( $token_service ) {
$this->stripe_id = self::PAYMENT_METHOD_STRIPE_ID;
$this->title = 'BECS Direct Debit';
$this->is_reusable = false;
- $this->currencies = [ 'AUD' ];
+ $this->currencies = [ Currency_Code::AUSTRALIAN_DOLLAR ];
$this->icon_url = plugins_url( 'assets/images/payment-methods/bank-debit.svg', WCPAY_PLUGIN_FILE );
+ $this->countries = [ Country_Code::AUSTRALIA ];
}
/**
diff --git a/includes/payment-methods/class-cc-payment-method.php b/includes/payment-methods/class-cc-payment-method.php
index dfd20c3eaf6..ae7f0a485dd 100644
--- a/includes/payment-methods/class-cc-payment-method.php
+++ b/includes/payment-methods/class-cc-payment-method.php
@@ -33,11 +33,11 @@ public function __construct( $token_service ) {
/**
* Returns payment method title
*
- * @param array|bool $payment_details Optional payment details from charge object.
- *
+ * @param string|null $account_country Account country.
+ * @param array|false $payment_details Payment details.
* @return string
*/
- public function get_title( $payment_details = false ) {
+ public function get_title( string $account_country = null, $payment_details = false ) {
if ( ! $payment_details ) {
return $this->title;
}
diff --git a/includes/payment-methods/class-eps-payment-method.php b/includes/payment-methods/class-eps-payment-method.php
index f4edea97f1c..5b2e73ed441 100644
--- a/includes/payment-methods/class-eps-payment-method.php
+++ b/includes/payment-methods/class-eps-payment-method.php
@@ -8,6 +8,8 @@
namespace WCPay\Payment_Methods;
use WC_Payments_Token_Service;
+use WCPay\Constants\Country_Code;
+use WCPay\Constants\Currency_Code;
/**
* EPS Payment Method class extending UPE base class
@@ -26,8 +28,9 @@ public function __construct( $token_service ) {
$this->stripe_id = self::PAYMENT_METHOD_STRIPE_ID;
$this->title = 'EPS';
$this->is_reusable = false;
- $this->currencies = [ 'EUR' ];
+ $this->currencies = [ Currency_Code::EURO ];
$this->icon_url = plugins_url( 'assets/images/payment-methods/eps.svg', WCPAY_PLUGIN_FILE );
+ $this->countries = [ Country_Code::AUSTRIA ];
}
/**
diff --git a/includes/payment-methods/class-giropay-payment-method.php b/includes/payment-methods/class-giropay-payment-method.php
index 1dfce93aa4a..b117382f0da 100644
--- a/includes/payment-methods/class-giropay-payment-method.php
+++ b/includes/payment-methods/class-giropay-payment-method.php
@@ -8,6 +8,8 @@
namespace WCPay\Payment_Methods;
use WC_Payments_Token_Service;
+use WCPay\Constants\Country_Code;
+use WCPay\Constants\Currency_Code;
/**
* Giropay Payment Method class extending UPE base class
@@ -26,8 +28,9 @@ public function __construct( $token_service ) {
$this->stripe_id = self::PAYMENT_METHOD_STRIPE_ID;
$this->title = 'giropay';
$this->is_reusable = false;
- $this->currencies = [ 'EUR' ];
+ $this->currencies = [ Currency_Code::EURO ];
$this->icon_url = plugins_url( 'assets/images/payment-methods/giropay.svg', WCPAY_PLUGIN_FILE );
+ $this->countries = [ Country_Code::GERMANY ];
}
/**
diff --git a/includes/payment-methods/class-ideal-payment-method.php b/includes/payment-methods/class-ideal-payment-method.php
index 1a642e612aa..084499b6efe 100644
--- a/includes/payment-methods/class-ideal-payment-method.php
+++ b/includes/payment-methods/class-ideal-payment-method.php
@@ -8,6 +8,8 @@
namespace WCPay\Payment_Methods;
use WC_Payments_Token_Service;
+use WCPay\Constants\Country_Code;
+use WCPay\Constants\Currency_Code;
/**
* IDEAL Payment Method class extending UPE base class
@@ -26,8 +28,9 @@ public function __construct( $token_service ) {
$this->stripe_id = self::PAYMENT_METHOD_STRIPE_ID;
$this->title = 'iDEAL';
$this->is_reusable = false;
- $this->currencies = [ 'EUR' ];
+ $this->currencies = [ Currency_Code::EURO ];
$this->icon_url = plugins_url( 'assets/images/payment-methods/ideal.svg', WCPAY_PLUGIN_FILE );
+ $this->countries = [ Country_Code::NETHERLANDS ];
}
/**
diff --git a/includes/payment-methods/class-klarna-payment-method.php b/includes/payment-methods/class-klarna-payment-method.php
index 9127cd16d48..6757ff048ce 100644
--- a/includes/payment-methods/class-klarna-payment-method.php
+++ b/includes/payment-methods/class-klarna-payment-method.php
@@ -10,6 +10,7 @@
use WC_Payments_Token_Service;
use WC_Payments_Utils;
use WCPay\Constants\Country_Code;
+use WCPay\Constants\Currency_Code;
use WCPay\MultiCurrency\MultiCurrency;
/**
@@ -30,23 +31,23 @@ public function __construct( $token_service ) {
$this->title = __( 'Klarna', 'woocommerce-payments' );
$this->is_reusable = false;
$this->icon_url = plugins_url( 'assets/images/payment-methods/klarna.svg', WCPAY_PLUGIN_FILE );
- $this->currencies = [ 'USD', 'GBP', 'EUR', 'DKK', 'NOK', 'SEK' ];
+ $this->currencies = [ Currency_Code::UNITED_STATES_DOLLAR, Currency_Code::POUND_STERLING, Currency_Code::EURO, Currency_Code::DANISH_KRONE, Currency_Code::NORWEGIAN_KRONE, Currency_Code::SWEDISH_KRONA ];
$this->accept_only_domestic_payment = true;
$this->countries = [ Country_Code::UNITED_STATES, Country_Code::UNITED_KINGDOM, Country_Code::AUSTRIA, Country_Code::GERMANY, Country_Code::NETHERLANDS, Country_Code::BELGIUM, Country_Code::SPAIN, Country_Code::ITALY, Country_Code::IRELAND, Country_Code::DENMARK, Country_Code::FINLAND, Country_Code::NORWAY, Country_Code::SWEDEN ];
$this->limits_per_currency = [
- 'USD' => [
+ Currency_Code::UNITED_STATES_DOLLAR => [
Country_Code::UNITED_STATES => [
'min' => 0,
'max' => 1000000,
],
],
- 'GBP' => [
+ Currency_Code::POUND_STERLING => [
Country_Code::UNITED_KINGDOM => [
'min' => 0,
'max' => 1150000,
],
],
- 'EUR' => [
+ Currency_Code::EURO => [
Country_Code::AUSTRIA => [
'min' => 1,
'max' => 1000000,
@@ -80,19 +81,19 @@ public function __construct( $token_service ) {
'max' => 1000000,
],
],
- 'DKK' => [
+ Currency_Code::DANISH_KRONE => [
Country_Code::DENMARK => [
'min' => 100,
'max' => 100000000,
],
],
- 'NOK' => [
+ Currency_Code::NORWEGIAN_KRONE => [
Country_Code::NORWAY => [
'min' => 0,
'max' => 100000000,
],
],
- 'SEK' => [
+ Currency_Code::SWEDISH_KRONA => [
Country_Code::SWEDEN => [
'min' => 0,
'max' => 15000000,
diff --git a/includes/payment-methods/class-link-payment-method.php b/includes/payment-methods/class-link-payment-method.php
index 23943f16309..6a9b904a03f 100644
--- a/includes/payment-methods/class-link-payment-method.php
+++ b/includes/payment-methods/class-link-payment-method.php
@@ -8,6 +8,7 @@
namespace WCPay\Payment_Methods;
use WC_Payments_Token_Service;
+use WCPay\Constants\Currency_Code;
/**
* Link Payment Method class extending UPE base class
@@ -26,7 +27,7 @@ public function __construct( $token_service ) {
$this->stripe_id = self::PAYMENT_METHOD_STRIPE_ID;
$this->title = __( 'Link', 'woocommerce-payments' );
$this->is_reusable = true;
- $this->currencies = [ 'USD' ];
+ $this->currencies = [ Currency_Code::UNITED_STATES_DOLLAR ];
$this->icon_url = plugins_url( 'assets/images/payment-methods/link.svg', WCPAY_PLUGIN_FILE );
}
diff --git a/includes/payment-methods/class-p24-payment-method.php b/includes/payment-methods/class-p24-payment-method.php
index 73e388e1eaa..8718911b480 100644
--- a/includes/payment-methods/class-p24-payment-method.php
+++ b/includes/payment-methods/class-p24-payment-method.php
@@ -8,6 +8,8 @@
namespace WCPay\Payment_Methods;
use WC_Payments_Token_Service;
+use WCPay\Constants\Country_Code;
+use WCPay\Constants\Currency_Code;
/**
* P24 Payment Method class extending UPE base class
@@ -26,8 +28,9 @@ public function __construct( $token_service ) {
$this->stripe_id = self::PAYMENT_METHOD_STRIPE_ID;
$this->title = 'Przelewy24 (P24)';
$this->is_reusable = false;
- $this->currencies = [ 'EUR', 'PLN' ];
+ $this->currencies = [ Currency_Code::EURO, Currency_Code::POLISH_ZLOTY ];
$this->icon_url = plugins_url( 'assets/images/payment-methods/p24.svg', WCPAY_PLUGIN_FILE );
+ $this->countries = [ Country_Code::POLAND ];
}
/**
diff --git a/includes/payment-methods/class-sepa-payment-method.php b/includes/payment-methods/class-sepa-payment-method.php
index 914363f7710..b11801ee738 100644
--- a/includes/payment-methods/class-sepa-payment-method.php
+++ b/includes/payment-methods/class-sepa-payment-method.php
@@ -8,6 +8,8 @@
namespace WCPay\Payment_Methods;
use WC_Payments_Token_Service;
+use WCPay\Constants\Country_Code;
+use WCPay\Constants\Currency_Code;
/**
* Sepa Payment Method class extending UPE base class
@@ -26,8 +28,13 @@ public function __construct( $token_service ) {
$this->stripe_id = self::PAYMENT_METHOD_STRIPE_ID;
$this->title = 'SEPA Direct Debit';
$this->is_reusable = false;
- $this->currencies = [ 'EUR' ];
+ $this->currencies = [ Currency_Code::EURO ];
$this->icon_url = plugins_url( 'assets/images/payment-methods/sepa-debit.svg', WCPAY_PLUGIN_FILE );
+
+ // https://stripe.com/en-br/resources/more/sepa-country-list#list-of-sepa-countries.
+ $eu_countries = [ Country_Code::AUSTRIA, Country_Code::BELGIUM, Country_Code::BULGARIA, Country_Code::CROATIA, Country_Code::CYPRUS, Country_Code::CZECHIA, Country_Code::DENMARK, Country_Code::ESTONIA, Country_Code::FINLAND, Country_Code::FRANCE, Country_Code::GERMANY, Country_Code::GREECE, Country_Code::HUNGARY, Country_Code::IRELAND, Country_Code::ITALY, Country_Code::LATVIA, Country_Code::LITHUANIA, Country_Code::LUXEMBOURG, Country_Code::MALTA, Country_Code::NETHERLANDS, Country_Code::POLAND, Country_Code::PORTUGAL, Country_Code::ROMANIA, Country_Code::SLOVAKIA, Country_Code::SLOVENIA, Country_Code::SPAIN, Country_Code::SWEDEN ];
+ $additional_sepa_countries = [ Country_Code::SWITZERLAND, Country_Code::UNITED_KINGDOM, Country_Code::SAN_MARINO, Country_Code::VATICAN_CITY, Country_Code::ANDORRA, Country_Code::MONACO, Country_Code::LIECHTENSTEIN, Country_Code::NORWAY, Country_Code::ICELAND ];
+ $this->countries = array_merge( $eu_countries, $additional_sepa_countries );
}
/**
diff --git a/includes/payment-methods/class-sofort-payment-method.php b/includes/payment-methods/class-sofort-payment-method.php
index a9d254d107f..2f4f4fba212 100644
--- a/includes/payment-methods/class-sofort-payment-method.php
+++ b/includes/payment-methods/class-sofort-payment-method.php
@@ -7,8 +7,10 @@
namespace WCPay\Payment_Methods;
+use WCPay\Constants\Country_Code;
use WP_User;
use WC_Payments_Token_Service;
+use WCPay\Constants\Currency_Code;
/**
* Sofort Payment Method class extending UPE base class
@@ -27,8 +29,9 @@ public function __construct( $token_service ) {
$this->stripe_id = self::PAYMENT_METHOD_STRIPE_ID;
$this->title = 'Sofort';
$this->is_reusable = false;
- $this->currencies = [ 'EUR' ];
+ $this->currencies = [ Currency_Code::EURO ];
$this->icon_url = plugins_url( 'assets/images/payment-methods/sofort.svg', WCPAY_PLUGIN_FILE );
+ $this->countries = [ Country_Code::AUSTRIA, Country_Code::BELGIUM, Country_Code::GERMANY, Country_Code::NETHERLANDS, Country_Code::SPAIN ];
}
/**
diff --git a/includes/payment-methods/class-upe-payment-method.php b/includes/payment-methods/class-upe-payment-method.php
index ddc954e719f..6f0fa965a88 100644
--- a/includes/payment-methods/class-upe-payment-method.php
+++ b/includes/payment-methods/class-upe-payment-method.php
@@ -113,11 +113,12 @@ public function get_id() {
/**
* Returns payment method title
*
- * @param array|bool $payment_details Optional payment details from charge object.
+ * @param string|null $account_country Country of merchants account.
+ * @param array|false $payment_details Optional payment details from charge object.
*
* @return string
*/
- public function get_title( $payment_details = false ) {
+ public function get_title( string $account_country = null, $payment_details = false ) {
return $this->title;
}
@@ -224,9 +225,10 @@ abstract public function get_testing_instructions();
/**
* Returns the payment method icon URL or an empty string.
*
+ * @param string|null $account_country Optional account country.
* @return string
*/
- public function get_icon() {
+ public function get_icon( string $account_country = null ) {
return isset( $this->icon_url ) ? $this->icon_url : '';
}
diff --git a/includes/wc-payment-api/class-wc-payments-api-client.php b/includes/wc-payment-api/class-wc-payments-api-client.php
index 18fb4a6a9c2..826b1434be7 100644
--- a/includes/wc-payment-api/class-wc-payments-api-client.php
+++ b/includes/wc-payment-api/class-wc-payments-api-client.php
@@ -416,12 +416,13 @@ public function get_fraud_outcome_transactions_export( $request ) {
* @param array $filters The filters to be used in the query.
* @param string $user_email The email to search for.
* @param string $deposit_id The deposit to filter on.
+ * @param string $locale Site locale.
*
* @return array Export summary
*
* @throws API_Exception - Exception thrown on request failure.
*/
- public function get_transactions_export( $filters = [], $user_email = '', $deposit_id = null ) {
+ public function get_transactions_export( $filters = [], $user_email = '', $deposit_id = null, $locale = null ) {
// Map Order # terms to the actual charge id to be used in the server.
if ( ! empty( $filters['search'] ) ) {
$filters['search'] = WC_Payments_Utils::map_search_orders_to_charge_ids( $filters['search'] );
@@ -432,6 +433,9 @@ public function get_transactions_export( $filters = [], $user_email = '', $depos
if ( ! empty( $deposit_id ) ) {
$filters['deposit_id'] = $deposit_id;
}
+ if ( ! empty( $locale ) ) {
+ $filters['locale'] = $locale;
+ }
return $this->request( $filters, self::TRANSACTIONS_API . '/download', self::POST );
}
@@ -578,15 +582,19 @@ public function close_dispute( $dispute_id ) {
*
* @param array $filters The filters to be used in the query.
* @param string $user_email The email to search for.
+ * @param string $locale Site locale.
*
* @return array Export summary
*
* @throws API_Exception - Exception thrown on request failure.
*/
- public function get_disputes_export( $filters = [], $user_email = '' ) {
+ public function get_disputes_export( $filters = [], $user_email = '', $locale = null ) {
if ( ! empty( $user_email ) ) {
$filters['user_email'] = $user_email;
}
+ if ( ! empty( $locale ) ) {
+ $filters['locale'] = $locale;
+ }
return $this->request( $filters, self::DISPUTES_API . '/download', self::POST );
}
@@ -596,15 +604,19 @@ public function get_disputes_export( $filters = [], $user_email = '' ) {
*
* @param array $filters The filters to be used in the query.
* @param string $user_email The email to send export to.
+ * @param string $locale Site locale.
*
* @return array Export summary
*
* @throws API_Exception - Exception thrown on request failure.
*/
- public function get_deposits_export( $filters = [], $user_email = '' ) {
+ public function get_deposits_export( $filters = [], $user_email = '', $locale = null ) {
if ( ! empty( $user_email ) ) {
$filters['user_email'] = $user_email;
}
+ if ( ! empty( $locale ) ) {
+ $filters['locale'] = $locale;
+ }
return $this->request( $filters, self::DEPOSITS_API . '/download', self::POST );
}
diff --git a/includes/woopay/class-woopay-order-status-sync.php b/includes/woopay/class-woopay-order-status-sync.php
index 2cb9416ab73..98c7ceb79e3 100644
--- a/includes/woopay/class-woopay-order-status-sync.php
+++ b/includes/woopay/class-woopay-order-status-sync.php
@@ -7,6 +7,7 @@
namespace WCPay\WooPay;
+use WC_Payments_Account;
use WC_Payments_API_Client;
use WCPay\Exceptions\API_Exception;
@@ -21,6 +22,13 @@
class WooPay_Order_Status_Sync {
const WCPAY_WEBHOOK_WOOPAY_ORDER_STATUS_CHANGED = 'wcpay_webhook_platform_checkout_order_status_changed';
+ /**
+ * WC_Payments_Account instance to get information about the account
+ *
+ * @var WC_Payments_Account
+ */
+ private $account;
+
/**
* Client for making requests to the WooCommerce Payments API
*
@@ -32,10 +40,12 @@ class WooPay_Order_Status_Sync {
* Setup webhook for the WooPay Order Status Sync.
*
* @param WC_Payments_API_Client $payments_api_client - WooCommerce Payments API client.
+ * @param WC_Payments_Account $account - WooCommerce Payments account.
*/
- public function __construct( WC_Payments_API_Client $payments_api_client ) {
+ public function __construct( WC_Payments_API_Client $payments_api_client, WC_Payments_Account $account ) {
$this->payments_api_client = $payments_api_client;
+ $this->account = $account;
add_filter( 'woocommerce_webhook_topic_hooks', [ __CLASS__, 'add_topics' ], 20, 2 );
add_filter( 'woocommerce_webhook_payload', [ __CLASS__, 'create_payload' ], 10, 4 );
@@ -63,6 +73,10 @@ public function maybe_create_woopay_order_webhook() {
return;
}
+ if ( $this->account->is_account_rejected() ) {
+ return;
+ }
+
$this->register_webhook();
}
diff --git a/includes/woopay/class-woopay-session.php b/includes/woopay/class-woopay-session.php
index 42a5ec09c67..e4712c6d9b0 100644
--- a/includes/woopay/class-woopay-session.php
+++ b/includes/woopay/class-woopay-session.php
@@ -111,6 +111,8 @@ public static function determine_current_user_for_woopay( $user ) {
wp_die( esc_html__( 'WooPay request is not signed correctly.', 'woocommerce-payments' ), 401 );
}
+ add_filter( 'wcpay_is_woopay_store_api_request', '__return_true' );
+
$cart_token_user_id = self::get_user_id_from_cart_token();
if ( null === $cart_token_user_id ) {
return $user;
@@ -543,6 +545,14 @@ public static function ajax_get_woopay_session() {
);
}
+ $blog_id = Jetpack_Options::get_option('id');
+ if ( empty( $blog_id ) ) {
+ wp_send_json_error(
+ __( 'Could not determine the blog ID.', 'woocommerce-payments' ),
+ 503
+ );
+ }
+
wp_send_json( self::get_frontend_init_session_request() );
}
diff --git a/package-lock.json b/package-lock.json
index ffbacceb596..fb84c0e080b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "woocommerce-payments",
- "version": "7.1.0",
+ "version": "7.2.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "woocommerce-payments",
- "version": "7.1.0",
+ "version": "7.2.0",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
diff --git a/package.json b/package.json
index 0152e41271c..7a7e308b8ac 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "woocommerce-payments",
- "version": "7.1.0",
+ "version": "7.2.0",
"main": "webpack.config.js",
"author": "Automattic",
"license": "GPL-3.0-or-later",
@@ -33,7 +33,7 @@
"test:e2e-up": "./tests/e2e/env/up.sh",
"test:e2e-cleanup": "./tests/e2e/env/cleanup.sh",
"test:e2e-reset": "npm run test:e2e-down && npm run test:e2e-cleanup",
- "test:e2e": "NODE_CONFIG_DIR='tests/e2e/config' wp-scripts test-e2e --config tests/e2e/config/jest.config.js",
+ "test:e2e": "NODE_CONFIG_DIR='tests/e2e/config' JEST_PUPPETEER_CONFIG='tests/e2e/config/jest-puppeteer-headless.config.js' wp-scripts test-e2e --config tests/e2e/config/jest.config.js",
"test:e2e-dev": "NODE_CONFIG_DIR='tests/e2e/config' JEST_PUPPETEER_CONFIG='tests/e2e/config/jest-puppeteer.config.js' wp-scripts test-e2e --config tests/e2e/config/jest.config.js --puppeteer-interactive",
"test:e2e-performance": "NODE_CONFIG_DIR='tests/e2e/config' wp-scripts test-e2e --config tests/e2e/config/jest.performance.config.js",
"test:update-snapshots": "npm run test:js -- --updateSnapshot",
diff --git a/readme.txt b/readme.txt
index 9ff761232e3..73ed820d5ca 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,10 +1,10 @@
-=== WooPayments - Fully Integrated Solution Built and Supported by Woo ===
+=== WooPayments: Integrated WooCommerce Payments ===
Contributors: woocommerce, automattic
Tags: woocommerce payments, apple pay, credit card, google pay, payment, payment gateway
Requires at least: 6.0
Tested up to: 6.4
Requires PHP: 7.3
-Stable tag: 7.1.0
+Stable tag: 7.2.0
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -94,6 +94,48 @@ Please note that our support for the checkout block is still experimental and th
== Changelog ==
+= 7.2.0 - 2024-02-14 =
+* Add - Add compatibility data to onboarding init payload.
+* Add - Add WooPay direct checkout flow behind a feature flag.
+* Add - Apply localization to CSV exports for transactions, deposits, and disputes sent via email.
+* Add - Displaying Clearpay instead of Afterpay for UK based stores
+* Add - Enhance WooPay session validation
+* Add - Filtering APMs by billing country
+* Add - Show a notice to the merchant when the available balance is below the minimum deposit amount.
+* Add - Show charge id on payments details page, so merchants can grab it to fill out the dispute evidence form when needed.
+* Add - Showing "started" event in transaction timeline
+* Add - Support Stripe Link payments with 3DS cards.
+* Fix - Adjust WordPress locale code to match the languages supported by the server.
+* Fix - Displaying the correct method name in Order Edit page for HPOS
+* Fix - Don't instantiate `Fraud_Prevention_Service` in checkout if processing an authorized WooPay request.
+* Fix - fix: help text alignment with Gutenberg plugin enabled
+* Fix - fix: pay-for-order compatibility with other gateways
+* Fix - Fixed a bug where the 'deposits paused while balance is negative' notice was erroneously shown after an instant deposit.
+* Fix - Fixes Pay for Order checkout using non-card payment methods.
+* Fix - Fix losing cart contents during the login at checkout.
+* Fix - Merge duplicated Payment Request and WooPay button functionality .
+* Fix - Prevent coupon usage increase in a WooPay preflight check.
+* Fix - Prevent WooPay webhook creation when account is suspended
+* Update - Add source to the onboarding flow page and track it
+* Update - Refactor the WooPay checkout flow UX
+* Update - Some minor update to tracking parameters to pass additional data like Woo store ID.
+* Update - Stop relying on Woo core for loading plugin translations.
+* Dev - Added ENUM class for currency codes
+* Dev - Bump WC tested up to version to 8.5.2.
+* Dev - chore: removed deprecated functions since 5.0.0
+* Dev - chore: remove unused checkout API methods
+* Dev - chore: remove unused gateway class methods
+* Dev - chore: remove unused isOrderPage return value from confirmIntent
+* Dev - chore: update colors on documentation pages
+* Dev - Comment: Bump qit-cli dependency to version 0.4.0.
+* Dev - E2E test - Merchant facing multi-currency on-boarding screen.
+* Dev - Fix for E2E shopper tests around 3DS and UPE settings
+* Dev - Refactoring the tracking logic
+* Dev - Refactor to how tracking events are defined for better readability.
+* Dev - Remove unnecessary tracks events for dispute accept success/error.
+* Dev - Update REST API documentation for deposits endpoints with changes to estimated and instant deposits
+* Dev - Update Tracks conditions
+
= 7.1.0 - 2024-01-25 =
* Add - Add active plugins array to compatibility data.
* Add - Add post_types and their counts as an array to compatibility data.
diff --git a/src/Internal/DependencyManagement/ServiceProvider/GenericServiceProvider.php b/src/Internal/DependencyManagement/ServiceProvider/GenericServiceProvider.php
index 2bb57a967d1..9d11140d15a 100644
--- a/src/Internal/DependencyManagement/ServiceProvider/GenericServiceProvider.php
+++ b/src/Internal/DependencyManagement/ServiceProvider/GenericServiceProvider.php
@@ -17,6 +17,7 @@
use WCPay\Internal\Service\Level3Service;
use WCPay\Internal\Service\OrderService;
use WCPay\Internal\Service\SessionService;
+use WCPay\Internal\PluginManagement\TranslationsLoader;
/**
* WCPay payments generic service provider.
@@ -31,6 +32,7 @@ class GenericServiceProvider extends AbstractServiceProvider {
Logger::class,
OrderService::class,
Level3Service::class,
+ TranslationsLoader::class,
];
/**
@@ -58,5 +60,9 @@ public function register(): void {
$container->addShared( SessionService::class )
->addArgument( LegacyProxy::class );
+
+ $container->addShared( TranslationsLoader::class )
+ ->addArgument( Logger::class )
+ ->addArgument( HooksProxy::class );
}
}
diff --git a/src/Internal/PluginManagement/TranslationsLoader.php b/src/Internal/PluginManagement/TranslationsLoader.php
new file mode 100644
index 00000000000..8232877caea
--- /dev/null
+++ b/src/Internal/PluginManagement/TranslationsLoader.php
@@ -0,0 +1,173 @@
+logger = $logger;
+ $this->hooks_proxy = $hooks_proxy;
+ }
+
+
+ /**
+ * Hooks into WordPress plugin update process to load plugin translations from translate.wordpress.com.
+ */
+ public function init_hooks() {
+ $this->hooks_proxy->add_filter( 'pre_set_site_transient_update_plugins', [ $this, 'load_wcpay_translations' ] );
+ }
+
+ /**
+ * Hooks into auto-update process to load plugin translations from translate.wordpress.com.
+ *
+ * Runs in a cron thread, or in a visitor thread if triggered
+ * by _maybe_update_plugins(), or in an auto-update thread.
+ *
+ * @param object $transient The update_plugins transient object.
+ *
+ * @return object The same or a modified version of the transient.
+ */
+ public function load_wcpay_translations( $transient ) {
+ try {
+ if ( is_object( $transient ) ) {
+ $translations = $this->get_translations_update_data();
+ $merged_translations = array_merge( isset( $transient->translations ) ? $transient->translations : [], $translations );
+ $transient->translations = $merged_translations;
+ }
+ } catch ( \Exception $ex ) {
+ $this->logger->error( 'Error with loading WooPayments translations from WordPress.com. Reason: ' . $ex->getMessage() );
+ return $transient;
+ }
+ return $transient;
+ }
+
+ /**
+ * Get translations updates information.
+ *
+ * @return array Update data {product_id => data}
+ * @throws \Exception If something goes wrong with fetching info about translation packages from WordPress.com.
+ */
+ public function get_translations_update_data() {
+ $installed_translations = wp_get_installed_translations( 'plugins' );
+ $locales = array_values( get_available_languages() );
+
+ if ( empty( $locales ) ) {
+ return [];
+ }
+
+ // Use the same timeout values as Woo Core https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/includes/admin/helper/class-wc-helper-updater.php#L257.
+ $timeout = wp_doing_cron() ? 30 : 3;
+
+ if ( ! function_exists( 'get_plugin_data' ) ) {
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
+ }
+
+ $plugin_data = get_plugin_data( WCPAY_PLUGIN_FILE );
+
+ /**
+ * Note: TextDomain could differ from the plugin slug, but WordPress uses TextDomain to load translations.
+ */
+ $plugin_name = $plugin_data['TextDomain'];
+
+ $request_body = [
+ 'locales' => $locales,
+ 'plugins' => [],
+ ];
+
+ $request_body['plugins'][ $plugin_name ] = [
+ 'version' => WCPAY_VERSION_NUMBER,
+ ];
+
+ $raw_response = wp_remote_post(
+ 'https://translate.wordpress.com/api/translations-updates/woocommerce',
+ [
+ 'body' => wp_json_encode( $request_body ),
+ 'headers' => [ 'Content-Type: application/json' ],
+ 'timeout' => $timeout,
+ ]
+ );
+
+ $response_code = wp_remote_retrieve_response_code( $raw_response );
+ if ( 200 !== $response_code ) {
+ $this->logger->debug(
+ sprintf( 'Raw response: %s', var_export( $raw_response, true ) ) // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export -- That's debug message which will only be logged when debuging is enabled.
+ );
+ throw new \Exception(
+ sprintf( 'Request failed. HTTP response code: %s', $response_code )
+ );
+ }
+
+ $response = json_decode( wp_remote_retrieve_body( $raw_response ), true );
+
+ if ( array_key_exists( 'success', $response ) && false === $response['success'] ) {
+ // The shape of response is not known, so more specific error message can't be provided in exception. Logging the response body for debuggin purposes.
+ $this->logger->debug(
+ sprintf( 'Unexpected response body: %s', var_export( $response, true ) ) // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export -- That's debug message which will only be logged when debuging is enabled.
+ );
+ throw new \Exception( 'Unexpected response body.' );
+ }
+
+ $language_packs = $response['data'][ $plugin_name ];
+
+ $translations = [];
+
+ foreach ( $language_packs as $language_pack ) {
+ // Maybe we have this language pack already installed so lets check revision date.
+ if ( array_key_exists( $plugin_name, $installed_translations ) && array_key_exists( $language_pack['wp_locale'], $installed_translations[ $plugin_name ] ) ) {
+ $installed_translation_revision_time = new DateTime( $installed_translations[ $plugin_name ][ $language_pack['wp_locale'] ]['PO-Revision-Date'] );
+ $new_translation_revision_time = new DateTime( $language_pack['last_modified'] );
+ // Skip if translation language pack is not newer than what is installed already.
+ if ( $new_translation_revision_time <= $installed_translation_revision_time ) {
+ continue;
+ }
+ }
+ $translations[] = [
+ 'type' => 'plugin',
+ 'slug' => $plugin_name,
+ 'language' => $language_pack['wp_locale'],
+ 'version' => $language_pack['version'],
+ 'updated' => $language_pack['last_modified'],
+ 'package' => $language_pack['package'],
+ 'autoupdate' => true,
+ ];
+ }
+
+ return $translations;
+ }
+}
diff --git a/tests/e2e/config/default.json b/tests/e2e/config/default.json
index a0e6569d2d6..2f0277dcf7d 100644
--- a/tests/e2e/config/default.json
+++ b/tests/e2e/config/default.json
@@ -74,6 +74,35 @@
"email": "e2e-wcpay-customer@woo.com"
}
},
+ "upe-customer": {
+ "billing": {
+ "be": {
+ "firstname": "I am",
+ "lastname": "Customer",
+ "company": "Automattic",
+ "country": "Belgium",
+ "addressfirstline": "Rue de l’Étuve, 1000",
+ "addresssecondline": "billing-be",
+ "city": "Bruxelles",
+ "postcode": "1000",
+ "phone": "123456789",
+ "email": "e2e-wcpay-customer@woo.com"
+ },
+ "de": {
+ "firstname": "I am",
+ "lastname": "Customer",
+ "company": "Automattic",
+ "country": "Germany",
+ "addressfirstline": "Petuelring 130",
+ "addresssecondline": "billing-de",
+ "city": "München",
+ "postcode": "80809",
+ "state": "DE-BY",
+ "phone": "123456789",
+ "email": "e2e-wcpay-customer@woo.com"
+ }
+ }
+ },
"subscriptions-customer": {
"billing": {
"firstname": "I am",
diff --git a/tests/e2e/config/jest-puppeteer-headless.config.js b/tests/e2e/config/jest-puppeteer-headless.config.js
new file mode 100644
index 00000000000..383d00305e6
--- /dev/null
+++ b/tests/e2e/config/jest-puppeteer-headless.config.js
@@ -0,0 +1,17 @@
+const { jestPuppeteerConfig } = require( '@woocommerce/e2e-environment' );
+
+// Add arg to allow accessing the payments iframes in interactive mode ({ headles: false }).
+// https://github.com/puppeteer/puppeteer/issues/4960#issuecomment-535729011
+jestPuppeteerConfig.launch.args.push( '--disable-features=site-per-process' );
+jestPuppeteerConfig.launch.args.push( '--disable-web-security' );
+jestPuppeteerConfig.launch.args.push( '--disable-features=IsolateOrigins' );
+jestPuppeteerConfig.launch.args.push( '--disable-site-isolation-trials' );
+
+// Set a real User Agent so the "Add block" button isn't disabled in Gutenberg during -dev tests.
+// Also keeping the "puppeteer-debug" value coming from @automattic.puppeteer
+jestPuppeteerConfig.launch.args.push(
+ // eslint-disable-next-line max-len
+ '--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36 puppeteer-debug'
+);
+
+module.exports = jestPuppeteerConfig;
diff --git a/tests/e2e/specs/blocks/shopper/shopper-wc-blocks-checkout-failures.spec.js b/tests/e2e/specs/blocks/shopper/shopper-wc-blocks-checkout-failures.spec.js
index 7ac506663e6..0c7cbba9adb 100644
--- a/tests/e2e/specs/blocks/shopper/shopper-wc-blocks-checkout-failures.spec.js
+++ b/tests/e2e/specs/blocks/shopper/shopper-wc-blocks-checkout-failures.spec.js
@@ -197,7 +197,7 @@ describeif( RUN_WC_BLOCKS_TESTS )(
await expect( page ).toClick( 'button > span', {
text: 'Place Order',
} );
- await confirmCardAuthentication( page, '3DS' );
+ await confirmCardAuthentication( page );
await page.waitForSelector( 'div.wc-block-components-notices' );
const declined3dsCardError = await page.$eval(
'div.wc-block-components-notices > div > div.components-notice__content',
diff --git a/tests/e2e/specs/blocks/shopper/shopper-wc-blocks-checkout-purchase.spec.js b/tests/e2e/specs/blocks/shopper/shopper-wc-blocks-checkout-purchase.spec.js
index 51022e6d92b..f3475df2805 100644
--- a/tests/e2e/specs/blocks/shopper/shopper-wc-blocks-checkout-purchase.spec.js
+++ b/tests/e2e/specs/blocks/shopper/shopper-wc-blocks-checkout-purchase.spec.js
@@ -77,7 +77,7 @@ describeif( RUN_WC_BLOCKS_TESTS )(
'.wc-block-components-main button:not(:disabled)'
);
await expect( page ).toClick( 'button', { text: 'Place Order' } );
- await confirmCardAuthentication( page, '3DS' );
+ await confirmCardAuthentication( page );
await page.waitForNavigation( {
waitUntil: 'networkidle0',
} );
diff --git a/tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-purchase-free-trial.spec.js b/tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-purchase-free-trial.spec.js
index 8a14c1d26a7..fa11e8b715d 100644
--- a/tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-purchase-free-trial.spec.js
+++ b/tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-purchase-free-trial.spec.js
@@ -116,7 +116,7 @@ describeif( RUN_SUBSCRIPTIONS_TESTS )(
await expect( page ).toClick(
testSelectors.checkoutPlaceOrderButton
);
- await confirmCardAuthentication( page, '3DS', true );
+ await confirmCardAuthentication( page, true );
await page.waitForNavigation( {
waitUntil: 'networkidle0',
} );
diff --git a/tests/e2e/specs/wcpay/merchant/merchant-admin-multi-currency-on-boarding.spec.js b/tests/e2e/specs/wcpay/merchant/merchant-admin-multi-currency-on-boarding.spec.js
new file mode 100644
index 00000000000..27459e1db51
--- /dev/null
+++ b/tests/e2e/specs/wcpay/merchant/merchant-admin-multi-currency-on-boarding.spec.js
@@ -0,0 +1,362 @@
+/**
+ * External dependencies
+ */
+const { merchant, WP_ADMIN_DASHBOARD } = require( '@woocommerce/e2e-utils' );
+/**
+ * Internal dependencies
+ */
+import {
+ merchantWCP,
+ setCheckboxState,
+ takeScreenshot,
+ uiLoaded,
+} from '../../../utils';
+
+// Shared selector constants.
+const THEME_SELECTOR = ( themeSlug ) => `.theme[data-slug="${ themeSlug }"]`;
+const ACTIVATE_THEME_BUTTON_SELECTOR = ( themeSlug ) =>
+ `${ THEME_SELECTOR( themeSlug ) } .button.activate`;
+const MULTI_CURRENCY_TOGGLE_SELECTOR = "[data-testid='multi-currency-toggle']";
+const RECOMMENDED_CURRENCY_LIST_SELECTOR =
+ 'li[data-testid="recommended-currency"]';
+const CURRENCY_NOT_IN_RECOMMENDED_LIST_SELECTOR =
+ 'li.enabled-currency-checkbox:not([data-testid="recommended-currency"])';
+const ENABLED_CURRENCY_LIST_SELECTOR = 'li.enabled-currency-checkbox';
+const GEO_CURRENCY_SWITCH_CHECKBOX_SELECTOR =
+ 'input[data-testid="enable_auto_currency"]';
+const PREVIEW_STORE_BTN_SELECTOR = '.multi-currency-setup-preview-button';
+const PREVIEW_STORE_IFRAME_SELECTOR =
+ '.multi-currency-store-settings-preview-iframe';
+const SUBMIT_STEP_BTN_SELECTOR =
+ '.add-currencies-task.is-active .task-collapsible-body.is-active > button.is-primary';
+const STOREFRONT_SWITCH_CHECKBOX_SELECTOR =
+ 'input[data-testid="enable_storefront_switcher"]';
+
+let wasMulticurrencyEnabled;
+
+const goToThemesPage = async () => {
+ await page.goto( `${ WP_ADMIN_DASHBOARD }themes.php`, {
+ waitUntil: 'networkidle0',
+ } );
+};
+
+const activateTheme = async ( themeSlug ) => {
+ await goToThemesPage();
+
+ // Check if the theme is already active.
+ const isActive = await page.evaluate( ( selector ) => {
+ const themeElement = document.querySelector( selector );
+ return themeElement && themeElement.classList.contains( 'active' );
+ }, THEME_SELECTOR( themeSlug ) );
+
+ // Activate the theme if it's not already active.
+ if ( ! isActive ) {
+ await page.click( ACTIVATE_THEME_BUTTON_SELECTOR( themeSlug ) );
+ await page.waitForNavigation( { waitUntil: 'networkidle0' } );
+ }
+};
+
+const goToOnboardingPage = async () => {
+ await page.goto(
+ `${ WP_ADMIN_DASHBOARD }admin.php?page=wc-admin&path=%2Fpayments%2Fmulti-currency-setup`,
+ {
+ waitUntil: 'networkidle0',
+ }
+ );
+ await uiLoaded();
+};
+
+const goToNextOnboardingStep = async () => {
+ await page.click( SUBMIT_STEP_BTN_SELECTOR );
+};
+
+describe( 'Merchant On-boarding', () => {
+ let activeThemeSlug;
+
+ beforeAll( async () => {
+ await merchant.login();
+ // Get initial multi-currency feature status.
+ await merchantWCP.openWCPSettings();
+ await page.waitForSelector( MULTI_CURRENCY_TOGGLE_SELECTOR );
+ wasMulticurrencyEnabled = await page.evaluate( ( selector ) => {
+ const checkbox = document.querySelector( selector );
+ return checkbox ? checkbox.checked : false;
+ }, MULTI_CURRENCY_TOGGLE_SELECTOR );
+ await merchantWCP.activateMulticurrency();
+
+ await goToThemesPage();
+
+ // Get current theme slug.
+ activeThemeSlug = await page.evaluate( () => {
+ const theme = document.querySelector( '.theme.active' );
+ return theme ? theme.getAttribute( 'data-slug' ) : '';
+ } );
+ } );
+
+ afterAll( async () => {
+ // Restore original theme.
+ await activateTheme( activeThemeSlug );
+
+ // Disable multi-currency if it was not initially enabled.
+ if ( ! wasMulticurrencyEnabled ) {
+ await merchant.login();
+ await merchantWCP.deactivateMulticurrency();
+ }
+ await merchant.logout();
+ } );
+
+ describe( 'Currency Selection and Management', () => {
+ beforeAll( async () => {
+ await merchantWCP.disableAllEnabledCurrencies();
+ } );
+
+ beforeEach( async () => {
+ await goToOnboardingPage();
+ } );
+
+ it( 'Should disable the submit button when no currencies are selected', async () => {
+ await takeScreenshot( 'merchant-on-boarding-multicurrency-screen' );
+ await setCheckboxState(
+ `${ ENABLED_CURRENCY_LIST_SELECTOR } .components-checkbox-control__input`,
+ false
+ );
+
+ await page.waitFor( 1000 );
+
+ const button = await page.$( SUBMIT_STEP_BTN_SELECTOR );
+ expect( button ).not.toBeNull();
+
+ const isDisabled = await page.evaluate(
+ ( btn ) => btn.disabled,
+ button
+ );
+
+ expect( isDisabled ).toBeTruthy();
+ } );
+
+ it( 'Should allow multiple currencies to be selectable', async () => {
+ await page.waitForSelector(
+ CURRENCY_NOT_IN_RECOMMENDED_LIST_SELECTOR,
+ {
+ timeout: 3000,
+ }
+ );
+
+ // Ensure the checkbox within the list item is present and not disabled.
+ const checkbox = await page.$(
+ `${ CURRENCY_NOT_IN_RECOMMENDED_LIST_SELECTOR } input[type="checkbox"]`
+ );
+ expect( checkbox ).not.toBeNull();
+ const isDisabled = await (
+ await checkbox.getProperty( 'disabled' )
+ ).jsonValue();
+ expect( isDisabled ).toBe( false );
+
+ // Click the checkbox to select the currency and verify it's checked.
+ await checkbox.click();
+
+ const isChecked = await (
+ await checkbox.getProperty( 'checked' )
+ ).jsonValue();
+ expect( isChecked ).toBe( true );
+ } );
+
+ it( 'Should exclude already enabled currencies from the currency screen', async () => {
+ await merchantWCP.addCurrency( 'GBP' );
+
+ await goToOnboardingPage();
+
+ await page.waitForSelector( ENABLED_CURRENCY_LIST_SELECTOR, {
+ timeout: 3000,
+ } );
+
+ // Get the list of currencies as text
+ const currencies = await page.$$eval(
+ ENABLED_CURRENCY_LIST_SELECTOR,
+ ( items ) => items.map( ( item ) => item.textContent.trim() )
+ );
+
+ expect( currencies ).not.toContain( 'GBP' );
+
+ await merchantWCP.removeCurrency( 'GBP' );
+ } );
+
+ it( 'Should display some suggested currencies at the beginning of the list', async () => {
+ await page.waitForSelector( RECOMMENDED_CURRENCY_LIST_SELECTOR, {
+ timeout: 3000,
+ } );
+
+ // Get the list of recommended currencies
+ const recommendedCurrencies = await page.$$eval(
+ RECOMMENDED_CURRENCY_LIST_SELECTOR,
+ ( items ) =>
+ items.map( ( item ) => ( {
+ code: item
+ .querySelector( 'input' )
+ .getAttribute( 'code' ),
+ name: item
+ .querySelector(
+ 'span.enabled-currency-checkbox__code'
+ )
+ .textContent.trim(),
+ } ) )
+ );
+
+ expect( recommendedCurrencies.length ).toBeGreaterThan( 0 );
+ } );
+
+ it( 'Should ensure selected currencies are enabled after submitting the form', async () => {
+ const testCurrencies = [ 'GBP', 'EUR', 'CAD', 'AUD' ];
+ const addCurrenciesContentSelector =
+ '.add-currencies-task__content';
+ const currencyCheckboxSelector = `${ addCurrenciesContentSelector } li input[type="checkbox"]`;
+
+ await page.waitForSelector( addCurrenciesContentSelector, {
+ timeout: 3000,
+ } );
+
+ // Select the currencies
+ for ( const currency of testCurrencies ) {
+ await setCheckboxState(
+ `${ currencyCheckboxSelector }[code="${ currency }"]`,
+ true
+ );
+ }
+
+ // Submit the form.
+ await goToNextOnboardingStep();
+
+ await merchantWCP.openMultiCurrency();
+
+ // Ensure the currencies are enabled.
+ for ( const currency of testCurrencies ) {
+ const selector = `li.enabled-currency.${ currency.toLowerCase() }`;
+ await page.waitForSelector( selector, { timeout: 10000 } );
+ const element = await page.$( selector );
+
+ expect( element ).not.toBeNull();
+ }
+ } );
+ } );
+
+ describe( 'Geolocation Features', () => {
+ beforeAll( async () => {
+ await merchantWCP.disableAllEnabledCurrencies();
+ } );
+
+ beforeEach( async () => {
+ await goToOnboardingPage();
+ } );
+
+ it( 'Should offer currency switch by geolocation', async () => {
+ await goToNextOnboardingStep();
+
+ const checkbox = await page.$(
+ GEO_CURRENCY_SWITCH_CHECKBOX_SELECTOR
+ );
+
+ // Check if exists and not disabled.
+ expect( checkbox ).not.toBeNull();
+ const isDisabled = await (
+ await checkbox.getProperty( 'disabled' )
+ ).jsonValue();
+ expect( isDisabled ).toBe( false );
+
+ // Click the checkbox to select it.
+ await page.click( GEO_CURRENCY_SWITCH_CHECKBOX_SELECTOR );
+
+ // Check if the checkbox is selected.
+ const isChecked = await (
+ await checkbox.getProperty( 'checked' )
+ ).jsonValue();
+ expect( isChecked ).toBe( true );
+ } );
+
+ it( 'Should preview currency switch by geolocation correctly with USD and GBP', async () => {
+ page.setViewport( { width: 1280, height: 1280 } ); // To take a better screenshot of the iframe preview.
+
+ await goToNextOnboardingStep();
+
+ await takeScreenshot(
+ 'merchant-on-boarding-multicurrency-screen-2'
+ );
+
+ // Enable feature.
+ await setCheckboxState(
+ GEO_CURRENCY_SWITCH_CHECKBOX_SELECTOR,
+ true
+ );
+
+ // Click preview button.
+ await page.click( PREVIEW_STORE_BTN_SELECTOR );
+
+ await page.waitForSelector( PREVIEW_STORE_IFRAME_SELECTOR, {
+ timeout: 3000,
+ } );
+
+ const iframeElement = await page.$( PREVIEW_STORE_IFRAME_SELECTOR );
+ const iframe = await iframeElement.contentFrame();
+
+ await iframe.waitForSelector( '.woocommerce-store-notice', {
+ timeout: 3000,
+ } );
+
+ await takeScreenshot(
+ 'merchant-on-boarding-multicurrency-geolocation-switcher-preview'
+ );
+
+ const noticeText = await iframe.$eval(
+ '.woocommerce-store-notice',
+ ( element ) => element.innerText
+ );
+ expect( noticeText ).toContain(
+ // eslint-disable-next-line max-len
+ "We noticed you're visiting from United Kingdom (UK). We've updated our prices to Pound sterling for your shopping convenience."
+ );
+ } );
+ } );
+
+ describe( 'Currency Switcher Widget', () => {
+ it( 'Should offer the currency switcher widget while Storefront theme is active', async () => {
+ await activateTheme( 'storefront' );
+
+ await goToOnboardingPage();
+ await goToNextOnboardingStep();
+
+ const checkbox = await page.$(
+ STOREFRONT_SWITCH_CHECKBOX_SELECTOR
+ );
+
+ // Check if exists and not disabled.
+ expect( checkbox ).not.toBeNull();
+ const isDisabled = await (
+ await checkbox.getProperty( 'disabled' )
+ ).jsonValue();
+ expect( isDisabled ).toBe( false );
+
+ // Click the checkbox to select it.
+ await page.click( STOREFRONT_SWITCH_CHECKBOX_SELECTOR );
+
+ // Check if the checkbox is selected.
+ const isChecked = await (
+ await checkbox.getProperty( 'checked' )
+ ).jsonValue();
+ expect( isChecked ).toBe( true );
+ } );
+
+ it( 'Should not offer the currency switcher widget when an unsupported theme is active', async () => {
+ await activateTheme( 'twentytwentyfour' );
+
+ await goToOnboardingPage();
+ await goToNextOnboardingStep();
+
+ const checkbox = await page.$(
+ STOREFRONT_SWITCH_CHECKBOX_SELECTOR
+ );
+
+ expect( checkbox ).toBeNull();
+
+ await activateTheme( 'storefront' );
+ } );
+ } );
+} );
diff --git a/tests/e2e/specs/wcpay/merchant/merchant-admin-multi-currency-setup.spec.js b/tests/e2e/specs/wcpay/merchant/merchant-admin-multi-currency-setup.spec.js
index 51f7fc9cd67..800ce9d0e8b 100644
--- a/tests/e2e/specs/wcpay/merchant/merchant-admin-multi-currency-setup.spec.js
+++ b/tests/e2e/specs/wcpay/merchant/merchant-admin-multi-currency-setup.spec.js
@@ -75,6 +75,7 @@ describe( 'Merchant Multi-Currency Settings', () => {
beforeAll( async () => {
await merchantWCP.activateMulticurrency();
+ await merchantWCP.disableAllEnabledCurrencies();
await shopperWCP.goToShopWithCurrency( 'USD' );
await shopperWCP.goToProductPageBySlug( 'beanie' );
diff --git a/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js
index 3f122226c13..d1f225c1c43 100644
--- a/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js
+++ b/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js
@@ -41,8 +41,9 @@ describe( 'Enabled UPE with deferred intent creation', () => {
describe( 'Enabled UPE with deferred intent creation', () => {
it( 'should successfully place order with Giropay', async () => {
await setupProductCheckout(
- config.get( 'addresses.customer.billing' )
+ config.get( 'addresses.upe-customer.billing.de' )
);
+ page.waitFor( 1000 );
await selectOnCheckout( 'giropay', page );
await shopper.placeOrder();
await completeRedirectedPayment( page, 'success' );
@@ -54,8 +55,9 @@ describe( 'Enabled UPE with deferred intent creation', () => {
it( 'should successfully place order with Bancontact', async () => {
await setupProductCheckout(
- config.get( 'addresses.customer.billing' )
+ config.get( 'addresses.upe-customer.billing.be' )
);
+ page.waitFor( 1000 );
await selectOnCheckout( 'bancontact', page );
await shopper.placeOrder();
await completeRedirectedPayment( page, 'success' );
diff --git a/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase.spec.js
index e1d871c9b07..ccb189a91ab 100644
--- a/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase.spec.js
+++ b/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase.spec.js
@@ -40,7 +40,7 @@ describe( 'Successful purchase', () => {
const card = config.get( 'cards.3ds' );
await fillCardDetails( page, card );
await expect( page ).toClick( '#place_order' );
- await confirmCardAuthentication( page, '3DS' );
+ await confirmCardAuthentication( page );
await page.waitForNavigation( {
waitUntil: 'networkidle0',
} );
diff --git a/tests/e2e/specs/wcpay/shopper/shopper-checkout-save-card-and-purchase.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-checkout-save-card-and-purchase.spec.js
index 341b52cf516..cd4b4eeb13f 100644
--- a/tests/e2e/specs/wcpay/shopper/shopper-checkout-save-card-and-purchase.spec.js
+++ b/tests/e2e/specs/wcpay/shopper/shopper-checkout-save-card-and-purchase.spec.js
@@ -45,7 +45,7 @@ describe( 'Saved cards ', () => {
await shopper.placeOrder();
} else {
await expect( page ).toClick( '#place_order' );
- await confirmCardAuthentication( page, cardType );
+ await confirmCardAuthentication( page );
await page.waitForNavigation( {
waitUntil: 'networkidle0',
} );
@@ -73,7 +73,7 @@ describe( 'Saved cards ', () => {
await shopper.placeOrder();
} else {
await expect( page ).toClick( '#place_order' );
- await confirmCardAuthentication( page, cardType );
+ await confirmCardAuthentication( page );
await page.waitForNavigation( {
waitUntil: 'networkidle0',
} );
diff --git a/tests/e2e/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-fail.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-fail.spec.js
index f3e3762f48d..e8fb0a0f79d 100644
--- a/tests/e2e/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-fail.spec.js
+++ b/tests/e2e/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-fail.spec.js
@@ -50,7 +50,7 @@ describe( 'Payment Methods', () => {
text: 'Add payment method',
} );
if ( cardType === 'declined-3ds' ) {
- await confirmCardAuthentication( page, '3DS2' );
+ await confirmCardAuthentication( page );
}
await expect( page ).toMatchElement( '.woocommerce-error', {
timeout: 30000,
diff --git a/tests/e2e/specs/wcpay/shopper/shopper-myaccount-save-card-and-checkout.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-myaccount-save-card-and-checkout.spec.js
index 8def9e54824..ddcd3c6586d 100644
--- a/tests/e2e/specs/wcpay/shopper/shopper-myaccount-save-card-and-checkout.spec.js
+++ b/tests/e2e/specs/wcpay/shopper/shopper-myaccount-save-card-and-checkout.spec.js
@@ -54,7 +54,7 @@ describe( 'Saved cards ', () => {
await shopper.placeOrder();
} else {
await expect( page ).toClick( '#place_order' );
- await confirmCardAuthentication( page, cardType );
+ await confirmCardAuthentication( page );
await page.waitForNavigation( {
waitUntil: 'networkidle0',
} );
diff --git a/tests/e2e/utils/flows.js b/tests/e2e/utils/flows.js
index 3399d5b9ffe..10499fe20c3 100644
--- a/tests/e2e/utils/flows.js
+++ b/tests/e2e/utils/flows.js
@@ -191,7 +191,7 @@ export const shopperWCP = {
! cardType.toLowerCase().includes( 'declined' );
if ( cardIs3DS ) {
- await confirmCardAuthentication( page, cardType );
+ await confirmCardAuthentication( page );
}
await page.waitForNavigation( {
@@ -426,7 +426,17 @@ export const merchantWCP = {
button.click()
);
}
- await page.$eval( paymentMethod, ( method ) => method.click() );
+ // Check if paymentMethod is an XPath
+ if ( paymentMethod.startsWith( '//' ) ) {
+ // Find the element using XPath and click it
+ const elements = await page.$x( paymentMethod );
+ if ( elements.length > 0 ) {
+ await elements[ 0 ].click();
+ }
+ } else {
+ // If it's a CSS selector, use $eval
+ await page.$eval( paymentMethod, ( method ) => method.click() );
+ }
await expect( page ).toClick( 'button', {
text: 'Remove',
} );
@@ -513,6 +523,11 @@ export const merchantWCP = {
}
}, currencyCode );
+ await page.waitForSelector(
+ 'div.wcpay-confirmation-modal__footer button.components-button.is-primary',
+ { timeout: 3000 }
+ );
+
await page.click(
'div.wcpay-confirmation-modal__footer button.components-button.is-primary',
{ text: 'Update selected' }
@@ -532,6 +547,7 @@ export const merchantWCP = {
},
removeCurrency: async ( currencyCode ) => {
+ await merchantWCP.openMultiCurrency();
const currencyItemSelector = `li.enabled-currency.${ currencyCode.toLowerCase() }`;
await page.waitForSelector( currencyItemSelector, { timeout: 10000 } );
await page.click(
@@ -732,6 +748,31 @@ export const merchantWCP = {
return wasInitiallyEnabled;
},
+ disableAllEnabledCurrencies: async () => {
+ await page.goto( WCPAY_MULTI_CURRENCY, { waitUntil: 'networkidle0' } );
+
+ await page.waitForSelector( '.enabled-currencies-list li', {
+ timeout: 10000,
+ } );
+
+ // Select all delete buttons for enabled currencies.
+ const deleteButtons = await page.$$(
+ '.enabled-currency .enabled-currency__action.delete'
+ );
+
+ // Loop through each delete button and click it.
+ for ( const button of deleteButtons ) {
+ await button.click();
+
+ await page.waitForSelector( '.components-snackbar', {
+ text: 'Enabled currencies updated.',
+ timeout: 10000,
+ } );
+
+ await page.waitFor( 1000 );
+ }
+ },
+
editCurrency: async ( currencyCode ) => {
await merchantWCP.openMultiCurrency();
diff --git a/tests/e2e/utils/helpers.js b/tests/e2e/utils/helpers.js
index ca829481a27..2d9b0e0932b 100644
--- a/tests/e2e/utils/helpers.js
+++ b/tests/e2e/utils/helpers.js
@@ -80,3 +80,21 @@ export const getProductPriceFromProductPage = async () => {
return price;
};
+
+/**
+ * Sets the state of all checkboxes matching the specified selector.
+ *
+ * @param {string} selector The selector to use to find checkboxes.
+ * @param {boolean} desiredState The desired state of the checkboxes.
+ */
+export const setCheckboxState = async ( selector, desiredState ) => {
+ const checkboxes = await page.$$( selector );
+ for ( const checkbox of checkboxes ) {
+ const isChecked = await (
+ await checkbox.getProperty( 'checked' )
+ ).jsonValue();
+ if ( isChecked !== desiredState ) {
+ await checkbox.click();
+ }
+ }
+};
diff --git a/tests/e2e/utils/payments.js b/tests/e2e/utils/payments.js
index dc09c6d11f0..b789068a9e9 100644
--- a/tests/e2e/utils/payments.js
+++ b/tests/e2e/utils/payments.js
@@ -177,11 +177,7 @@ export async function clearWCBCardDetails() {
await page.keyboard.press( 'Backspace' );
}
-export async function confirmCardAuthentication(
- page,
- cardType = '3DS',
- authorize = true
-) {
+export async function confirmCardAuthentication( page, authorize = true ) {
const target = authorize
? '#test-source-authorize-3ds'
: '#test-source-fail-3ds';
@@ -195,14 +191,7 @@ export async function confirmCardAuthentication(
const challengeFrameHandle = await stripeFrame.waitForSelector(
'iframe#challengeFrame'
);
- let challengeFrame = await challengeFrameHandle.contentFrame();
- // 3DS 1 cards have another iframe enclosing the authorize form
- if ( cardType.toUpperCase() === '3DS' ) {
- const acsFrameHandle = await challengeFrame.waitForSelector(
- 'iframe[name="acsFrame"]'
- );
- challengeFrame = await acsFrameHandle.contentFrame();
- }
+ const challengeFrame = await challengeFrameHandle.contentFrame();
// Need to wait for the CSS animations to complete.
await page.waitFor( 500 );
const button = await challengeFrame.waitForSelector( target );
@@ -256,7 +245,7 @@ export async function setupProductCheckout(
export async function setupCheckout( billingDetails ) {
await shopper.goToCheckout();
await uiUnblocked();
- await shopper.fillBillingDetails( billingDetails );
+ await fillBillingDetails( billingDetails );
// Woo core blocks and refreshes the UI after 1s after each key press in a text field or immediately after a select
// field changes. Need to wait to make sure that all key presses were processed by that mechanism.
@@ -267,6 +256,55 @@ export async function setupCheckout( billingDetails ) {
);
}
+// Copy of the fillBillingDetails function from woocommerce/e2e-utils/src/flows/shopper.js
+// Supporting countries that do not have a state select input.
+// Remove after https://github.com/woocommerce/woocommerce/pull/44090 is merged.
+async function fillBillingDetails( customerBillingDetails ) {
+ await expect( page ).toFill(
+ '#billing_first_name',
+ customerBillingDetails.firstname
+ );
+ await expect( page ).toFill(
+ '#billing_last_name',
+ customerBillingDetails.lastname
+ );
+ await expect( page ).toFill(
+ '#billing_company',
+ customerBillingDetails.company
+ );
+ await expect( page ).toSelect(
+ '#billing_country',
+ customerBillingDetails.country
+ );
+ await expect( page ).toFill(
+ '#billing_address_1',
+ customerBillingDetails.addressfirstline
+ );
+ await expect( page ).toFill(
+ '#billing_address_2',
+ customerBillingDetails.addresssecondline
+ );
+ await expect( page ).toFill( '#billing_city', customerBillingDetails.city );
+ if ( customerBillingDetails.state ) {
+ await expect( page ).toSelect(
+ '#billing_state',
+ customerBillingDetails.state
+ );
+ }
+ await expect( page ).toFill(
+ '#billing_postcode',
+ customerBillingDetails.postcode
+ );
+ await expect( page ).toFill(
+ '#billing_phone',
+ customerBillingDetails.phone
+ );
+ await expect( page ).toFill(
+ '#billing_email',
+ customerBillingDetails.email
+ );
+}
+
/**
* Selects the payment method on the checkout page.
*
diff --git a/tests/fixtures/captured-payments/foreign-card.json b/tests/fixtures/captured-payments/foreign-card.json
index 9a121e3a7ed..50dc975b029 100644
--- a/tests/fixtures/captured-payments/foreign-card.json
+++ b/tests/fixtures/captured-payments/foreign-card.json
@@ -33,10 +33,7 @@
},
"currency": "CAD",
"datetime": 1651997332,
- "deposit": {
- "id": "wcpay_estimated_daily_usd_1652572800",
- "arrival_date": "1652572800"
- },
+ "deposit": null,
"transaction_id": "txn_3Kx5Ae2EFxam75ai0P2BCbp0",
"transaction_details": {
"customer_currency": "CAD",
diff --git a/tests/fixtures/captured-payments/fx-decimal.json b/tests/fixtures/captured-payments/fx-decimal.json
index 77a136924f8..52d02537e81 100644
--- a/tests/fixtures/captured-payments/fx-decimal.json
+++ b/tests/fixtures/captured-payments/fx-decimal.json
@@ -26,10 +26,7 @@
},
"currency": "EUR",
"datetime": 1651215495,
- "deposit": {
- "id": "wcpay_estimated_daily_usd_1651795200",
- "arrival_date": "1651795200"
- },
+ "deposit": null,
"transaction_id": "txn_3Ktnm22EFxam75ai0Sr9SR5A",
"transaction_details": {
"customer_currency": "EUR",
diff --git a/tests/fixtures/captured-payments/fx-foreign-card.json b/tests/fixtures/captured-payments/fx-foreign-card.json
index 9b26ad48fc1..846353f7e24 100644
--- a/tests/fixtures/captured-payments/fx-foreign-card.json
+++ b/tests/fixtures/captured-payments/fx-foreign-card.json
@@ -27,10 +27,7 @@
},
"currency": "USD",
"datetime": 1651996460,
- "deposit": {
- "id": "wcpay_estimated_daily_usd_1652572800",
- "arrival_date": "1652572800"
- },
+ "deposit": null,
"transaction_id": "txn_3Kx4w12EFxam75ai0W5q4669",
"transaction_details": {
"customer_currency": "USD",
diff --git a/tests/fixtures/captured-payments/fx-with-capped-fee.json b/tests/fixtures/captured-payments/fx-with-capped-fee.json
index 23c3cbf1387..7d3c354ac95 100644
--- a/tests/fixtures/captured-payments/fx-with-capped-fee.json
+++ b/tests/fixtures/captured-payments/fx-with-capped-fee.json
@@ -35,10 +35,7 @@
},
"currency": "EUR",
"datetime": 1651998676,
- "deposit": {
- "id": "wcpay_estimated_weekly_usd_1652659200",
- "arrival_date": "1652659200"
- },
+ "deposit": null,
"transaction_id": "txn_3Kx5WG2HDHuit9Eg0ZrUH90z",
"transaction_details": {
"customer_currency": "EUR",
diff --git a/tests/fixtures/captured-payments/fx.json b/tests/fixtures/captured-payments/fx.json
index 166deab4a86..7a4c1186d1e 100644
--- a/tests/fixtures/captured-payments/fx.json
+++ b/tests/fixtures/captured-payments/fx.json
@@ -27,10 +27,7 @@
},
"currency": "VND",
"datetime": 1651215552,
- "deposit": {
- "id": "wcpay_estimated_daily_usd_1651795200",
- "arrival_date": "1651795200"
- },
+ "deposit": null,
"transaction_id": "txn_3KtnnI2EFxam75ai06EEZYXQ",
"transaction_details": {
"customer_currency": "VND",
diff --git a/tests/fixtures/captured-payments/only-base-fee.json b/tests/fixtures/captured-payments/only-base-fee.json
index 0385bd61c6f..a84920fd3b3 100644
--- a/tests/fixtures/captured-payments/only-base-fee.json
+++ b/tests/fixtures/captured-payments/only-base-fee.json
@@ -19,10 +19,7 @@
},
"currency": "USD",
"datetime": 1651997740,
- "deposit": {
- "id": "wcpay_estimated_daily_usd_1652572800",
- "arrival_date": "1652572800"
- },
+ "deposit": null,
"transaction_id": "txn_3Kx5HD2EFxam75ai1FerGksO",
"transaction_details": {
"customer_currency": "USD",
diff --git a/tests/fixtures/captured-payments/subscription.json b/tests/fixtures/captured-payments/subscription.json
index a9a4d01eae4..bf58a36666f 100644
--- a/tests/fixtures/captured-payments/subscription.json
+++ b/tests/fixtures/captured-payments/subscription.json
@@ -34,10 +34,7 @@
},
"currency": "EUR",
"datetime": 1651999249,
- "deposit": {
- "id": "wcpay_estimated_weekly_usd_1652659200",
- "arrival_date": "1652659200"
- },
+ "deposit": null,
"transaction_id": "txn_3Kx5fY2HDHuit9Eg0fQ402Ee",
"transaction_details": {
"customer_currency": "EUR",
diff --git a/tests/js/jest-test-file-setup.js b/tests/js/jest-test-file-setup.js
index c4d9395a9a1..09400abae27 100644
--- a/tests/js/jest-test-file-setup.js
+++ b/tests/js/jest-test-file-setup.js
@@ -101,6 +101,16 @@ global.wpApiSettings = {
nonce: 'random_wp_rest_nonce',
};
+global.wcpaySettings = {
+ locale: {
+ code: 'es_ES',
+ native_name: 'Spanish',
+ },
+ accountLoans: {
+ loans: [ 'flxln_123456|active' ],
+ },
+};
+
// const config = require( '../../config/development.json' );
// window.wcAdminFeatures = config && config.features ? config.features : {};
@@ -116,3 +126,10 @@ global.ResizeObserver = jest.fn().mockImplementation( () => ( {
unobserve: jest.fn(),
disconnect: jest.fn(),
} ) );
+
+// Mock the tracks module to avoid the need to mock wcpaySettings in every test.
+jest.mock( 'tracks', () => ( {
+ recordEvent: jest.fn(),
+ isEnabled: jest.fn(),
+ events: {},
+} ) );
diff --git a/tests/unit/admin/test-class-wc-payments-admin.php b/tests/unit/admin/test-class-wc-payments-admin.php
index 1f828d877b8..ca7917968cb 100644
--- a/tests/unit/admin/test-class-wc-payments-admin.php
+++ b/tests/unit/admin/test-class-wc-payments-admin.php
@@ -400,83 +400,6 @@ public function data_maybe_redirect_overview_to_connect() {
];
}
- /**
- * @dataProvider data_maybe_redirect_onboarding_flow_to_connect
- */
- public function test_maybe_redirect_onboarding_flow_to_connect( $expected_times_redirect_called, $is_server_connected, $get_params ) {
- $this->mock_current_user_is_admin();
- $_GET = $get_params;
-
- $this->mock_api_client
- ->method( 'is_server_connected' )
- ->willReturn( $is_server_connected );
-
- $this->mock_account
- ->expects( $this->exactly( $expected_times_redirect_called ) )
- ->method( 'redirect_to_onboarding_welcome_page' );
-
- $this->payments_admin->maybe_redirect_onboarding_flow_to_connect();
- }
-
- /**
- * Data provider for test_maybe_redirect_onboarding_flow_to_connect
- */
- public function data_maybe_redirect_onboarding_flow_to_connect() {
- return [
- 'no_get_params' => [
- 0,
- false,
- [],
- ],
- 'empty_page_param' => [
- 0,
- false,
- [
- 'path' => '/payments/onboarding',
- ],
- ],
- 'incorrect_page_param' => [
- 0,
- false,
- [
- 'page' => 'wc-settings',
- 'path' => '/payments/onboarding',
- ],
- ],
- 'empty_path_param' => [
- 0,
- false,
- [
- 'page' => 'wc-admin',
- ],
- ],
- 'incorrect_path_param' => [
- 0,
- false,
- [
- 'page' => 'wc-admin',
- 'path' => '/payments/does-not-exist',
- ],
- ],
- 'server_connected' => [
- 0,
- true,
- [
- 'page' => 'wc-admin',
- 'path' => '/payments/onboarding',
- ],
- ],
- 'happy_path' => [
- 1,
- false,
- [
- 'page' => 'wc-admin',
- 'path' => '/payments/onboarding',
- ],
- ],
- ];
- }
-
/**
* Tests WC_Payments_Admin::add_disputes_notification_badge()
*/
diff --git a/tests/unit/multi-currency/test-class-payment-methods-compatibility.php b/tests/unit/multi-currency/test-class-payment-methods-compatibility.php
index 6a0f24eeba8..7a6e910db46 100644
--- a/tests/unit/multi-currency/test-class-payment-methods-compatibility.php
+++ b/tests/unit/multi-currency/test-class-payment-methods-compatibility.php
@@ -54,9 +54,11 @@ public function set_up() {
->setMethods(
[
'get_upe_enabled_payment_method_ids',
+ 'get_account_country',
]
)
->getMock();
+ $this->gateway_mock->method( 'get_account_country' )->willReturn( 'US' );
$this->payment_methods_compatibility = new \WCPay\MultiCurrency\PaymentMethodsCompatibility( $this->multi_currency_mock, $this->gateway_mock );
$this->payment_methods_compatibility->init_hooks();
diff --git a/tests/unit/payment-methods/test-class-upe-payment-gateway.php b/tests/unit/payment-methods/test-class-upe-payment-gateway.php
new file mode 100644
index 00000000000..8260f8707b5
--- /dev/null
+++ b/tests/unit/payment-methods/test-class-upe-payment-gateway.php
@@ -0,0 +1,1029 @@
+ 'success',
+ 'payment_needed' => true,
+ 'redirect' => 'testURL/key=mock_order_key',
+ ];
+
+ /**
+ * WC_Payments_Localization_Service instance.
+ *
+ * @var WC_Payments_Localization_Service
+ */
+ private $mock_localization_service;
+
+ /**
+ * Mock Fraud Service.
+ *
+ * @var WC_Payments_Fraud_Service|MockObject;
+ */
+ private $mock_fraud_service;
+
+ /**
+ * Pre-test setup
+ */
+ public function set_up() {
+ parent::set_up();
+
+ // Arrange: Mock WC_Payments_API_Client so we can configure the
+ // return value of create_and_confirm_intention().
+ // Note that we cannot use createStub here since it's not defined in PHPUnit 6.5.
+ $this->mock_api_client = $this->getMockBuilder( 'WC_Payments_API_Client' )
+ ->disableOriginalConstructor()
+ ->onlyMethods(
+ [
+ 'get_payment_method',
+ 'is_server_connected',
+ 'get_timeline',
+ ]
+ )
+ ->getMock();
+
+ $this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class );
+ $this->mock_wcpay_account->method( 'get_account_country' )->willReturn( 'US' );
+ $this->mock_wcpay_account->method( 'get_account_default_currency' )->willReturn( 'USD' );
+
+ // 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 );
+
+ $payment_methods = [
+ 'link' => [
+ 'base' => 0.1,
+ ],
+ ];
+
+ $this->mock_wcpay_account
+ ->expects( $this->any() )
+ ->method( 'get_fees' )
+ ->willReturn( $payment_methods );
+
+ $this->mock_woopay_utilities = $this->createMock( WooPay_Utilities::class );
+
+ // Arrange: Mock WC_Payments_Customer_Service so its methods aren't called directly.
+ $this->mock_customer_service = $this->getMockBuilder( 'WC_Payments_Customer_Service' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ // Arrange: Mock WC_Payments_Customer_Service so its methods aren't called directly.
+ $this->mock_token_service = $this->getMockBuilder( 'WC_Payments_Token_Service' )
+ ->disableOriginalConstructor()
+ ->onlyMethods( [ 'add_payment_method_to_user' ] )
+ ->getMock();
+
+ // Arrange: Mock WC_Payments_Action_Scheduler_Service so its methods aren't called directly.
+ $this->mock_action_scheduler_service = $this->getMockBuilder( 'WC_Payments_Action_Scheduler_Service' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+
+ $this->mock_localization_service = $this->createMock( WC_Payments_Localization_Service::class );
+ $this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class );
+
+ $this->mock_payment_methods = [];
+ $payment_method_classes = [
+ CC_Payment_Method::class,
+ Giropay_Payment_Method::class,
+ Sofort_Payment_Method::class,
+ Bancontact_Payment_Method::class,
+ EPS_Payment_Method::class,
+ P24_Payment_Method::class,
+ Ideal_Payment_Method::class,
+ Sepa_Payment_Method::class,
+ Becs_Payment_Method::class,
+ Link_Payment_Method::class,
+ Affirm_Payment_Method::class,
+ Afterpay_Payment_Method::class,
+ ];
+
+ $this->mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class );
+ foreach ( $payment_method_classes as $payment_method_class ) {
+ $mock_payment_method = $this->getMockBuilder( $payment_method_class )
+ ->setConstructorArgs( [ $this->mock_token_service ] )
+ ->onlyMethods( [ 'is_subscription_item_in_cart', 'get_icon' ] )
+ ->getMock();
+ $this->mock_payment_methods[ $mock_payment_method->get_id() ] = $mock_payment_method;
+ }
+
+ $this->mock_order_service = $this->getMockBuilder( WC_Payments_Order_Service::class )
+ ->setConstructorArgs(
+ [
+ $this->mock_api_client,
+ ]
+ )
+ ->onlyMethods(
+ [
+ 'get_payment_method_id_for_order',
+ ]
+ )
+ ->getMock();
+
+ $this->mock_payment_method = $this->getMockBuilder( $payment_method_class )
+ ->setConstructorArgs( [ $this->mock_token_service ] )
+ ->onlyMethods( [ 'is_subscription_item_in_cart', 'get_icon' ] )
+ ->getMock();
+ $this->mock_payment_methods[ $this->mock_payment_method->get_id() ] = $this->mock_payment_method;
+
+ // Arrange: Mock WC_Payment_Gateway_WCPay so that some of its methods can be
+ // mocked, and their return values can be used for testing.
+ $this->mock_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
+ ->setConstructorArgs(
+ [
+ $this->mock_api_client,
+ $this->mock_wcpay_account,
+ $this->mock_customer_service,
+ $this->mock_token_service,
+ $this->mock_action_scheduler_service,
+ $this->mock_payment_method,
+ $this->mock_payment_methods,
+ $this->mock_rate_limiter,
+ $this->mock_order_service,
+ $this->mock_dpps,
+ $this->mock_localization_service,
+ $this->mock_fraud_service,
+ ]
+ )
+ ->setMethods(
+ [
+ 'get_return_url',
+ 'manage_customer_details_for_order',
+ 'parent_process_payment',
+ 'get_upe_enabled_payment_method_statuses',
+ 'is_payment_recurring',
+ ]
+ )
+ ->getMock();
+
+ // Arrange: Set the return value of get_return_url() so it can be used in a test later.
+ $this->mock_gateway
+ ->expects( $this->any() )
+ ->method( 'get_return_url' )
+ ->will(
+ $this->returnValue( $this->return_url )
+ );
+ $this->mock_gateway
+ ->expects( $this->any() )
+ ->method( 'parent_process_payment' )
+ ->will(
+ $this->returnValue( $this->mock_payment_result )
+ );
+
+ // Arrange: Define a $_POST array which includes the payment method,
+ // so that get_payment_method_from_request() does not throw error.
+ $_POST = [
+ 'wcpay-payment-method' => 'pm_mock',
+ 'payment_method' => WC_Payment_Gateway_WCPay::GATEWAY_ID,
+ ];
+
+ // Mock the level3 service to always return an empty array.
+ $mock_level3_service = $this->createMock( Level3Service::class );
+ $mock_level3_service->expects( $this->any() )
+ ->method( 'get_data_from_order' )
+ ->willReturn( [] );
+ wcpay_get_test_container()->replace( Level3Service::class, $mock_level3_service );
+
+ // Mock the order service to always return an empty array for meta.
+ $mock_order_service = $this->createMock( OrderService::class );
+ $mock_order_service->expects( $this->any() )
+ ->method( 'get_payment_metadata' )
+ ->willReturn( [] );
+ wcpay_get_test_container()->replace( OrderService::class, $mock_order_service );
+ }
+
+ /**
+ * Cleanup after tests.
+ *
+ * @return void
+ */
+ public function tear_down() {
+ parent::tear_down();
+ WC_Payments::set_database_cache( $this->_cache );
+ wcpay_get_test_container()->reset_all_replacements();
+ }
+
+ public function test_process_payment_returns_correct_redirect_when_using_saved_payment() {
+ $order = WC_Helper_Order::create_order();
+ $_POST = $this->setup_saved_payment_method();
+ $intent = WC_Helper_Intention::create_intention();
+
+ $this->mock_gateway->expects( $this->once() )
+ ->method( 'manage_customer_details_for_order' )
+ ->will(
+ $this->returnValue( [ wp_get_current_user(), 'cus_123' ] )
+ );
+ $this->mock_wcpay_request( Create_And_Confirm_Intention::class, 1, $intent->get_id() )
+ ->expects( $this->once() )
+ ->method( 'format_response' )
+ ->willReturn( $intent );
+
+ $this->set_cart_contains_subscription_items( false );
+
+ $result = $this->mock_gateway->process_payment( $order->get_id() );
+
+ $this->assertEquals( 'success', $result['result'] );
+ $this->assertEquals( $this->return_url, $result['redirect'] );
+ }
+
+ public function test_process_payment_returns_correct_redirect_when_using_payment_request() {
+ $order = WC_Helper_Order::create_order();
+ $intent = WC_Helper_Intention::create_intention();
+ $_POST['payment_request_type'] = 'google_pay';
+
+ $this->mock_gateway->expects( $this->once() )
+ ->method( 'manage_customer_details_for_order' )
+ ->will(
+ $this->returnValue( [ wp_get_current_user(), 'cus_123' ] )
+ );
+ $this->mock_wcpay_request( Create_And_Confirm_Intention::class, 1, $intent->get_id() )
+ ->expects( $this->once() )
+ ->method( 'format_response' )
+ ->willReturn( $intent );
+ $this->set_cart_contains_subscription_items( false );
+
+ $result = $this->mock_gateway->process_payment( $order->get_id() );
+
+ $this->assertEquals( 'success', $result['result'] );
+ $this->assertEquals( $this->return_url, $result['redirect'] );
+ }
+
+ public function is_proper_intent_used_with_order_returns_false() {
+ $this->assertFalse( $this->mock_gateway->is_proper_intent_used_with_order( WC_Helper_Order::create_order(), 'wrong_intent_id' ) );
+ }
+
+ public function test_process_redirect_payment_intent_processing() {
+ $order = WC_Helper_Order::create_order();
+ $order_id = $order->get_id();
+ $save_payment_method = false;
+ $user = wp_get_current_user();
+ $intent_status = Intent_Status::PROCESSING;
+ $intent_metadata = [ 'order_id' => (string) $order_id ];
+ $charge_id = 'ch_mock';
+ $customer_id = 'cus_mock';
+ $intent_id = 'pi_mock';
+ $payment_method_id = 'pm_mock';
+
+ // Supply the order with the intent id so that it can be retrieved during the redirect payment processing.
+ $order->update_meta_data( '_intent_id', $intent_id );
+ $order->save();
+
+ $payment_intent = WC_Helper_Intention::create_intention(
+ [
+ 'status' => $intent_status,
+ 'metadata' => $intent_metadata,
+ ]
+ );
+
+ $this->mock_gateway->expects( $this->once() )
+ ->method( 'manage_customer_details_for_order' )
+ ->will(
+ $this->returnValue( [ $user, $customer_id ] )
+ );
+
+ $request = $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id );
+
+ $request->expects( $this->once() )
+ ->method( 'format_response' )
+ ->will( $this->returnValue( $payment_intent ) );
+
+ $this->set_cart_contains_subscription_items( false );
+
+ $this->mock_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method );
+
+ $result_order = wc_get_order( $order_id );
+ $note = wc_get_order_notes(
+ [
+ 'order_id' => $order_id,
+ 'limit' => 1,
+ ]
+ )[0];
+
+ $this->assertStringContainsString( 'authorized', $note->content );
+ $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) );
+ $this->assertEquals( $charge_id, $result_order->get_meta( '_charge_id', true ) );
+ $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) );
+ $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) );
+ $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) );
+ $this->assertEquals( Order_Status::ON_HOLD, $result_order->get_status() );
+ }
+
+ public function test_process_redirect_payment_intent_succeded() {
+ $order = WC_Helper_Order::create_order();
+ $order_id = $order->get_id();
+ $save_payment_method = false;
+ $user = wp_get_current_user();
+ $intent_status = Intent_Status::SUCCEEDED;
+ $intent_metadata = [ 'order_id' => (string) $order_id ];
+ $charge_id = 'ch_mock';
+ $customer_id = 'cus_mock';
+ $intent_id = 'pi_mock';
+ $payment_method_id = 'pm_mock';
+
+ // Supply the order with the intent id so that it can be retrieved during the redirect payment processing.
+ $order->update_meta_data( '_intent_id', $intent_id );
+ $order->save();
+
+ $payment_intent = WC_Helper_Intention::create_intention(
+ [
+ 'status' => $intent_status,
+ 'metadata' => $intent_metadata,
+ ]
+ );
+
+ $this->mock_gateway->expects( $this->once() )
+ ->method( 'manage_customer_details_for_order' )
+ ->will(
+ $this->returnValue( [ $user, $customer_id ] )
+ );
+
+ $request = $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id );
+
+ $request->expects( $this->once() )
+ ->method( 'format_response' )
+ ->will( $this->returnValue( $payment_intent ) );
+
+ $this->set_cart_contains_subscription_items( false );
+
+ $this->mock_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method );
+
+ $result_order = wc_get_order( $order_id );
+
+ $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) );
+ $this->assertEquals( $charge_id, $result_order->get_meta( '_charge_id', true ) );
+ $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) );
+ $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) );
+ $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) );
+ $this->assertEquals( Order_Status::PROCESSING, $result_order->get_status() );
+ }
+
+ public function test_validate_order_id_received_vs_intent_meta_order_id_throw_exception() {
+ $order = WC_Helper_Order::create_order();
+ $intent_metadata = [ 'order_id' => (string) ( $order->get_id() + 100 ) ];
+
+ $this->expectException( Process_Payment_Exception::class );
+ $this->expectExceptionMessage( "We're not able to process this payment due to the order ID mismatch. Please try again later." );
+
+ \PHPUnit_Utils::call_method(
+ $this->mock_gateway,
+ 'validate_order_id_received_vs_intent_meta_order_id',
+ [ $order, $intent_metadata ]
+ );
+ }
+
+ public function test_validate_order_id_received_vs_intent_meta_order_id_returning_void() {
+ $order = WC_Helper_Order::create_order();
+ $intent_metadata = [ 'order_id' => (string) ( $order->get_id() ) ];
+
+ $res = \PHPUnit_Utils::call_method(
+ $this->mock_gateway,
+ 'validate_order_id_received_vs_intent_meta_order_id',
+ [ $order, $intent_metadata ]
+ );
+
+ $this->assertSame( null, $res );
+ }
+
+ public function test_correct_payment_method_title_for_order() {
+ $order = WC_Helper_Order::create_order();
+
+ $visa_credit_details = [
+ 'type' => 'card',
+ 'card' => [
+ 'network' => 'visa',
+ 'funding' => 'credit',
+ ],
+ ];
+ $visa_debit_details = [
+ 'type' => 'card',
+ 'card' => [
+ 'network' => 'visa',
+ 'funding' => 'debit',
+ ],
+ ];
+ $mastercard_credit_details = [
+ 'type' => 'card',
+ 'card' => [
+ 'network' => 'mastercard',
+ 'funding' => 'credit',
+ ],
+ ];
+ $eps_details = [
+ 'type' => 'eps',
+ ];
+ $giropay_details = [
+ 'type' => 'giropay',
+ ];
+ $p24_details = [
+ 'type' => 'p24',
+ ];
+ $sofort_details = [
+ 'type' => 'sofort',
+ ];
+ $bancontact_details = [
+ 'type' => 'bancontact',
+ ];
+ $sepa_details = [
+ 'type' => 'sepa_debit',
+ ];
+ $ideal_details = [
+ 'type' => 'ideal',
+ ];
+ $becs_details = [
+ 'type' => 'au_becs_debit',
+ ];
+
+ $charge_payment_method_details = [
+ $visa_credit_details,
+ $visa_debit_details,
+ $mastercard_credit_details,
+ $giropay_details,
+ $sofort_details,
+ $bancontact_details,
+ $eps_details,
+ $p24_details,
+ $ideal_details,
+ $sepa_details,
+ $becs_details,
+ ];
+
+ $expected_payment_method_titles = [
+ 'Visa credit card',
+ 'Visa debit card',
+ 'Mastercard credit card',
+ 'giropay',
+ 'Sofort',
+ 'Bancontact',
+ 'EPS',
+ 'Przelewy24 (P24)',
+ 'iDEAL',
+ 'SEPA Direct Debit',
+ 'BECS Direct Debit',
+ ];
+
+ foreach ( $charge_payment_method_details as $i => $payment_method_details ) {
+ $this->mock_gateway->set_payment_method_title_for_order( $order, $payment_method_details['type'], $payment_method_details );
+ $this->assertEquals( $expected_payment_method_titles[ $i ], $order->get_payment_method_title() );
+ }
+ }
+
+ public function test_payment_methods_show_correct_default_outputs() {
+ $mock_token = WC_Helper_Token::create_token( 'pm_mock' );
+ $this->mock_token_service->expects( $this->any() )
+ ->method( 'add_payment_method_to_user' )
+ ->will(
+ $this->returnValue( $mock_token )
+ );
+
+ $mock_user = 'mock_user';
+ $mock_payment_method_id = 'pm_mock';
+
+ $mock_visa_details = [
+ 'type' => 'card',
+ 'card' => [
+ 'network' => 'visa',
+ 'funding' => 'debit',
+ ],
+ ];
+ $mock_mastercard_details = [
+ 'type' => 'card',
+ 'card' => [
+ 'network' => 'mastercard',
+ 'funding' => 'credit',
+ ],
+ ];
+ $mock_giropay_details = [
+ 'type' => 'giropay',
+ ];
+ $mock_p24_details = [
+ 'type' => 'p24',
+ ];
+ $mock_sofort_details = [
+ 'type' => 'sofort',
+ ];
+ $mock_bancontact_details = [
+ 'type' => 'bancontact',
+ ];
+ $mock_eps_details = [
+ 'type' => 'eps',
+ ];
+ $mock_sepa_details = [
+ 'type' => 'sepa_debit',
+ ];
+ $mock_ideal_details = [
+ 'type' => 'ideal',
+ ];
+ $mock_becs_details = [
+ 'type' => 'au_becs_debit',
+ ];
+ $mock_affirm_details = [
+ 'type' => 'affirm',
+ ];
+ $mock_afterpay_details = [
+ 'type' => 'afterpay_clearpay',
+ ];
+
+ $this->set_cart_contains_subscription_items( false );
+ $card_method = $this->mock_payment_methods['card'];
+ $giropay_method = $this->mock_payment_methods['giropay'];
+ $p24_method = $this->mock_payment_methods['p24'];
+ $sofort_method = $this->mock_payment_methods['sofort'];
+ $bancontact_method = $this->mock_payment_methods['bancontact'];
+ $eps_method = $this->mock_payment_methods['eps'];
+ $sepa_method = $this->mock_payment_methods['sepa_debit'];
+ $ideal_method = $this->mock_payment_methods['ideal'];
+ $becs_method = $this->mock_payment_methods['au_becs_debit'];
+ $affirm_method = $this->mock_payment_methods['affirm'];
+ $afterpay_method = $this->mock_payment_methods['afterpay_clearpay'];
+
+ $this->assertEquals( 'card', $card_method->get_id() );
+ $this->assertEquals( 'Credit card / debit card', $card_method->get_title( 'US' ) );
+ $this->assertEquals( 'Visa debit card', $card_method->get_title( 'US', $mock_visa_details ) );
+ $this->assertEquals( 'Mastercard credit card', $card_method->get_title( 'US', $mock_mastercard_details ) );
+ $this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertTrue( $card_method->is_reusable() );
+ $this->assertEquals( $mock_token, $card_method->get_payment_token_for_user( $mock_user, $mock_payment_method_id ) );
+
+ $this->assertEquals( 'giropay', $giropay_method->get_id() );
+ $this->assertEquals( 'giropay', $giropay_method->get_title( 'US' ) );
+ $this->assertEquals( 'giropay', $giropay_method->get_title( 'US', $mock_giropay_details ) );
+ $this->assertTrue( $giropay_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $giropay_method->is_reusable() );
+
+ $this->assertEquals( 'p24', $p24_method->get_id() );
+ $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( 'US' ) );
+ $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( 'US', $mock_p24_details ) );
+ $this->assertTrue( $p24_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $p24_method->is_reusable() );
+
+ $this->assertEquals( 'sofort', $sofort_method->get_id() );
+ $this->assertEquals( 'Sofort', $sofort_method->get_title( 'US' ) );
+ $this->assertEquals( 'Sofort', $sofort_method->get_title( 'US', $mock_sofort_details ) );
+ $this->assertTrue( $sofort_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $sofort_method->is_reusable() );
+
+ $this->assertEquals( 'bancontact', $bancontact_method->get_id() );
+ $this->assertEquals( 'Bancontact', $bancontact_method->get_title( 'US' ) );
+ $this->assertEquals( 'Bancontact', $bancontact_method->get_title( 'US', $mock_bancontact_details ) );
+ $this->assertTrue( $bancontact_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $bancontact_method->is_reusable() );
+
+ $this->assertEquals( 'eps', $eps_method->get_id() );
+ $this->assertEquals( 'EPS', $eps_method->get_title( 'US' ) );
+ $this->assertEquals( 'EPS', $eps_method->get_title( 'US', $mock_eps_details ) );
+ $this->assertTrue( $eps_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $eps_method->is_reusable() );
+
+ $this->assertEquals( 'sepa_debit', $sepa_method->get_id() );
+ $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( 'US' ) );
+ $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( 'US', $mock_sepa_details ) );
+ $this->assertTrue( $sepa_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $sepa_method->is_reusable() );
+
+ $this->assertEquals( 'ideal', $ideal_method->get_id() );
+ $this->assertEquals( 'iDEAL', $ideal_method->get_title( 'US' ) );
+ $this->assertEquals( 'iDEAL', $ideal_method->get_title( 'US', $mock_ideal_details ) );
+ $this->assertTrue( $ideal_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $ideal_method->is_reusable() );
+
+ $this->assertEquals( 'au_becs_debit', $becs_method->get_id() );
+ $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( 'US' ) );
+ $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( 'US', $mock_becs_details ) );
+ $this->assertTrue( $becs_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $becs_method->is_reusable() );
+
+ $this->assertSame( 'affirm', $affirm_method->get_id() );
+ $this->assertSame( 'Affirm', $affirm_method->get_title( 'US' ) );
+ $this->assertSame( 'Affirm', $affirm_method->get_title( 'US', $mock_affirm_details ) );
+ $this->assertTrue( $affirm_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $affirm_method->is_reusable() );
+
+ $this->assertSame( 'afterpay_clearpay', $afterpay_method->get_id() );
+ $this->assertSame( 'Afterpay', $afterpay_method->get_title( 'US' ) );
+ $this->assertSame( 'Afterpay', $afterpay_method->get_title( 'US', $mock_afterpay_details ) );
+ $this->assertTrue( $afterpay_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $afterpay_method->is_reusable() );
+ $this->assertSame( 'Clearpay', $afterpay_method->get_title( 'GB' ) );
+ $this->assertSame( 'Clearpay', $afterpay_method->get_title( 'GB', $mock_afterpay_details ) );
+ $this->assertTrue( $afterpay_method->is_enabled_at_checkout( 'GB' ) );
+ }
+
+ public function test_only_reusabled_payment_methods_enabled_with_subscription_item_present() {
+ $this->set_cart_contains_subscription_items( true );
+
+ $card_method = $this->mock_payment_methods['card'];
+ $giropay_method = $this->mock_payment_methods['giropay'];
+ $sofort_method = $this->mock_payment_methods['sofort'];
+ $bancontact_method = $this->mock_payment_methods['bancontact'];
+ $eps_method = $this->mock_payment_methods['eps'];
+ $sepa_method = $this->mock_payment_methods['sepa_debit'];
+ $p24_method = $this->mock_payment_methods['p24'];
+ $ideal_method = $this->mock_payment_methods['ideal'];
+ $becs_method = $this->mock_payment_methods['au_becs_debit'];
+ $affirm_method = $this->mock_payment_methods['affirm'];
+ $afterpay_method = $this->mock_payment_methods['afterpay_clearpay'];
+
+ $this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $giropay_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $sofort_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $bancontact_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $eps_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $sepa_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $p24_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $ideal_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $becs_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $affirm_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $afterpay_method->is_enabled_at_checkout( 'US' ) );
+ }
+
+ public function test_only_valid_payment_methods_returned_for_currency() {
+ $card_method = $this->mock_payment_methods['card'];
+ $giropay_method = $this->mock_payment_methods['giropay'];
+ $sofort_method = $this->mock_payment_methods['sofort'];
+ $bancontact_method = $this->mock_payment_methods['bancontact'];
+ $eps_method = $this->mock_payment_methods['eps'];
+ $sepa_method = $this->mock_payment_methods['sepa_debit'];
+ $p24_method = $this->mock_payment_methods['p24'];
+ $ideal_method = $this->mock_payment_methods['ideal'];
+ $becs_method = $this->mock_payment_methods['au_becs_debit'];
+ $affirm_method = $this->mock_payment_methods['affirm'];
+ $afterpay_method = $this->mock_payment_methods['afterpay_clearpay'];
+
+ WC_Helper_Site_Currency::$mock_site_currency = 'EUR';
+
+ $account_domestic_currency = 'USD';
+ $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $giropay_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $sofort_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $bancontact_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $eps_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $sepa_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $p24_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $ideal_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) );
+ // BNPLs can accept only domestic payments.
+ $this->assertFalse( $affirm_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $afterpay_method->is_currency_valid( $account_domestic_currency ) );
+
+ WC_Helper_Site_Currency::$mock_site_currency = 'USD';
+
+ $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $giropay_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $sofort_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $bancontact_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $eps_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $sepa_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $p24_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $ideal_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $affirm_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $afterpay_method->is_currency_valid( $account_domestic_currency ) );
+
+ WC_Helper_Site_Currency::$mock_site_currency = 'AUD';
+ $this->assertTrue( $becs_method->is_currency_valid( $account_domestic_currency ) );
+
+ // BNPLs can accept only domestic payments.
+ WC_Helper_Site_Currency::$mock_site_currency = 'USD';
+ $account_domestic_currency = 'CAD';
+ $this->assertFalse( $affirm_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $afterpay_method->is_currency_valid( $account_domestic_currency ) );
+
+ WC_Helper_Site_Currency::$mock_site_currency = '';
+ }
+
+ public function test_payment_method_compares_correct_currency() {
+ $card_method = $this->mock_payment_methods['card'];
+ $giropay_method = $this->mock_payment_methods['giropay'];
+ $sofort_method = $this->mock_payment_methods['sofort'];
+ $bancontact_method = $this->mock_payment_methods['bancontact'];
+ $eps_method = $this->mock_payment_methods['eps'];
+ $sepa_method = $this->mock_payment_methods['sepa_debit'];
+ $p24_method = $this->mock_payment_methods['p24'];
+ $ideal_method = $this->mock_payment_methods['ideal'];
+ $becs_method = $this->mock_payment_methods['au_becs_debit'];
+ $affirm_method = $this->mock_payment_methods['affirm'];
+ $afterpay_method = $this->mock_payment_methods['afterpay_clearpay'];
+
+ WC_Helper_Site_Currency::$mock_site_currency = 'EUR';
+ $account_domestic_currency = 'USD';
+
+ $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $giropay_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $sofort_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $bancontact_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $eps_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $sepa_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $p24_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $ideal_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) );
+
+ global $wp;
+ $order = WC_Helper_Order::create_order();
+ $order_id = $order->get_id();
+ $wp->query_vars = [ 'order-pay' => strval( $order_id ) ];
+ $order->set_currency( 'USD' );
+
+ $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $giropay_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $sofort_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $bancontact_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $eps_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $sepa_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $p24_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $ideal_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $affirm_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $afterpay_method->is_currency_valid( $account_domestic_currency ) );
+
+ $wp->query_vars = [];
+ }
+
+ public function test_create_token_from_setup_intent_adds_token() {
+ $mock_token = WC_Helper_Token::create_token( 'pm_mock' );
+ $mock_setup_intent_id = 'si_mock';
+ $mock_user = wp_get_current_user();
+
+ $request = $this->mock_wcpay_request( Get_Setup_Intention::class, 1, $mock_setup_intent_id );
+
+ $request->expects( $this->once() )
+ ->method( 'format_response' )
+ ->willReturn(
+ WC_Helper_Intention::create_setup_intention(
+ [
+ 'id' => $mock_setup_intent_id,
+ 'payment_method' => 'pm_mock',
+ ]
+ )
+ );
+
+ $this->mock_token_service->expects( $this->once() )
+ ->method( 'add_payment_method_to_user' )
+ ->with( 'pm_mock', $mock_user )
+ ->will(
+ $this->returnValue( $mock_token )
+ );
+
+ $this->assertEquals( $mock_token, $this->mock_gateway->create_token_from_setup_intent( $mock_setup_intent_id, $mock_user ) );
+ }
+
+ public function test_exception_will_be_thrown_if_phone_number_is_invalid() {
+ $order = WC_Helper_Order::create_order();
+ $order->set_billing_phone( '+1123456789123456789123' );
+ $order->save();
+ $this->expectException( Exception::class );
+ $this->expectExceptionMessage( 'Invalid phone number.' );
+ $this->mock_gateway->process_payment( $order->get_id() );
+ }
+
+ public function test_remove_link_payment_method_if_card_disabled() {
+ $this->mock_gateway->settings['upe_enabled_payment_method_ids'] = [ 'link' ];
+
+ $this->mock_gateway
+ ->expects( $this->once() )
+ ->method( 'get_upe_enabled_payment_method_statuses' )
+ ->will(
+ $this->returnValue( [ 'link_payments' => [ 'status' => 'active' ] ] )
+ );
+
+ $this->assertSame( $this->mock_gateway->get_payment_method_ids_enabled_at_checkout(), [] );
+ }
+
+ /**
+ * @dataProvider available_payment_methods_provider
+ */
+ public function test_get_upe_available_payment_methods( $payment_methods, $expected_result ) {
+ $mock_wcpay_account = $this->createMock( WC_Payments_Account::class );
+ $mock_wcpay_account
+ ->expects( $this->any() )
+ ->method( 'get_fees' )
+ ->willReturn( $payment_methods );
+
+ $gateway = new WC_Payment_Gateway_WCPay(
+ $this->mock_api_client,
+ $mock_wcpay_account,
+ $this->mock_customer_service,
+ $this->mock_token_service,
+ $this->mock_action_scheduler_service,
+ $this->mock_payment_method,
+ $this->mock_payment_methods,
+ $this->mock_rate_limiter,
+ $this->mock_order_service,
+ $this->mock_dpps,
+ $this->mock_localization_service,
+ $this->mock_fraud_service
+ );
+
+ $this->assertEquals( $expected_result, $gateway->get_upe_available_payment_methods() );
+ }
+
+ public function available_payment_methods_provider() {
+ return [
+ 'card only' => [
+ [ 'card' => [ 'base' => 0.1 ] ],
+ [ 'card' ],
+ ],
+ 'no match with fees' => [
+ [ 'some_other_payment_method' => [ 'base' => 0.1 ] ],
+ [],
+ ],
+ 'multiple matches with fees' => [
+ [
+ 'card' => [ 'base' => 0.1 ],
+ 'bancontact' => [ 'base' => 0.2 ],
+ ],
+ [ 'card', 'bancontact' ],
+ ],
+ 'no fees no methods' => [
+ [],
+ [],
+ ],
+ ];
+ }
+
+ /**
+ * Helper function to mock subscriptions for internal UPE payment methods.
+ */
+ private function set_cart_contains_subscription_items( $cart_contains_subscriptions ) {
+ foreach ( $this->mock_payment_methods as $mock_payment_method ) {
+ $mock_payment_method->expects( $this->any() )
+ ->method( 'is_subscription_item_in_cart' )
+ ->will(
+ $this->returnValue( $cart_contains_subscriptions )
+ );
+ }
+ }
+
+ private function setup_saved_payment_method() {
+ $token = WC_Helper_Token::create_token( 'pm_mock' );
+
+ return [
+ 'payment_method' => WC_Payment_Gateway_WCPay::GATEWAY_ID,
+ 'wc-' . WC_Payment_Gateway_WCPay::GATEWAY_ID . '-payment-token' => (string) $token->get_id(),
+ ];
+ }
+
+ private function set_get_upe_enabled_payment_method_statuses_return_value( $return_value = null ) {
+ if ( null === $return_value ) {
+ $return_value = [
+ 'card_payments' => [
+ 'status' => 'active',
+ ],
+ ];
+ }
+ $this->mock_gateway
+ ->expects( $this->any() )
+ ->method( 'get_upe_enabled_payment_method_statuses' )
+ ->will( $this->returnValue( $return_value ) );
+ }
+}
diff --git a/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php b/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php
new file mode 100644
index 00000000000..1e3162dead3
--- /dev/null
+++ b/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php
@@ -0,0 +1,1290 @@
+ 'success',
+ 'payment_needed' => true,
+ 'redirect' => 'testURL/key=mock_order_key',
+ ];
+
+ /**
+ * WC_Payments_Localization_Service instance.
+ *
+ * @var WC_Payments_Localization_Service
+ */
+ private $mock_localization_service;
+
+ /**
+ * Mock Fraud Service.
+ *
+ * @var WC_Payments_Fraud_Service|MockObject
+ */
+ private $mock_fraud_service;
+
+ /**
+ * Mapping for payment ID to payment method.
+ *
+ * @var array
+ */
+ private $payment_method_classes = [
+ Payment_Method::CARD => CC_Payment_Method::class,
+ Payment_Method::GIROPAY => Giropay_Payment_Method::class,
+ Payment_Method::SOFORT => Sofort_Payment_Method::class,
+ Payment_Method::BANCONTACT => Bancontact_Payment_Method::class,
+ Payment_Method::EPS => EPS_Payment_Method::class,
+ Payment_Method::P24 => P24_Payment_Method::class,
+ Payment_Method::IDEAL => Ideal_Payment_Method::class,
+ Payment_Method::SEPA => Sepa_Payment_Method::class,
+ Payment_Method::BECS => Becs_Payment_Method::class,
+ Payment_Method::LINK => Link_Payment_Method::class,
+ ];
+
+ /**
+ * Pre-test setup
+ */
+ public function set_up() {
+ parent::set_up();
+
+ $this->mock_payment_gateways = [];
+ $this->mock_payment_methods = [];
+
+ // 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 );
+
+ // Arrange: Mock WC_Payments_API_Client so we can configure the
+ // return value of create_and_confirm_intention().
+ // Note that we cannot use createStub here since it's not defined in PHPUnit 6.5.
+ $this->mock_api_client = $this->getMockBuilder( 'WC_Payments_API_Client' )
+ ->disableOriginalConstructor()
+ ->setMethods(
+ [
+ 'create_intention',
+ 'create_setup_intention',
+ 'update_intention',
+ 'get_intent',
+ 'get_payment_method',
+ 'is_server_connected',
+ 'get_charge',
+ 'get_timeline',
+ ]
+ )
+ ->getMock();
+
+ $this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class );
+ $this->mock_wcpay_account->method( 'get_account_country' )->willReturn( 'US' );
+ $this->mock_wcpay_account->method( 'get_account_default_currency' )->willReturn( 'USD' );
+
+ $payment_methods = [
+ 'link' => [
+ 'base' => 0.1,
+ ],
+ ];
+
+ $this->mock_wcpay_account
+ ->expects( $this->any() )
+ ->method( 'get_fees' )
+ ->willReturn( $payment_methods );
+
+ $this->mock_woopay_utilities = $this->createMock( WooPay_Utilities::class );
+
+ // Arrange: Mock WC_Payments_Customer_Service so its methods aren't called directly.
+ $this->mock_customer_service = $this->getMockBuilder( 'WC_Payments_Customer_Service' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ // Arrange: Mock WC_Payments_Customer_Service so its methods aren't called directly.
+ $this->mock_token_service = $this->getMockBuilder( 'WC_Payments_Token_Service' )
+ ->disableOriginalConstructor()
+ ->setMethods( [ 'add_payment_method_to_user' ] )
+ ->getMock();
+
+ // Arrange: Mock WC_Payments_Action_Scheduler_Service so its methods aren't called directly.
+ $this->mock_action_scheduler_service = $this->getMockBuilder( 'WC_Payments_Action_Scheduler_Service' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class );
+ $this->order_service = new WC_Payments_Order_Service( $this->mock_api_client );
+
+ $this->mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+
+ $this->mock_localization_service = $this->createMock( WC_Payments_Localization_Service::class );
+ $this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class );
+
+ // Arrange: Define a $_POST array which includes the payment method,
+ // so that get_payment_method_from_request() does not throw error.
+ $_POST = [
+ 'wcpay-payment-method' => 'pm_mock',
+ 'payment_method' => WC_Payment_Gateway_WCPay::GATEWAY_ID,
+ ];
+
+ $get_payment_gateway_by_id_return_value_map = [];
+
+ foreach ( $this->payment_method_classes as $payment_method_id => $payment_method_class ) {
+ $mock_payment_method = $this->getMockBuilder( $payment_method_class )
+ ->setConstructorArgs( [ $this->mock_token_service ] )
+ ->setMethods( [ 'is_subscription_item_in_cart', 'get_icon' ] )
+ ->getMock();
+ $this->mock_payment_methods[ $mock_payment_method->get_id() ] = $mock_payment_method;
+
+ $mock_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
+ ->setConstructorArgs(
+ [
+ $this->mock_api_client,
+ $this->mock_wcpay_account,
+ $this->mock_customer_service,
+ $this->mock_token_service,
+ $this->mock_action_scheduler_service,
+ $mock_payment_method,
+ $this->mock_payment_methods,
+ $this->mock_rate_limiter,
+ $this->order_service,
+ $this->mock_dpps,
+ $this->mock_localization_service,
+ $this->mock_fraud_service,
+ ]
+ )
+ ->setMethods(
+ [
+ 'get_return_url',
+ 'manage_customer_details_for_order',
+ 'parent_process_payment',
+ 'get_upe_enabled_payment_method_statuses',
+ 'is_payment_recurring',
+ 'get_payment_method_ids_enabled_at_checkout',
+ 'wc_payments_get_payment_gateway_by_id',
+ 'get_selected_payment_method',
+ 'get_upe_enabled_payment_method_ids',
+ ]
+ )
+ ->getMock();
+
+ // Arrange: Set the return value of get_return_url() so it can be used in a test later.
+ $mock_gateway
+ ->expects( $this->any() )
+ ->method( 'get_return_url' )
+ ->will(
+ $this->returnValue( $this->return_url )
+ );
+ $mock_gateway
+ ->expects( $this->any() )
+ ->method( 'parent_process_payment' )
+ ->will(
+ $this->returnValue( $this->mock_payment_result )
+ );
+
+ $this->mock_payment_gateways[ $payment_method_id ] = $mock_gateway;
+
+ $get_payment_gateway_by_id_return_value_map[] = [ $payment_method_id, $mock_gateway ];
+
+ WC_Helper_Site_Currency::$mock_site_currency = '';
+ }
+
+ foreach ( $this->mock_payment_gateways as $id => $mock_gateway ) {
+ $mock_gateway->expects( $this->any() )
+ ->method( 'wc_payments_get_payment_gateway_by_id' )
+ ->will(
+ $this->returnValueMap( $get_payment_gateway_by_id_return_value_map )
+ );
+ }
+
+ // Mock the level3 service to always return an empty array.
+ $mock_level3_service = $this->createMock( Level3Service::class );
+ $mock_level3_service->expects( $this->any() )
+ ->method( 'get_data_from_order' )
+ ->willReturn( [] );
+ wcpay_get_test_container()->replace( Level3Service::class, $mock_level3_service );
+
+ // Mock the order service to always return an empty array for meta.
+ $mock_order_service = $this->createMock( OrderService::class );
+ $mock_order_service->expects( $this->any() )
+ ->method( 'get_payment_metadata' )
+ ->willReturn( [] );
+ wcpay_get_test_container()->replace( OrderService::class, $mock_order_service );
+ }
+
+ /**
+ * Cleanup after tests.
+ *
+ * @return void
+ */
+ public function tear_down() {
+ parent::tear_down();
+ WC_Payments::set_database_cache( $this->_cache );
+ wcpay_get_test_container()->reset_all_replacements();
+ }
+
+ /**
+ * Test the UI
container that will hold the payment method.
+ *
+ * @return void
+ */
+ public function test_display_gateway_html_for_multiple_gateways() {
+ foreach ( $this->mock_payment_gateways as $payment_method_id => $mock_payment_gateway ) {
+ /**
+ * This tests each payment method output separately without concatenating the output
+ * into 1 single buffer. Each iteration has 1 assertion.
+ */
+ ob_start();
+ $mock_payment_gateway->display_gateway_html();
+ $actual_output = ob_get_contents();
+ ob_end_clean();
+
+ $this->assertStringContainsString( '
', $actual_output );
+ }
+ }
+
+ public function test_should_not_use_stripe_platform_on_checkout_page_for_upe() {
+ $payment_gateway = $this->mock_payment_gateways[ Payment_Method::SEPA ];
+ $this->assertFalse( $payment_gateway->should_use_stripe_platform_on_checkout_page() );
+ }
+
+ public function test_link_payment_method_requires_mandate_data() {
+ $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
+
+ $mock_upe_gateway
+ ->expects( $this->once() )
+ ->method( 'get_upe_enabled_payment_method_ids' )
+ ->will(
+ $this->returnValue( [ 'link' ] )
+ );
+
+ $this->assertTrue( $mock_upe_gateway->is_mandate_data_required() );
+ }
+
+ public function test_sepa_debit_payment_method_requires_mandate_data() {
+ $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::SEPA ];
+ $this->assertTrue( $mock_upe_gateway->is_mandate_data_required() );
+ }
+
+ public function test_non_required_mandate_data() {
+ $mock_gateway_not_requiring_mandate_data = $this->mock_payment_gateways[ Payment_Method::GIROPAY ];
+ $this->assertFalse( $mock_gateway_not_requiring_mandate_data->is_mandate_data_required() );
+ }
+
+ public function test_non_reusable_payment_method_is_not_available_when_subscription_is_in_cart() {
+ $non_reusable_payment_method = Payment_Method::BANCONTACT;
+ $payment_gateway = $this->mock_payment_gateways[ $non_reusable_payment_method ];
+
+ $this->set_cart_contains_subscription_items( true );
+
+ $this->assertFalse( $payment_gateway->is_available() );
+ }
+
+ public function test_process_payment_returns_correct_redirect_when_using_saved_payment() {
+ $mock_card_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
+ $user = wp_get_current_user();
+ $customer_id = 'cus_mock';
+
+ $order = WC_Helper_Order::create_order();
+ $_POST = $this->setup_saved_payment_method();
+ $mock_card_payment_gateway->expects( $this->once() )
+ ->method( 'manage_customer_details_for_order' )
+ ->will(
+ $this->returnValue( [ $user, $customer_id ] )
+ );
+ $mock_card_payment_gateway->expects( $this->any() )
+ ->method( 'get_upe_enabled_payment_method_ids' )
+ ->will(
+ $this->returnValue( [ Payment_Method::CARD ] )
+ );
+ $this->mock_wcpay_request( Create_And_Confirm_Intention::class, 1 )
+ ->expects( $this->once() )
+ ->method( 'format_response' )
+ ->willReturn(
+ WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] )
+ );
+
+ $this->set_cart_contains_subscription_items( false );
+
+ $result = $mock_card_payment_gateway->process_payment( $order->get_id() );
+
+ $this->assertEquals( 'success', $result['result'] );
+ $this->assertEquals( $this->return_url, $result['redirect'] );
+ }
+
+ public function test_upe_process_payment_check_session_order_redirect_to_previous_order() {
+ $_POST['wc_payment_intent_id'] = 'pi_mock';
+ $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::SEPA ];
+
+ $response = [
+ 'dummy_result' => 'xyz',
+ ];
+
+ // Arrange the order is being processed.
+ $order = WC_Helper_Order::create_order();
+ $order_id = $order->get_id();
+
+ // Arrange the DPPs to return a redirect.
+ $this->mock_dpps->expects( $this->once() )
+ ->method( 'check_against_session_processing_order' )
+ ->with( wc_get_order( $order ) )
+ ->willReturn( $response );
+
+ // Act: process the order but redirect to the previous/session paid order.
+ $result = $mock_upe_gateway->process_payment( $order_id );
+
+ // Assert: the result of check_against_session_processing_order.
+ $this->assertSame( $response, $result );
+ }
+
+ public function test_process_redirect_payment_intent_processing() {
+
+ $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
+ $order = WC_Helper_Order::create_order();
+
+ $order_id = $order->get_id();
+ $save_payment_method = false;
+ $user = wp_get_current_user();
+ $intent_status = Intent_Status::PROCESSING;
+ $intent_metadata = [ 'order_id' => (string) $order_id ];
+ $charge_id = 'ch_mock';
+ $customer_id = 'cus_mock';
+ $intent_id = 'pi_mock';
+ $payment_method_id = 'pm_mock';
+
+ // Supply the order with the intent id so that it can be retrieved during the redirect payment processing.
+ $order->update_meta_data( '_intent_id', $intent_id );
+ $order->save();
+
+ $card_method = $this->mock_payment_methods['card'];
+
+ $payment_intent = WC_Helper_Intention::create_intention(
+ [
+ 'status' => $intent_status,
+ 'metadata' => $intent_metadata,
+ ]
+ );
+
+ $mock_upe_gateway->expects( $this->once() )
+ ->method( 'manage_customer_details_for_order' )
+ ->will(
+ $this->returnValue( [ $user, $customer_id ] )
+ );
+
+ $mock_upe_gateway->expects( $this->any() )
+ ->method( 'get_selected_payment_method' )
+ ->willReturn( $card_method );
+
+ $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id )
+ ->expects( $this->once() )
+ ->method( 'format_response' )
+ ->willReturn( $payment_intent );
+
+ $this->set_cart_contains_subscription_items( false );
+
+ $mock_upe_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method );
+
+ $result_order = wc_get_order( $order_id );
+ $note = wc_get_order_notes(
+ [
+ 'order_id' => $order_id,
+ 'limit' => 1,
+ ]
+ )[0];
+
+ $this->assertStringContainsString( 'authorized', $note->content );
+ $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) );
+ $this->assertEquals( $charge_id, $result_order->get_meta( '_charge_id', true ) );
+ $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) );
+ $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) );
+ $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) );
+ $this->assertEquals( Order_Status::ON_HOLD, $result_order->get_status() );
+ }
+
+ public function test_process_redirect_payment_intent_succeded() {
+
+ $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
+ $order = WC_Helper_Order::create_order();
+
+ $order_id = $order->get_id();
+ $save_payment_method = false;
+ $user = wp_get_current_user();
+ $intent_status = Intent_Status::SUCCEEDED;
+ $intent_metadata = [ 'order_id' => (string) $order_id ];
+ $charge_id = 'ch_mock';
+ $customer_id = 'cus_mock';
+ $intent_id = 'pi_mock';
+ $payment_method_id = 'pm_mock';
+
+ // Supply the order with the intent id so that it can be retrieved during the redirect payment processing.
+ $order->update_meta_data( '_intent_id', $intent_id );
+ $order->save();
+
+ $card_method = $this->mock_payment_methods['card'];
+
+ $payment_intent = WC_Helper_Intention::create_intention(
+ [
+ 'status' => $intent_status,
+ 'metadata' => $intent_metadata,
+ ]
+ );
+
+ $mock_upe_gateway->expects( $this->once() )
+ ->method( 'manage_customer_details_for_order' )
+ ->will(
+ $this->returnValue( [ $user, $customer_id ] )
+ );
+
+ $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id )
+ ->expects( $this->once() )
+ ->method( 'format_response' )
+ ->willReturn( $payment_intent );
+
+ $mock_upe_gateway->expects( $this->any() )
+ ->method( 'get_selected_payment_method' )
+ ->willReturn( $card_method );
+
+ $this->set_cart_contains_subscription_items( false );
+
+ $mock_upe_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method );
+
+ $result_order = wc_get_order( $order_id );
+
+ $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) );
+ $this->assertEquals( $charge_id, $result_order->get_meta( '_charge_id', true ) );
+ $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) );
+ $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) );
+ $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) );
+ $this->assertEquals( Order_Status::PROCESSING, $result_order->get_status() );
+ }
+
+ public function is_proper_intent_used_with_order_returns_false() {
+ $this->assertFalse( $this->mock_upe_gateway->is_proper_intent_used_with_order( WC_Helper_Order::create_order(), 'wrong_intent_id' ) );
+ }
+
+ public function test_process_redirect_setup_intent_succeded() {
+
+ $order = WC_Helper_Order::create_order();
+ $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
+
+ $order_id = $order->get_id();
+ $save_payment_method = true;
+ $user = wp_get_current_user();
+ $intent_status = Intent_Status::SUCCEEDED;
+ $client_secret = 'cs_mock';
+ $customer_id = 'cus_mock';
+ $intent_id = 'si_mock';
+ $payment_method_id = 'pm_mock';
+ $token = WC_Helper_Token::create_token( $payment_method_id );
+
+ // Supply the order with the intent id so that it can be retrieved during the redirect payment processing.
+ $order->update_meta_data( '_intent_id', $intent_id );
+ $order->save();
+
+ $card_method = $this->mock_payment_methods['card'];
+
+ $order->set_shipping_total( 0 );
+ $order->set_shipping_tax( 0 );
+ $order->set_cart_tax( 0 );
+ $order->set_total( 0 );
+ $order->save();
+
+ $setup_intent = WC_Helper_Intention::create_setup_intention(
+ [
+ 'id' => $intent_id,
+ 'client_secret' => $client_secret,
+ 'status' => $intent_status,
+ 'payment_method' => $payment_method_id,
+ 'payment_method_options' => [
+ 'card' => [
+ 'request_three_d_secure' => 'automatic',
+ ],
+ ],
+ 'last_setup_error' => [],
+ ]
+ );
+
+ $mock_upe_gateway->expects( $this->once() )
+ ->method( 'manage_customer_details_for_order' )
+ ->will(
+ $this->returnValue( [ $user, $customer_id ] )
+ );
+
+ $request = $this->mock_wcpay_request( Get_Setup_Intention::class, 1, $intent_id );
+
+ $request->expects( $this->once() )
+ ->method( 'format_response' )
+ ->willReturn( $setup_intent );
+
+ $this->mock_token_service->expects( $this->once() )
+ ->method( 'add_payment_method_to_user' )
+ ->will(
+ $this->returnValue( $token )
+ );
+
+ $mock_upe_gateway->expects( $this->any() )
+ ->method( 'get_selected_payment_method' )
+ ->willReturn( $card_method );
+
+ $this->set_cart_contains_subscription_items( true );
+
+ $mock_upe_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method );
+
+ $result_order = wc_get_order( $order_id );
+
+ $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) );
+ $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) );
+ $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) );
+ $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) );
+ $this->assertEquals( Order_Status::PROCESSING, $result_order->get_status() );
+ $this->assertEquals( 1, count( $result_order->get_payment_tokens() ) );
+ }
+
+ public function test_process_redirect_payment_save_payment_token() {
+
+ $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
+
+ $order = WC_Helper_Order::create_order();
+ $order_id = $order->get_id();
+ $save_payment_method = true;
+ $user = wp_get_current_user();
+ $intent_status = Intent_Status::PROCESSING;
+ $intent_metadata = [ 'order_id' => (string) $order_id ];
+ $charge_id = 'ch_mock';
+ $customer_id = 'cus_mock';
+ $intent_id = 'pi_mock';
+ $payment_method_id = 'pm_mock';
+ $token = WC_Helper_Token::create_token( $payment_method_id );
+
+ // Supply the order with the intent id so that it can be retrieved during the redirect payment processing.
+ $order->update_meta_data( '_intent_id', $intent_id );
+ $order->save();
+
+ $card_method = $this->mock_payment_methods['card'];
+
+ $payment_intent = WC_Helper_Intention::create_intention(
+ [
+ 'status' => $intent_status,
+ 'metadata' => $intent_metadata,
+ ]
+ );
+
+ $mock_upe_gateway->expects( $this->once() )
+ ->method( 'manage_customer_details_for_order' )
+ ->will(
+ $this->returnValue( [ $user, $customer_id ] )
+ );
+
+ $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id )
+ ->expects( $this->once() )
+ ->method( 'format_response' )
+ ->willReturn( $payment_intent );
+
+ $this->mock_token_service->expects( $this->once() )
+ ->method( 'add_payment_method_to_user' )
+ ->will(
+ $this->returnValue( $token )
+ );
+
+ $mock_upe_gateway->expects( $this->any() )
+ ->method( 'get_selected_payment_method' )
+ ->willReturn( $card_method );
+
+ $this->set_cart_contains_subscription_items( false );
+
+ $mock_upe_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method );
+
+ $result_order = wc_get_order( $order_id );
+ $note = wc_get_order_notes(
+ [
+ 'order_id' => $order_id,
+ 'limit' => 1,
+ ]
+ )[0];
+
+ $this->assertStringContainsString( 'authorized', $note->content );
+ $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) );
+ $this->assertEquals( $charge_id, $result_order->get_meta( '_charge_id', true ) );
+ $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) );
+ $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) );
+ $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) );
+ $this->assertEquals( Order_Status::ON_HOLD, $result_order->get_status() );
+ $this->assertEquals( 1, count( $result_order->get_payment_tokens() ) );
+ }
+
+ public function test_correct_payment_method_title_for_order() {
+ $order = WC_Helper_Order::create_order();
+
+ $visa_credit_details = [
+ 'type' => 'card',
+ 'card' => [
+ 'network' => 'visa',
+ 'funding' => 'credit',
+ ],
+ ];
+ $visa_debit_details = [
+ 'type' => 'card',
+ 'card' => [
+ 'network' => 'visa',
+ 'funding' => 'debit',
+ ],
+ ];
+ $mastercard_credit_details = [
+ 'type' => 'card',
+ 'card' => [
+ 'network' => 'mastercard',
+ 'funding' => 'credit',
+ ],
+ ];
+ $eps_details = [
+ 'type' => 'eps',
+ ];
+ $giropay_details = [
+ 'type' => 'giropay',
+ ];
+ $p24_details = [
+ 'type' => 'p24',
+ ];
+ $sofort_details = [
+ 'type' => 'sofort',
+ ];
+ $bancontact_details = [
+ 'type' => 'bancontact',
+ ];
+ $sepa_details = [
+ 'type' => 'sepa_debit',
+ ];
+ $ideal_details = [
+ 'type' => 'ideal',
+ ];
+ $becs_details = [
+ 'type' => 'au_becs_debit',
+ ];
+
+ $charge_payment_method_details = [
+ $visa_credit_details,
+ $visa_debit_details,
+ $mastercard_credit_details,
+ $giropay_details,
+ $sofort_details,
+ $bancontact_details,
+ $eps_details,
+ $p24_details,
+ $ideal_details,
+ $sepa_details,
+ $becs_details,
+ ];
+
+ $expected_payment_method_titles = [
+ 'Visa credit card',
+ 'Visa debit card',
+ 'Mastercard credit card',
+ 'giropay',
+ 'Sofort',
+ 'Bancontact',
+ 'EPS',
+ 'Przelewy24 (P24)',
+ 'iDEAL',
+ 'SEPA Direct Debit',
+ 'BECS Direct Debit',
+ ];
+
+ foreach ( $charge_payment_method_details as $i => $payment_method_details ) {
+ $payment_method_id = $payment_method_details['type'];
+ $mock_upe_gateway = $this->mock_payment_gateways[ $payment_method_id ];
+ $payment_method = $this->mock_payment_methods[ $payment_method_id ];
+ $mock_upe_gateway->expects( $this->any() )
+ ->method( 'get_selected_payment_method' )
+ ->willReturn( $payment_method );
+ $mock_upe_gateway->set_payment_method_title_for_order( $order, $payment_method_id, $payment_method_details );
+ $this->assertEquals( $expected_payment_method_titles[ $i ], $order->get_payment_method_title() );
+ }
+ }
+
+ public function test_payment_methods_show_correct_default_outputs() {
+ $mock_token = WC_Helper_Token::create_token( 'pm_mock' );
+ $this->mock_token_service->expects( $this->any() )
+ ->method( 'add_payment_method_to_user' )
+ ->will(
+ $this->returnValue( $mock_token )
+ );
+
+ $mock_user = 'mock_user';
+ $mock_payment_method_id = 'pm_mock';
+
+ $mock_visa_details = [
+ 'type' => 'card',
+ 'card' => [
+ 'network' => 'visa',
+ 'funding' => 'debit',
+ ],
+ ];
+ $mock_mastercard_details = [
+ 'type' => 'card',
+ 'card' => [
+ 'network' => 'mastercard',
+ 'funding' => 'credit',
+ ],
+ ];
+ $mock_giropay_details = [
+ 'type' => 'giropay',
+ ];
+ $mock_p24_details = [
+ 'type' => 'p24',
+ ];
+ $mock_sofort_details = [
+ 'type' => 'sofort',
+ ];
+ $mock_bancontact_details = [
+ 'type' => 'bancontact',
+ ];
+ $mock_eps_details = [
+ 'type' => 'eps',
+ ];
+ $mock_sepa_details = [
+ 'type' => 'sepa_debit',
+ ];
+ $mock_ideal_details = [
+ 'type' => 'ideal',
+ ];
+ $mock_becs_details = [
+ 'type' => 'au_becs_debit',
+ ];
+
+ $this->set_cart_contains_subscription_items( false );
+ $card_method = $this->mock_payment_methods['card'];
+ $giropay_method = $this->mock_payment_methods['giropay'];
+ $p24_method = $this->mock_payment_methods['p24'];
+ $sofort_method = $this->mock_payment_methods['sofort'];
+ $bancontact_method = $this->mock_payment_methods['bancontact'];
+ $eps_method = $this->mock_payment_methods['eps'];
+ $sepa_method = $this->mock_payment_methods['sepa_debit'];
+ $ideal_method = $this->mock_payment_methods['ideal'];
+ $becs_method = $this->mock_payment_methods['au_becs_debit'];
+
+ $this->assertEquals( 'card', $card_method->get_id() );
+ $this->assertEquals( 'Credit card / debit card', $card_method->get_title( 'US' ) );
+ $this->assertEquals( 'Visa debit card', $card_method->get_title( 'US', $mock_visa_details ) );
+ $this->assertEquals( 'Mastercard credit card', $card_method->get_title( 'US', $mock_mastercard_details ) );
+ $this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertTrue( $card_method->is_reusable() );
+ $this->assertEquals( $mock_token, $card_method->get_payment_token_for_user( $mock_user, $mock_payment_method_id ) );
+
+ $this->assertEquals( 'giropay', $giropay_method->get_id() );
+ $this->assertEquals( 'giropay', $giropay_method->get_title( 'US' ) );
+ $this->assertEquals( 'giropay', $giropay_method->get_title( 'US', $mock_giropay_details ) );
+ $this->assertTrue( $giropay_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $giropay_method->is_reusable() );
+
+ $this->assertEquals( 'p24', $p24_method->get_id() );
+ $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( 'US' ) );
+ $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( 'US', $mock_p24_details ) );
+ $this->assertTrue( $p24_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $p24_method->is_reusable() );
+
+ $this->assertEquals( 'sofort', $sofort_method->get_id() );
+ $this->assertEquals( 'Sofort', $sofort_method->get_title( 'US' ) );
+ $this->assertEquals( 'Sofort', $sofort_method->get_title( 'US', $mock_sofort_details ) );
+ $this->assertTrue( $sofort_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $sofort_method->is_reusable() );
+
+ $this->assertEquals( 'bancontact', $bancontact_method->get_id() );
+ $this->assertEquals( 'Bancontact', $bancontact_method->get_title( 'US' ) );
+ $this->assertEquals( 'Bancontact', $bancontact_method->get_title( 'US', $mock_bancontact_details ) );
+ $this->assertTrue( $bancontact_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $bancontact_method->is_reusable() );
+
+ $this->assertEquals( 'eps', $eps_method->get_id() );
+ $this->assertEquals( 'EPS', $eps_method->get_title( 'US' ) );
+ $this->assertEquals( 'EPS', $eps_method->get_title( 'US', $mock_eps_details ) );
+ $this->assertTrue( $eps_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $eps_method->is_reusable() );
+
+ $this->assertEquals( 'sepa_debit', $sepa_method->get_id() );
+ $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( 'US' ) );
+ $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( 'US', $mock_sepa_details ) );
+ $this->assertTrue( $sepa_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $sepa_method->is_reusable() );
+
+ $this->assertEquals( 'ideal', $ideal_method->get_id() );
+ $this->assertEquals( 'iDEAL', $ideal_method->get_title( 'US' ) );
+ $this->assertEquals( 'iDEAL', $ideal_method->get_title( 'US', $mock_ideal_details ) );
+ $this->assertTrue( $ideal_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $ideal_method->is_reusable() );
+
+ $this->assertEquals( 'au_becs_debit', $becs_method->get_id() );
+ $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( 'US' ) );
+ $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( 'US', $mock_becs_details ) );
+ $this->assertTrue( $becs_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $becs_method->is_reusable() );
+ }
+
+ public function test_only_reusabled_payment_methods_enabled_with_subscription_item_present() {
+ // Setup $this->mock_payment_methods.
+
+ $this->set_cart_contains_subscription_items( true );
+
+ $card_method = $this->mock_payment_methods['card'];
+ $giropay_method = $this->mock_payment_methods['giropay'];
+ $sofort_method = $this->mock_payment_methods['sofort'];
+ $bancontact_method = $this->mock_payment_methods['bancontact'];
+ $eps_method = $this->mock_payment_methods['eps'];
+ $sepa_method = $this->mock_payment_methods['sepa_debit'];
+ $p24_method = $this->mock_payment_methods['p24'];
+ $ideal_method = $this->mock_payment_methods['ideal'];
+ $becs_method = $this->mock_payment_methods['au_becs_debit'];
+
+ $this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $giropay_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $sofort_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $bancontact_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $eps_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $sepa_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $p24_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $ideal_method->is_enabled_at_checkout( 'US' ) );
+ $this->assertFalse( $becs_method->is_enabled_at_checkout( 'US' ) );
+ }
+
+ public function test_only_valid_payment_methods_returned_for_currency() {
+ // Setup $this->mock_payment_methods.
+
+ $card_method = $this->mock_payment_methods['card'];
+ $giropay_method = $this->mock_payment_methods['giropay'];
+ $sofort_method = $this->mock_payment_methods['sofort'];
+ $bancontact_method = $this->mock_payment_methods['bancontact'];
+ $eps_method = $this->mock_payment_methods['eps'];
+ $sepa_method = $this->mock_payment_methods['sepa_debit'];
+ $p24_method = $this->mock_payment_methods['p24'];
+ $ideal_method = $this->mock_payment_methods['ideal'];
+ $becs_method = $this->mock_payment_methods['au_becs_debit'];
+
+ WC_Helper_Site_Currency::$mock_site_currency = 'EUR';
+ $account_domestic_currency = 'USD';
+
+ $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $giropay_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $sofort_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $bancontact_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $eps_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $sepa_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $p24_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertTrue( $ideal_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) );
+
+ WC_Helper_Site_Currency::$mock_site_currency = 'USD';
+
+ $this->assertTrue( $card_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $giropay_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $sofort_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $bancontact_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $eps_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $sepa_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $p24_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $ideal_method->is_currency_valid( $account_domestic_currency ) );
+ $this->assertFalse( $becs_method->is_currency_valid( $account_domestic_currency ) );
+
+ WC_Helper_Site_Currency::$mock_site_currency = 'AUD';
+ $this->assertTrue( $becs_method->is_currency_valid( $account_domestic_currency ) );
+
+ WC_Helper_Site_Currency::$mock_site_currency = '';
+ }
+
+ public function test_create_token_from_setup_intent_adds_token() {
+
+ $mock_token = WC_Helper_Token::create_token( 'pm_mock' );
+ $mock_setup_intent_id = 'si_mock';
+ $mock_user = wp_get_current_user();
+
+ $this->mock_token_service
+ ->method( 'add_payment_method_to_user' )
+ ->with( 'pm_mock', $mock_user )
+ ->will(
+ $this->returnValue( $mock_token )
+ );
+
+ foreach ( $this->mock_payment_gateways as $mock_upe_gateway ) {
+ $request = $this->mock_wcpay_request( Get_Setup_Intention::class, 1, $mock_setup_intent_id );
+
+ $request->expects( $this->once() )
+ ->method( 'format_response' )
+ ->willReturn(
+ WC_Helper_Intention::create_setup_intention(
+ [
+ 'id' => $mock_setup_intent_id,
+ 'payment_method' => 'pm_mock',
+ ]
+ )
+ );
+ $this->assertEquals( $mock_token, $mock_upe_gateway->create_token_from_setup_intent( $mock_setup_intent_id, $mock_user ) );
+ }
+ }
+
+ /**
+ * Test get_payment_method_types with regular checkout post request context.
+ *
+ * @return void
+ */
+ public function test_get_payment_methods_with_request_context() {
+ $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
+ ->setConstructorArgs(
+ [
+ $this->mock_api_client,
+ $this->mock_wcpay_account,
+ $this->mock_customer_service,
+ $this->mock_token_service,
+ $this->mock_action_scheduler_service,
+ $this->mock_payment_methods[ Payment_Method::CARD ],
+ $this->mock_payment_methods,
+ $this->mock_rate_limiter,
+ $this->order_service,
+ $this->mock_dpps,
+ $this->mock_localization_service,
+ $this->mock_fraud_service,
+ ]
+ )
+ ->setMethods( [ 'get_payment_methods_from_gateway_id' ] )
+ ->getMock();
+
+ $order = WC_Helper_Order::create_order();
+ $payment_information = new Payment_Information( 'pm_mock', $order );
+
+ $_POST['payment_method'] = 'woocommerce_payments';
+
+ $mock_upe_gateway->expects( $this->once() )
+ ->method( 'get_payment_methods_from_gateway_id' )
+ ->with( 'woocommerce_payments' )
+ ->will(
+ $this->returnValue( [ Payment_Method::CARD ] )
+ );
+
+ $payment_methods = $mock_upe_gateway->get_payment_method_types( $payment_information );
+
+ $this->assertSame( [ Payment_Method::CARD ], $payment_methods );
+
+ unset( $_POST['payment_method'] ); // phpcs:ignore WordPress.Security.NonceVerification
+ }
+
+ /**
+ * Test get_payment_method_types without post request context.
+ *
+ * @return void
+ */
+ public function test_get_payment_methods_without_request_context() {
+ $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
+ ->setConstructorArgs(
+ [
+ $this->mock_api_client,
+ $this->mock_wcpay_account,
+ $this->mock_customer_service,
+ $this->mock_token_service,
+ $this->mock_action_scheduler_service,
+ $this->mock_payment_methods[ Payment_Method::CARD ],
+ $this->mock_payment_methods,
+ $this->mock_rate_limiter,
+ $this->order_service,
+ $this->mock_dpps,
+ $this->mock_localization_service,
+ $this->mock_fraud_service,
+ ]
+ )
+ ->setMethods( [ 'get_payment_methods_from_gateway_id' ] )
+ ->getMock();
+
+ $token = WC_Helper_Token::create_token( 'pm_mock' );
+ $order = WC_Helper_Order::create_order();
+ $payment_information = new Payment_Information( 'pm_mock', $order, null, $token );
+
+ unset( $_POST['payment_method'] ); // phpcs:ignore WordPress.Security.NonceVerification
+
+ $mock_upe_gateway->expects( $this->once() )
+ ->method( 'get_payment_methods_from_gateway_id' )
+ ->with( $token->get_gateway_id(), $order->get_id() )
+ ->will(
+ $this->returnValue( [ Payment_Method::CARD ] )
+ );
+
+ $payment_methods = $mock_upe_gateway->get_payment_method_types( $payment_information );
+
+ $this->assertSame( [ Payment_Method::CARD ], $payment_methods );
+ }
+
+ /**
+ * Test get_payment_method_types without post request context or saved token.
+ *
+ * @return void
+ */
+ public function test_get_payment_methods_without_request_context_or_token() {
+ $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
+ ->setConstructorArgs(
+ [
+ $this->mock_api_client,
+ $this->mock_wcpay_account,
+ $this->mock_customer_service,
+ $this->mock_token_service,
+ $this->mock_action_scheduler_service,
+ $this->mock_payment_methods[ Payment_Method::CARD ],
+ $this->mock_payment_methods,
+ $this->mock_rate_limiter,
+ $this->order_service,
+ $this->mock_dpps,
+ $this->mock_localization_service,
+ $this->mock_fraud_service,
+ ]
+ )
+ ->setMethods(
+ [
+ 'get_payment_methods_from_gateway_id',
+ 'get_payment_method_ids_enabled_at_checkout',
+ ]
+ )
+ ->getMock();
+
+ $payment_information = new Payment_Information( 'pm_mock' );
+
+ unset( $_POST['payment_method'] ); // phpcs:ignore WordPress.Security.NonceVerification
+
+ $gateway = WC_Payments::get_gateway();
+ WC_Payments::set_gateway( $mock_upe_gateway );
+
+ $mock_upe_gateway->expects( $this->never() )
+ ->method( 'get_payment_methods_from_gateway_id' );
+
+ $mock_upe_gateway->expects( $this->once() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [ Payment_Method::CARD ] );
+
+ $payment_methods = $mock_upe_gateway->get_payment_method_types( $payment_information );
+
+ $this->assertSame( [ Payment_Method::CARD ], $payment_methods );
+
+ WC_Payments::set_gateway( $gateway );
+ }
+
+ /**
+ * Test get_payment_methods_from_gateway_id function with UPE enabled.
+ *
+ * @return void
+ */
+ public function test_get_payment_methods_from_gateway_id_upe() {
+ WC_Helper_Order::create_order();
+ $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
+ ->setConstructorArgs(
+ [
+ $this->mock_api_client,
+ $this->mock_wcpay_account,
+ $this->mock_customer_service,
+ $this->mock_token_service,
+ $this->mock_action_scheduler_service,
+ $this->mock_payment_methods[ Payment_Method::CARD ],
+ $this->mock_payment_methods,
+ $this->mock_rate_limiter,
+ $this->order_service,
+ $this->mock_dpps,
+ $this->mock_localization_service,
+ $this->mock_fraud_service,
+ ]
+ )
+ ->onlyMethods(
+ [
+ 'get_upe_enabled_payment_method_ids',
+ 'get_payment_method_ids_enabled_at_checkout',
+ ]
+ )
+ ->getMock();
+
+ $gateway = WC_Payments::get_gateway();
+ WC_Payments::set_gateway( $mock_upe_gateway );
+
+ $mock_upe_gateway->expects( $this->any() )
+ ->method( 'get_upe_enabled_payment_method_ids' )
+ ->will(
+ $this->returnValue( [ Payment_Method::CARD, Payment_Method::LINK ] )
+ );
+
+ $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( WC_Payment_Gateway_WCPay::GATEWAY_ID . '_' . Payment_Method::BANCONTACT );
+ $this->assertSame( [ Payment_Method::BANCONTACT ], $payment_methods );
+
+ $mock_upe_gateway->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->will(
+ $this->onConsecutiveCalls(
+ [ Payment_Method::CARD, Payment_Method::LINK ],
+ [ Payment_Method::CARD ]
+ )
+ );
+
+ $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( WC_Payment_Gateway_WCPay::GATEWAY_ID );
+ $this->assertSame( [ Payment_Method::CARD, Payment_Method::LINK ], $payment_methods );
+
+ $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( WC_Payment_Gateway_WCPay::GATEWAY_ID );
+ $this->assertSame( [ Payment_Method::CARD ], $payment_methods );
+
+ WC_Payments::set_gateway( $gateway );
+ }
+
+ /**
+ * Helper function to mock subscriptions for internal UPE payment methods.
+ */
+ private function set_cart_contains_subscription_items( $cart_contains_subscriptions ) {
+ foreach ( $this->mock_payment_methods as $mock_payment_method ) {
+ $mock_payment_method->expects( $this->any() )
+ ->method( 'is_subscription_item_in_cart' )
+ ->will(
+ $this->returnValue( $cart_contains_subscriptions )
+ );
+ }
+ }
+
+ private function setup_saved_payment_method() {
+ $token = WC_Helper_Token::create_token( 'pm_mock' );
+
+ return [
+ 'payment_method' => WC_Payment_Gateway_WCPay::GATEWAY_ID,
+ 'wc-' . WC_Payment_Gateway_WCPay::GATEWAY_ID . '-payment-token' => (string) $token->get_id(),
+ ];
+ }
+
+ private function set_get_upe_enabled_payment_method_statuses_return_value( $mock_payment_gateway, $return_value = null ) {
+ if ( null === $return_value ) {
+ $return_value = [
+ 'card_payments' => [
+ 'status' => 'active',
+ ],
+ ];
+ }
+ $mock_payment_gateway
+ ->expects( $this->any() )
+ ->method( 'get_upe_enabled_payment_method_statuses' )
+ ->will( $this->returnValue( $return_value ) );
+ }
+}
diff --git a/tests/unit/reports/test-class-wc-rest-payments-reports-transactions-controller.php b/tests/unit/reports/test-class-wc-rest-payments-reports-transactions-controller.php
index 46c2b21452c..260f3c62057 100644
--- a/tests/unit/reports/test-class-wc-rest-payments-reports-transactions-controller.php
+++ b/tests/unit/reports/test-class-wc-rest-payments-reports-transactions-controller.php
@@ -208,7 +208,7 @@ private function get_transactions_list_from_server() {
'currency' => 'usd',
'risk_level' => 0,
'charge_id' => 'ch_3NVXQQR7Mcmd7SUg0eV2k74L',
- 'deposit_id' => 'wcpay_estimated_daily_usd_1689897600',
+ 'deposit_id' => null,
'available_on' => '2023-07-21',
'exchange_rate' => 1.12284,
'customer_amount' => 2300,
@@ -217,7 +217,7 @@ private function get_transactions_list_from_server() {
'amount_in_usd' => 2583,
'source_device' => null,
'channel' => null,
- 'deposit_status' => 'estimated',
+ 'deposit_status' => null,
'order' => [
'number' => '123',
'url' => 'https:\/\/wcpay.test\/wp-admin\/post.php?post=278&action=edit',
@@ -241,7 +241,7 @@ private function get_transactions_list_from_server() {
'currency' => 'usd',
'risk_level' => 0,
'charge_id' => 'ch_3NVXQER7Mcmd7SUg1Mk9SsNy',
- 'deposit_id' => 'wcpay_estimated_daily_usd_1689897600',
+ 'deposit_id' => null,
'available_on' => '2023-07-21',
'exchange_rate' => 1.12284,
'customer_amount' => 2300,
@@ -250,7 +250,7 @@ private function get_transactions_list_from_server() {
'amount_in_usd' => 2583,
'source_device' => null,
'channel' => null,
- 'deposit_status' => 'estimated',
+ 'deposit_status' => null,
'order' => [
'number' => '275',
'url' => 'https:\/\/wcpay.test\/wp-admin\/post.php?post=275&action=edit',
@@ -289,8 +289,8 @@ private function get_transactions_list() {
'order_id' => 123,
'risk_level' => 0,
'deposit_date' => '2023-07-21',
- 'deposit_id' => 'wcpay_estimated_daily_usd_1689897600',
- 'deposit_status' => 'estimated',
+ 'deposit_id' => null,
+ 'deposit_status' => null,
],
[
'transaction_id' => 'txn_345',
@@ -315,8 +315,8 @@ private function get_transactions_list() {
'order_id' => 275,
'risk_level' => 0,
'deposit_date' => '2023-07-21',
- 'deposit_id' => 'wcpay_estimated_daily_usd_1689897600',
- 'deposit_status' => 'estimated',
+ 'deposit_id' => null,
+ 'deposit_status' => null,
],
];
}
diff --git a/tests/unit/subscriptions/test-class-wc-payments-subscription-migration-log-handler.php b/tests/unit/subscriptions/test-class-wc-payments-subscription-migration-log-handler.php
index 7a0a7153e7d..d105707da38 100644
--- a/tests/unit/subscriptions/test-class-wc-payments-subscription-migration-log-handler.php
+++ b/tests/unit/subscriptions/test-class-wc-payments-subscription-migration-log-handler.php
@@ -72,6 +72,14 @@ public function test_log() {
* Confirms that log files are not deleted by WC's log cleanup and that mock log files are deleted.
*/
public function test_extend_life_of_migration_file_logs() {
+
+ // WC 8.6 changed the way log files are cleaned up, this test which uses the `touch()` method is no longer valid.
+ if ( version_compare( WC_VERSION, '8.6.0', '>=' ) ) {
+ $this->markTestSkipped(
+ 'This test only applies on WC versions prior to 8.6.0.'
+ );
+ }
+
$message = 'Test message 1234567890';
// Log messages - Log to the migration file and a dummy log.
diff --git a/tests/unit/test-class-compatibility-service.php b/tests/unit/test-class-compatibility-service.php
index 8debd6b802d..fbbe4aca216 100644
--- a/tests/unit/test-class-compatibility-service.php
+++ b/tests/unit/test-class-compatibility-service.php
@@ -26,6 +26,42 @@ class Compatibility_Service_Test extends WCPAY_UnitTestCase {
*/
private $compatibility_service;
+ /**
+ * Test theme name.
+ *
+ * @var string
+ */
+ private $stylesheet = 'my_theme_name';
+
+ /**
+ * Test active plugins.
+ *
+ * @var array
+ */
+ private $active_plugins = [
+ 'woocommerce/woocommerce.php',
+ 'woocommerce-payments/woocommerce-payments.php',
+ ];
+
+ /**
+ * Test post types count.
+ *
+ * @var array
+ */
+ private $post_types_count = [
+ 'post' => 1,
+ 'page' => 6,
+ 'attachment' => 0,
+ 'product' => 12,
+ ];
+
+ /**
+ * Test posts.
+ *
+ * @var array
+ */
+ private $test_posts = [];
+
/**
* Pre-test setup
*/
@@ -35,47 +71,60 @@ public function set_up() {
$this->mock_api_client = $this->createMock( WC_Payments_API_Client::class );
$this->compatibility_service = new Compatibility_Service( $this->mock_api_client );
$this->compatibility_service->init_hooks();
+
+ $this->add_stylesheet_filter();
+ $this->add_option_active_plugins_filter();
+ $this->insert_test_posts();
}
- public function test_registers_woocommerce_filters_properly() {
- $priority = has_filter( 'woocommerce_payments_account_refreshed', [ $this->compatibility_service, 'update_compatibility_data' ] );
- $this->assertEquals( 10, $priority );
- $priority = has_action( 'after_switch_theme', [ $this->compatibility_service, 'update_compatibility_data' ] );
- $this->assertEquals( 10, $priority );
+ /**
+ * Post-test anarchy
+ */
+ public function tear_down() {
+ parent::tear_down();
+
+ $this->remove_stylesheet_filters();
+ $this->remove_option_active_plugins_filters();
+ $this->delete_test_posts();
}
- public function test_update_compatibility_data() {
- $stylesheet = 'my_theme_name';
- add_filter(
- 'stylesheet',
- function( $theme ) use ( $stylesheet ) {
- return $stylesheet;
- }
- );
+ /**
+ * Tests to make sure filters are registered correctly.
+ *
+ * @param string $filter The filter name.
+ * @param string $method The method being called in the class.
+ *
+ * @dataProvider provider_test_registers_woocommerce_filters_properly
+ *
+ * @return void
+ */
+ public function test_registers_woocommerce_filters_properly( string $filter, string $method ) {
+ $priority = has_filter( $filter, [ $this->compatibility_service, $method ] );
+ $this->assertEquals( 10, $priority );
+ }
- // Arrange: Create the expected value to be passed to update_compatibility_data.
- $expected = [
- 'woopayments_version' => WCPAY_VERSION_NUMBER,
- 'woocommerce_version' => WC_VERSION,
- 'blog_theme' => $stylesheet,
- 'active_plugins' => [
- 'woocommerce/woocommerce.php',
- 'woocommerce-payments/woocommerce-payments.php',
+ public function provider_test_registers_woocommerce_filters_properly(): array {
+ return [
+ 'woocommerce_payments_account_refreshed' => [
+ 'filter' => 'woocommerce_payments_account_refreshed',
+ 'method' => 'update_compatibility_data',
+ ],
+ 'after_switch_theme' => [
+ 'filter' => 'woocommerce_payments_account_refreshed',
+ 'method' => 'update_compatibility_data',
],
- 'post_types_count' => [
- 'post' => 1,
- 'page' => 6,
- 'attachment' => 0,
- 'product' => 12,
+ 'wc_payments_get_onboarding_data_args' => [
+ 'filter' => 'wc_payments_get_onboarding_data_args',
+ 'method' => 'add_compatibility_onboarding_data',
],
];
+ }
- // Arrange/Assert: Set the expectations for update_compatibility_data.
- add_filter( 'option_active_plugins', [ $this, 'active_plugins_filter_return' ] );
-
- // Arrange: Insert test posts.
- $post_ids = $this->insert_test_posts( $expected['post_types_count'] );
+ public function test_update_compatibility_data() {
+ // Arrange: Create the expected value to be passed to update_compatibility_data.
+ $expected = $this->get_mock_compatibility_data();
+ // Arrange/Assert: Set the expectations for update_compatibility_data.
$this->mock_api_client
->expects( $this->once() )
->method( 'update_compatibility_data' )
@@ -83,41 +132,19 @@ function( $theme ) use ( $stylesheet ) {
// Act: Call the method we're testing.
$this->compatibility_service->update_compatibility_data();
-
- remove_filter( 'option_active_plugins', [ $this, 'active_plugins_filter_return' ] );
-
- // Clean up: Delete the test posts.
- $this->delete_test_posts( $post_ids );
}
public function test_update_compatibility_data_active_plugins_false() {
- $stylesheet = 'my_theme_name';
- add_filter(
- 'stylesheet',
- function( $theme ) use ( $stylesheet ) {
- return $stylesheet;
- }
- );
-
// Arrange: Create the expected value to be passed to update_compatibility_data.
- $expected = [
- 'woopayments_version' => WCPAY_VERSION_NUMBER,
- 'woocommerce_version' => WC_VERSION,
- 'blog_theme' => $stylesheet,
- 'active_plugins' => [],
- 'post_types_count' => [
- 'post' => 1,
- 'page' => 6,
- 'attachment' => 0,
- 'product' => 12,
- ],
- ];
+ $expected = $this->get_mock_compatibility_data(
+ [
+ 'active_plugins' => [],
+ ]
+ );
+ // Arrange: Purposely break/delete the active_plugins option in WP.
$this->break_active_plugins_option();
- // Arrange: Insert test posts.
- $post_ids = $this->insert_test_posts( $expected['post_types_count'] );
-
// Arrange/Assert: Set the expectations for update_compatibility_data.
$this->mock_api_client
->expects( $this->once() )
@@ -127,25 +154,93 @@ function( $theme ) use ( $stylesheet ) {
// Act: Call the method we're testing.
$this->compatibility_service->update_compatibility_data();
+ // Arrange: Fix the broke active_plugins option in WP.
$this->fix_active_plugins_option();
+ }
+
+ public function test_add_compatibility_onboarding_data() {
+ // Arrange: Create the expected value.
+ $expected = [ 'compatibility_data' => $this->get_mock_compatibility_data() ];
- // Clean up: Delete the test posts.
- $this->delete_test_posts( $post_ids );
+ // Act/Assert: Call the method we're testing and confirm we get the expected value.
+ $this->assertSame( $expected, $this->compatibility_service->add_compatibility_onboarding_data( [] ) );
}
+ /**
+ * Returns the mock compatibility data.
+ *
+ * @param array $args If any values need to be overridden, the values can be added here.
+ *
+ * @return array
+ */
+ private function get_mock_compatibility_data( array $args = [] ): array {
+ return array_merge(
+ [
+ 'woopayments_version' => WCPAY_VERSION_NUMBER,
+ 'woocommerce_version' => WC_VERSION,
+ 'blog_theme' => $this->stylesheet,
+ 'active_plugins' => $this->active_plugins,
+ 'post_types_count' => $this->post_types_count,
+ ],
+ $args
+ );
+ }
- public function active_plugins_filter_return() {
- return [
- 'woocommerce/woocommerce.php',
- 'woocommerce-payments/woocommerce-payments.php',
- ];
+ /**
+ * Adds a filter for the theme/stylesheet name.
+ * Will use the default defined in the test class if no params passed.
+ *
+ * @param string $stylesheet The theme name you'd like to use, default null.
+ *
+ * @return void
+ */
+ private function add_stylesheet_filter( $stylesheet = null ): void {
+ $stylesheet = $stylesheet ?? $this->stylesheet;
+ add_filter(
+ 'stylesheet',
+ function( $theme ) use ( $stylesheet ) {
+ return $stylesheet;
+ },
+ 404 // 404 is used to be able to use remove_all_filters later.
+ );
+ }
+
+ // Removes all stylesheet/theme name filters.
+ private function remove_stylesheet_filters(): void {
+ remove_all_filters( 'stylesheet', 404 );
+ }
+
+ /**
+ * Adds a filter for the active plugins array.
+ * Will use the default defined in the test class if no params passed.
+ *
+ * @param array $plugins The plugin array you'd like to use, default null.
+ *
+ * @return void
+ */
+ private function add_option_active_plugins_filter( $plugins = null ): void {
+ $plugins = $plugins ?? $this->active_plugins;
+ add_filter(
+ 'option_active_plugins',
+ function( $active_plugins ) use ( $plugins ) {
+ return $plugins;
+ },
+ 404 // 404 is used to be able to use remove_all_filters later.
+ );
+ }
+
+ // Removes all active plugin filters.
+ private function remove_option_active_plugins_filters() {
+ remove_all_filters( 'option_active_plugins', [ $this, 'active_plugins_filter_return' ], 404 );
}
+ // Used to purposely delete the active_plugins option in WP.
private function break_active_plugins_option() {
update_option( 'temp_active_plugins', get_option( 'active_plugins' ) );
delete_option( 'active_plugins' );
}
+ // Used to restore the active_plugins option in WP after break_active_plugins_option is used.
private function fix_active_plugins_option() {
update_option( 'active_plugins', get_option( 'temp_active_plugins' ) );
delete_option( 'temp_active_plugins' );
@@ -153,13 +248,15 @@ private function fix_active_plugins_option() {
/**
* Insert test posts for use during a unit test.
+ * Will use the default defined in the test class if no params passed.
*
* @param array $post_types Assoc array of post types as keys and the number of posts to create for each.
*
* @return array Array of post IDs that were created.
*/
- private function insert_test_posts( array $post_types ): array {
- $post_ids = [];
+ private function insert_test_posts( array $post_types = [] ): array {
+ $post_types = ! empty( $post_types ) ? $post_types : $this->post_types_count;
+ $post_ids = [];
foreach ( $post_types as $post_type => $count ) {
$title_content = 'This is a ' . $post_type . ' test post';
for ( $i = 0; $i < $count; $i++ ) {
@@ -174,6 +271,7 @@ private function insert_test_posts( array $post_types ): array {
}
}
+ $this->test_posts = $post_ids;
return $post_ids;
}
@@ -182,7 +280,8 @@ private function insert_test_posts( array $post_types ): array {
*
* @param array $post_ids Array of post IDs to delete.
*/
- private function delete_test_posts( array $post_ids ) {
+ private function delete_test_posts( array $post_ids = [] ) {
+ $post_ids = ! empty( $post_ids ) ? $post_ids : $this->test_posts;
foreach ( $post_ids as $post_id ) {
wp_delete_post( (int) $post_id, true );
}
diff --git a/tests/unit/test-class-duplicate-payment-prevention-service.php b/tests/unit/test-class-duplicate-payment-prevention-service.php
index b0a3099b3b3..411f446cd40 100644
--- a/tests/unit/test-class-duplicate-payment-prevention-service.php
+++ b/tests/unit/test-class-duplicate-payment-prevention-service.php
@@ -77,7 +77,6 @@ public function test_check_session_order_redirect_to_previous_order() {
$result = $this->service->check_against_session_processing_order( $current_order );
// Assert: the result of check_against_session_processing_order.
- $this->assertSame( 'yes', $result['wcpay_upe_paid_for_previous_order'] );
$this->assertSame( 'success', $result['result'] );
$this->assertStringContainsString( $return_url, $result['redirect'] );
@@ -267,7 +266,6 @@ public function test_check_payment_intent_attached_to_order_succeeded_return_red
$result = $this->service->check_payment_intent_attached_to_order_succeeded( $order );
// Assert: the result of check_intent_attached_to_order_succeeded.
- $this->assertSame( 'yes', $result['wcpay_upe_previous_successful_intent'] );
$this->assertSame( 'success', $result['result'] );
$this->assertStringContainsString( $return_url, $result['redirect'] );
}
diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay-process-payment.php b/tests/unit/test-class-wc-payment-gateway-wcpay-process-payment.php
index b064ef08f90..a3038cc410c 100644
--- a/tests/unit/test-class-wc-payment-gateway-wcpay-process-payment.php
+++ b/tests/unit/test-class-wc-payment-gateway-wcpay-process-payment.php
@@ -702,7 +702,7 @@ public function test_failed_transaction_rate_limiter_is_limited() {
}
/**
- * Tests that a draft order is updated to "pending" when the $_POST 'is-woopay-preflight-check` is present.
+ * Tests that a draft order is updated to "pending" when the $_POST 'is-woopay-preflight-check' is present.
*/
public function test_draft_order_is_set_to_pending_for_woopay_preflight_check_request() {
$_POST['is-woopay-preflight-check'] = true;
@@ -723,7 +723,60 @@ public function test_draft_order_is_set_to_pending_for_woopay_preflight_check_re
}
/**
- * Tests that a success response and no redirect is returned when the $_POST 'is-woopay-preflight-check` is present.
+ * Tests that woocommerce_order_status_pending action is not called when the $_POST 'is-woopay-preflight-check' is present.
+ */
+ public function test_woopay_preflight_request_does_not_call_woocommerce_order_status_pending() {
+ // Arrange: Add woocommerce_order_status_pending action to check if it's called.
+ $results = [
+ 'has_called_woocommerce_order_status_pending' => false,
+ ];
+ add_action(
+ 'woocommerce_order_status_pending',
+ function () use ( &$results ) {
+ $results['has_called_woocommerce_order_status_pending'] = true;
+ }
+ );
+
+ // Arrange: Add filter to change default order status to 'wc-checkout-draft'.
+ // Needed to avoid a default order status of 'pending'.
+ add_filter(
+ 'woocommerce_default_order_status',
+ function () {
+ return 'wc-checkout-draft';
+ }
+ );
+
+ // Arrange: Create a request to simulate a woopay preflight request.
+ $_POST['is-woopay-preflight-check'] = true;
+ $request = new WP_REST_Request( 'POST', '' );
+ $request->set_body_params(
+ [
+ 'payment_data' => [
+ [
+ 'key' => 'is-woopay-preflight-check',
+ 'value' => true,
+ ],
+ ],
+ ]
+ );
+ apply_filters( 'rest_request_before_callbacks', [], [], $request );
+
+ // Arrange: Create an order to test with.
+ $order_data = [
+ 'status' => 'wc-checkout-draft',
+ 'total' => '100',
+ ];
+ $order = wc_create_order( $order_data );
+
+ // Act: process payment.
+ $this->mock_wcpay_gateway->process_payment( $order->get_id() );
+
+ // Assert: woocommerce_order_status_pending was not called.
+ $this->assertFalse( $results['has_called_woocommerce_order_status_pending'] );
+ }
+
+ /**
+ * Tests that a success response and no redirect is returned when the $_POST 'is-woopay-preflight-check' is present.
*/
public function test_successful_result_no_redirect_for_woopay_preflight_check_request() {
$_POST['is-woopay-preflight-check'] = true;
diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay.php b/tests/unit/test-class-wc-payment-gateway-wcpay.php
index 62dd5c2f83a..6ecc387059b 100644
--- a/tests/unit/test-class-wc-payment-gateway-wcpay.php
+++ b/tests/unit/test-class-wc-payment-gateway-wcpay.php
@@ -573,71 +573,77 @@ public function test_payment_methods_show_correct_default_outputs() {
$this->assertEquals( 'card', $card_method->get_id() );
$this->assertEquals( 'Credit card / debit card', $card_method->get_title() );
- $this->assertEquals( 'Visa debit card', $card_method->get_title( $mock_visa_details ) );
- $this->assertEquals( 'Mastercard credit card', $card_method->get_title( $mock_mastercard_details ) );
+ $this->assertEquals( 'Visa debit card', $card_method->get_title( 'US', $mock_visa_details ) );
+ $this->assertEquals( 'Mastercard credit card', $card_method->get_title( 'US', $mock_mastercard_details ) );
$this->assertTrue( $card_method->is_enabled_at_checkout( 'US' ) );
$this->assertTrue( $card_method->is_reusable() );
$this->assertEquals( $mock_token, $card_method->get_payment_token_for_user( $mock_user, $mock_payment_method_id ) );
$this->assertEquals( 'giropay', $giropay_method->get_id() );
$this->assertEquals( 'giropay', $giropay_method->get_title() );
- $this->assertEquals( 'giropay', $giropay_method->get_title( $mock_giropay_details ) );
+ $this->assertEquals( 'giropay', $giropay_method->get_title( 'US', $mock_giropay_details ) );
$this->assertTrue( $giropay_method->is_enabled_at_checkout( 'US' ) );
$this->assertFalse( $giropay_method->is_reusable() );
$this->assertEquals( 'p24', $p24_method->get_id() );
$this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title() );
- $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( $mock_p24_details ) );
+ $this->assertEquals( 'Przelewy24 (P24)', $p24_method->get_title( 'US', $mock_p24_details ) );
$this->assertTrue( $p24_method->is_enabled_at_checkout( 'US' ) );
$this->assertFalse( $p24_method->is_reusable() );
$this->assertEquals( 'sofort', $sofort_method->get_id() );
$this->assertEquals( 'Sofort', $sofort_method->get_title() );
- $this->assertEquals( 'Sofort', $sofort_method->get_title( $mock_sofort_details ) );
+ $this->assertEquals( 'Sofort', $sofort_method->get_title( 'US', $mock_sofort_details ) );
$this->assertTrue( $sofort_method->is_enabled_at_checkout( 'US' ) );
$this->assertFalse( $sofort_method->is_reusable() );
$this->assertEquals( 'bancontact', $bancontact_method->get_id() );
$this->assertEquals( 'Bancontact', $bancontact_method->get_title() );
- $this->assertEquals( 'Bancontact', $bancontact_method->get_title( $mock_bancontact_details ) );
+ $this->assertEquals( 'Bancontact', $bancontact_method->get_title( 'US', $mock_bancontact_details ) );
$this->assertTrue( $bancontact_method->is_enabled_at_checkout( 'US' ) );
$this->assertFalse( $bancontact_method->is_reusable() );
$this->assertEquals( 'eps', $eps_method->get_id() );
$this->assertEquals( 'EPS', $eps_method->get_title() );
- $this->assertEquals( 'EPS', $eps_method->get_title( $mock_eps_details ) );
+ $this->assertEquals( 'EPS', $eps_method->get_title( 'US', $mock_eps_details ) );
$this->assertTrue( $eps_method->is_enabled_at_checkout( 'US' ) );
$this->assertFalse( $eps_method->is_reusable() );
$this->assertEquals( 'sepa_debit', $sepa_method->get_id() );
$this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title() );
- $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( $mock_sepa_details ) );
+ $this->assertEquals( 'SEPA Direct Debit', $sepa_method->get_title( 'US', $mock_sepa_details ) );
$this->assertTrue( $sepa_method->is_enabled_at_checkout( 'US' ) );
$this->assertFalse( $sepa_method->is_reusable() );
$this->assertEquals( 'ideal', $ideal_method->get_id() );
$this->assertEquals( 'iDEAL', $ideal_method->get_title() );
- $this->assertEquals( 'iDEAL', $ideal_method->get_title( $mock_ideal_details ) );
+ $this->assertEquals( 'iDEAL', $ideal_method->get_title( 'US', $mock_ideal_details ) );
$this->assertTrue( $ideal_method->is_enabled_at_checkout( 'US' ) );
$this->assertFalse( $ideal_method->is_reusable() );
$this->assertEquals( 'au_becs_debit', $becs_method->get_id() );
$this->assertEquals( 'BECS Direct Debit', $becs_method->get_title() );
- $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( $mock_becs_details ) );
+ $this->assertEquals( 'BECS Direct Debit', $becs_method->get_title( 'US', $mock_becs_details ) );
$this->assertTrue( $becs_method->is_enabled_at_checkout( 'US' ) );
$this->assertFalse( $becs_method->is_reusable() );
$this->assertSame( 'affirm', $affirm_method->get_id() );
$this->assertSame( 'Affirm', $affirm_method->get_title() );
- $this->assertSame( 'Affirm', $affirm_method->get_title( $mock_affirm_details ) );
+ $this->assertSame( 'Affirm', $affirm_method->get_title( 'US', $mock_affirm_details ) );
$this->assertTrue( $affirm_method->is_enabled_at_checkout( 'US' ) );
$this->assertFalse( $affirm_method->is_reusable() );
$this->assertSame( 'afterpay_clearpay', $afterpay_method->get_id() );
$this->assertSame( 'Afterpay', $afterpay_method->get_title() );
- $this->assertSame( 'Afterpay', $afterpay_method->get_title( $mock_afterpay_details ) );
+ $this->assertSame( 'Afterpay', $afterpay_method->get_title( 'US', $mock_afterpay_details ) );
$this->assertTrue( $afterpay_method->is_enabled_at_checkout( 'US' ) );
$this->assertFalse( $afterpay_method->is_reusable() );
+
+ $this->assertSame( 'afterpay_clearpay', $afterpay_method->get_id() );
+ $this->assertSame( 'Clearpay', $afterpay_method->get_title( 'GB' ) );
+ $this->assertSame( 'Clearpay', $afterpay_method->get_title( 'GB', $mock_afterpay_details ) );
+ $this->assertTrue( $afterpay_method->is_enabled_at_checkout( 'GB' ) );
+ $this->assertFalse( $afterpay_method->is_reusable() );
}
public function test_only_reusabled_payment_methods_enabled_with_subscription_item_present() {
@@ -2790,6 +2796,35 @@ public function test_process_payment_continues_if_valid_fraud_prevention_token()
$mock_wcpay_gateway->process_payment( $order->get_id() );
}
+ public function test_process_payment_continues_if_missing_fraud_prevention_token_but_request_is_from_woopay() {
+ $order = WC_Helper_Order::create_order();
+
+ add_filter( 'wcpay_is_woopay_store_api_request', '__return_true' );
+
+ $fraud_prevention_service_mock = $this->get_fraud_prevention_service_mock();
+
+ $fraud_prevention_service_mock
+ ->expects( $this->never() )
+ ->method( 'is_enabled' );
+
+ $this->mock_rate_limiter
+ ->expects( $this->once() )
+ ->method( 'is_limited' )
+ ->willReturn( false );
+
+ $mock_wcpay_gateway = $this->get_partial_mock_for_gateway( [ 'prepare_payment_information', 'process_payment_for_order' ] );
+ $mock_wcpay_gateway
+ ->expects( $this->once() )
+ ->method( 'prepare_payment_information' );
+ $mock_wcpay_gateway
+ ->expects( $this->once() )
+ ->method( 'process_payment_for_order' );
+
+ $mock_wcpay_gateway->process_payment( $order->get_id() );
+
+ remove_filter( 'wcpay_is_woopay_store_api_request', '__return_true' );
+ }
+
public function test_get_upe_enabled_payment_method_statuses_with_empty_cache() {
$this->mock_wcpay_account
->expects( $this->any() )
diff --git a/tests/unit/test-class-wc-payments-account.php b/tests/unit/test-class-wc-payments-account.php
index a872511ba2d..fac43dacb2c 100644
--- a/tests/unit/test-class-wc-payments-account.php
+++ b/tests/unit/test-class-wc-payments-account.php
@@ -96,6 +96,7 @@ public function test_filters_registered_properly() {
$this->assertNotFalse( has_action( 'admin_init', [ $this->wcpay_account, 'maybe_redirect_to_server_link' ] ), 'maybe_redirect_to_server_link action does not exist.' );
$this->assertNotFalse( has_action( 'admin_init', [ $this->wcpay_account, 'maybe_redirect_settings_to_connect_or_overview' ] ), 'maybe_redirect_settings_to_connect_or_overview action does not exist.' );
$this->assertNotFalse( has_action( 'admin_init', [ $this->wcpay_account, 'maybe_redirect_onboarding_flow_to_overview' ] ), 'maybe_redirect_onboarding_flow_to_overview action does not exist.' );
+ $this->assertNotFalse( has_action( 'admin_init', [ $this->wcpay_account, 'maybe_redirect_onboarding_flow_to_connect' ] ), 'maybe_redirect_onboarding_flow_to_connect action does not exist.' );
$this->assertNotFalse( has_action( 'admin_init', [ $this->wcpay_account, 'maybe_activate_woopay' ] ), 'maybe_activate_woopay action does not exist.' );
$this->assertNotFalse( has_action( 'woocommerce_payments_account_refreshed', [ $this->wcpay_account, 'handle_instant_deposits_inbox_note' ] ), 'handle_instant_deposits_inbox_note action does not exist.' );
$this->assertNotFalse( has_action( 'woocommerce_payments_account_refreshed', [ $this->wcpay_account, 'handle_loan_approved_inbox_note' ] ), 'handle_loan_approved_inbox_note action does not exist.' );
@@ -433,6 +434,93 @@ public function data_maybe_redirect_onboarding_flow_to_overview() {
];
}
+ /**
+ * @dataProvider data_maybe_redirect_onboarding_flow_to_connect
+ */
+ public function test_maybe_redirect_onboarding_flow_to_connect( $expected_times_redirect_called, $is_server_connected, $get_params ) {
+ wp_set_current_user( 1 );
+ $_GET = $get_params;
+
+ $this->mock_api_client = $this->getMockBuilder( 'WC_Payments_API_Client' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->mock_api_client
+ ->method( 'is_server_connected' )
+ ->willReturn( $is_server_connected );
+
+ // Mock WC_Payments_Account without redirect_to_onboarding_welcome_page to prevent headers already sent error.
+ $this->wcpay_account = $this->getMockBuilder( WC_Payments_Account::class )
+ ->setConstructorArgs( [ $this->mock_api_client, $this->mock_database_cache, $this->mock_action_scheduler_service, $this->mock_session_service ] )
+ ->onlyMethods( [ 'redirect_to_onboarding_welcome_page' ] )
+ ->getMock();
+
+ $this->wcpay_account
+ ->expects( $this->exactly( $expected_times_redirect_called ) )
+ ->method( 'redirect_to_onboarding_welcome_page' );
+
+ $this->wcpay_account->maybe_redirect_onboarding_flow_to_connect();
+ }
+
+ /**
+ * Data provider for test_maybe_redirect_onboarding_flow_to_connect
+ */
+ public function data_maybe_redirect_onboarding_flow_to_connect() {
+ return [
+ 'no_get_params' => [
+ 0,
+ false,
+ [],
+ ],
+ 'empty_page_param' => [
+ 0,
+ false,
+ [
+ 'path' => '/payments/onboarding',
+ ],
+ ],
+ 'incorrect_page_param' => [
+ 0,
+ false,
+ [
+ 'page' => 'wc-settings',
+ 'path' => '/payments/onboarding',
+ ],
+ ],
+ 'empty_path_param' => [
+ 0,
+ false,
+ [
+ 'page' => 'wc-admin',
+ ],
+ ],
+ 'incorrect_path_param' => [
+ 0,
+ false,
+ [
+ 'page' => 'wc-admin',
+ 'path' => '/payments/does-not-exist',
+ ],
+ ],
+ 'server_connected' => [
+ 0,
+ true,
+ [
+ 'page' => 'wc-admin',
+ 'path' => '/payments/onboarding',
+ ],
+ ],
+ 'happy_path' => [
+ 1,
+ false,
+ [
+ 'page' => 'wc-admin',
+ 'path' => '/payments/onboarding',
+ ],
+ ],
+ ];
+ }
+
/**
* @dataProvider data_maybe_redirect_settings_to_connect_or_overview
*/
diff --git a/tests/unit/test-class-wc-payments-checkout.php b/tests/unit/test-class-wc-payments-checkout.php
index d6273a1fcd2..72a7688187d 100644
--- a/tests/unit/test-class-wc-payments-checkout.php
+++ b/tests/unit/test-class-wc-payments-checkout.php
@@ -103,6 +103,9 @@ public function set_up() {
->disableOriginalConstructor()
->getMock();
$this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class );
+ $this->mock_wcpay_account
+ ->method( 'get_account_country' )
+ ->willReturn( 'US' );
$this->mock_customer_service = $this->createMock( WC_Payments_Customer_Service::class );
$this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class );
diff --git a/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php b/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php
index 899e530aa67..42acd644a62 100644
--- a/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php
+++ b/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php
@@ -95,12 +95,27 @@ public function set_up() {
->setMethods( [ 'is_country_available' ] )
->getMock();
+ $this->mock_express_checkout_helper = $this->getMockBuilder( WC_Payments_Express_Checkout_Button_Helper::class )
+ ->setConstructorArgs(
+ [
+ $this->mock_wcpay_gateway,
+ $this->mock_wcpay_account,
+ ]
+ )
+ ->setMethods(
+ [
+ 'is_checkout',
+ ]
+ )
+ ->getMock();
+
$this->mock_woopay_button_handler = $this->getMockBuilder( WC_Payments_WooPay_Button_Handler::class )
->setConstructorArgs(
[
$this->mock_wcpay_account,
$this->mock_wcpay_gateway,
$this->mock_woopay_utilities,
+ $this->mock_express_checkout_helper,
]
)
->setMethods(
@@ -111,14 +126,12 @@ public function set_up() {
)
->getMock();
- $this->express_checkout_helper = new WC_Payments_Express_Checkout_Button_Helper( $this->mock_wcpay_account );
-
$this->mock_payment_request_button_handler = $this->getMockBuilder( WC_Payments_Payment_Request_Button_Handler::class )
->setConstructorArgs(
[
$this->mock_wcpay_account,
$this->mock_wcpay_gateway,
- $this->express_checkout_helper,
+ $this->mock_express_checkout_helper,
]
)
->setMethods(
@@ -129,7 +142,7 @@ public function set_up() {
)
->getMock();
- $this->express_checkout_button_display_handler = new WC_Payments_Express_Checkout_Button_Display_Handler( $this->mock_wcpay_gateway, $this->mock_payment_request_button_handler, $this->mock_woopay_button_handler, $this->express_checkout_helper );
+ $this->express_checkout_button_display_handler = new WC_Payments_Express_Checkout_Button_Display_Handler( $this->mock_wcpay_gateway, $this->mock_payment_request_button_handler, $this->mock_woopay_button_handler, $this->mock_express_checkout_helper );
add_filter(
'woocommerce_available_payment_gateways',
@@ -176,7 +189,7 @@ public function test_display_express_checkout_buttons_all_enabled() {
->method( 'should_show_payment_request_button' )
->willReturn( true );
- $this->mock_payment_request_button_handler
+ $this->mock_express_checkout_helper
->method( 'is_checkout' )
->willReturn( false );
@@ -198,7 +211,7 @@ public function test_display_express_checkout_buttons_all_disabled() {
->method( 'should_show_payment_request_button' )
->willReturn( false );
- $this->mock_payment_request_button_handler
+ $this->mock_express_checkout_helper
->method( 'is_checkout' )
->willReturn( false );
@@ -218,7 +231,7 @@ public function test_display_express_checkout_buttons_only_woopay() {
->method( 'should_show_payment_request_button' )
->willReturn( false );
- $this->mock_payment_request_button_handler
+ $this->mock_express_checkout_helper
->method( 'is_checkout' )
->willReturn( false );
@@ -239,7 +252,7 @@ public function test_display_express_checkout_buttons_only_payment_request() {
->method( 'should_show_payment_request_button' )
->willReturn( true );
- $this->mock_payment_request_button_handler
+ $this->mock_express_checkout_helper
->method( 'is_checkout' )
->willReturn( true );
diff --git a/tests/unit/test-class-wc-payments-express-checkout-button-helper.php b/tests/unit/test-class-wc-payments-express-checkout-button-helper.php
new file mode 100644
index 00000000000..cef516aad5f
--- /dev/null
+++ b/tests/unit/test-class-wc-payments-express-checkout-button-helper.php
@@ -0,0 +1,152 @@
+mock_wcpay_account = $this->createMock( WC_Payments_Account::class );
+ $this->mock_wcpay_gateway = $this->make_wcpay_gateway();
+
+ $this->mock_express_checkout_helper = new WC_Payments_Express_Checkout_Button_Helper( $this->mock_wcpay_gateway, $this->mock_wcpay_account );
+ }
+
+ public function tear_down() {
+ parent::tear_down();
+ remove_filter( 'wc_tax_enabled', '__return_true' );
+ remove_filter( 'wc_tax_enabled', '__return_false' );
+ remove_filter( 'pre_option_woocommerce_tax_display_cart', [ $this, '__return_excl' ] );
+ remove_filter( 'pre_option_woocommerce_tax_display_cart', [ $this, '__return_incl' ] );
+ }
+
+ public function __return_excl() {
+ return 'excl';
+ }
+
+ public function __return_incl() {
+ return 'incl';
+ }
+
+ public function __return_base() {
+ return 'base';
+ }
+
+ /**
+ * @return WC_Payment_Gateway_WCPay
+ */
+ private function make_wcpay_gateway() {
+ $mock_api_client = $this->createMock( WC_Payments_API_Client::class );
+ $mock_customer_service = $this->createMock( WC_Payments_Customer_Service::class );
+ $mock_token_service = $this->createMock( WC_Payments_Token_Service::class );
+ $mock_action_scheduler_service = $this->createMock( WC_Payments_Action_Scheduler_Service::class );
+ $mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class );
+ $mock_order_service = $this->createMock( WC_Payments_Order_Service::class );
+ $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+ $mock_payment_method = $this->createMock( CC_Payment_Method::class );
+
+ return new WC_Payment_Gateway_WCPay(
+ $mock_api_client,
+ $this->mock_wcpay_account,
+ $mock_customer_service,
+ $mock_token_service,
+ $mock_action_scheduler_service,
+ $mock_payment_method,
+ [ 'card' => $mock_payment_method ],
+ $mock_rate_limiter,
+ $mock_order_service,
+ $mock_dpps,
+ $this->createMock( WC_Payments_Localization_Service::class ),
+ $this->createMock( WC_Payments_Fraud_Service::class )
+ );
+ }
+
+ public function test_common_get_button_settings() {
+ $this->assertEquals(
+ [
+ 'type' => 'buy',
+ 'theme' => 'dark',
+ 'height' => '48',
+ ],
+ $this->mock_express_checkout_helper->get_common_button_settings()
+ );
+ }
+
+ public function test_cart_prices_include_tax_with_tax_disabled() {
+ add_filter( 'wc_tax_enabled', '__return_false' );
+ $this->assertTrue( $this->mock_express_checkout_helper->cart_prices_include_tax() );
+ }
+
+ public function test_cart_prices_include_tax_with_tax_enabled_and_display_incl() {
+ add_filter( 'wc_tax_enabled', '__return_true' ); // reset in tear_down.
+ add_filter( 'pre_option_woocommerce_tax_display_cart', [ $this, '__return_incl' ] ); // reset in tear_down.
+
+ $this->assertTrue( $this->mock_express_checkout_helper->cart_prices_include_tax() );
+ }
+
+ public function test_cart_prices_include_tax_with_tax_enabled_and_display_excl() {
+ add_filter( 'wc_tax_enabled', '__return_true' ); // reset in tear_down.
+ add_filter( 'pre_option_woocommerce_tax_display_cart', [ $this, '__return_excl' ] ); // reset in tear_down.
+
+ $this->assertFalse( $this->mock_express_checkout_helper->cart_prices_include_tax() );
+ }
+
+ public function test_get_total_label() {
+ $this->mock_wcpay_account->method( 'get_statement_descriptor' )
+ ->willReturn( 'Google Pay' );
+
+ $result = $this->mock_express_checkout_helper->get_total_label();
+
+ $this->assertEquals( 'Google Pay (via WooCommerce)', $result );
+ }
+
+ public function test_get_total_label_with_filter() {
+ $this->mock_wcpay_account->method( 'get_statement_descriptor' )
+ ->willReturn( 'Google Pay' );
+
+ add_filter(
+ 'wcpay_payment_request_total_label_suffix',
+ function() {
+ return ' (via WooPayments)';
+ }
+ );
+
+ $result = $this->mock_express_checkout_helper->get_total_label();
+
+ $this->assertEquals( 'Google Pay (via WooPayments)', $result );
+ }
+}
diff --git a/tests/unit/test-class-wc-payments-onboarding-service.php b/tests/unit/test-class-wc-payments-onboarding-service.php
index 982a363cb92..4cdc5596842 100644
--- a/tests/unit/test-class-wc-payments-onboarding-service.php
+++ b/tests/unit/test-class-wc-payments-onboarding-service.php
@@ -239,4 +239,36 @@ public function test_set_onboarding_flow_state() {
delete_option( WC_Payments_Onboarding_Service::ONBOARDING_FLOW_STATE_OPTION );
}
+
+ /**
+ * @dataProvider data_get_source
+ */
+ public function test_get_source( $expected, $referer, $get_params ) {
+ $this->assertEquals( $expected, WC_Payments_Onboarding_Service::get_source( $referer, $get_params ) );
+ }
+
+ public function data_get_source() {
+ return [
+ [ 'wcadmin-payment-task', 'any', [ 'wcpay-connect' => 'WCADMIN_PAYMENT_TASK' ] ],
+ [ 'wcadmin-settings-page', '/wp-admin/admin.php?page=wc-settings&tab=checkout', [ 'wcpay-connect' => '1' ] ],
+ [ 'wcadmin-incentive-page', '/wp-admin/admin.php?page=wc-admin&path=%2Fwc-pay-welcome-page', [ 'wcpay-connect' => '1' ] ],
+ [ 'wcpay-connect-page', '/wp-admin/admin.php?page=wc-admin&path=%2Fpayments%2Fconnect', [ 'wcpay-connect' => '1' ] ],
+ [
+ 'wcpay-setup-live-payments',
+ 'any',
+ [
+ 'wcpay-connect' => '1',
+ 'wcpay-disable-onboarding-test-mode' => '1',
+ ],
+ ],
+ [
+ 'wcpay-reset-account',
+ 'any',
+ [
+ 'wcpay-connect' => '1',
+ 'wcpay-reset-account' => '1',
+ ],
+ ],
+ ];
+ }
}
diff --git a/tests/unit/test-class-wc-payments-payment-request-button-handler.php b/tests/unit/test-class-wc-payments-payment-request-button-handler.php
index c774cf5573f..10c83c22260 100644
--- a/tests/unit/test-class-wc-payments-payment-request-button-handler.php
+++ b/tests/unit/test-class-wc-payments-payment-request-button-handler.php
@@ -109,7 +109,15 @@ public function set_up() {
$this->mock_wcpay_gateway = $this->make_wcpay_gateway();
- $this->express_checkout_helper = new WC_Payments_Express_Checkout_Button_Helper( $this->mock_wcpay_account );
+ $this->express_checkout_helper = $this->getMockBuilder( WC_Payments_Express_Checkout_Button_Helper::class )
+ ->setMethods(
+ [
+ 'is_product',
+ 'get_product',
+ ]
+ )
+ ->setConstructorArgs( [ $this->mock_wcpay_gateway, $this->mock_wcpay_account ] )
+ ->getMock();
$this->pr = new WC_Payments_Payment_Request_Button_Handler( $this->mock_wcpay_account, $this->mock_wcpay_gateway, $this->express_checkout_helper );
@@ -307,22 +315,6 @@ public function test_get_shipping_options_keeps_chosen_option() {
$this->assertEquals( $expected_shipping_options, $data['shipping_options'], 'Shipping options mismatch' );
}
- public function test_get_button_settings() {
- $this->mock_wcpay_gateway = $this->make_wcpay_gateway();
- $this->pr = new WC_Payments_Payment_Request_Button_Handler( $this->mock_wcpay_account, $this->mock_wcpay_gateway, $this->express_checkout_helper );
-
- $this->assertEquals(
- [
- 'type' => 'buy',
- 'theme' => 'dark',
- 'height' => '48',
- 'locale' => 'en',
- 'branded_type' => 'long',
- ],
- $this->pr->get_button_settings()
- );
- }
-
public function test_multiple_packages_in_cart_not_allowed() {
// Add fake packages to the cart.
add_filter(
@@ -522,17 +514,19 @@ public function test_get_product_data_returns_the_same_as_build_display_items_wi
WC()->cart->calculate_totals();
$build_display_items_result = $this->express_checkout_helper->build_display_items( true );
+ $this->express_checkout_helper
+ ->method( 'is_product' )
+ ->willReturn( true );
+
+ $this->express_checkout_helper
+ ->method( 'get_product' )
+ ->willReturn( $this->simple_product );
+
$mock_pr = $this->getMockBuilder( WC_Payments_Payment_Request_Button_Handler::class )
->setConstructorArgs( [ $this->mock_wcpay_account, $this->mock_wcpay_gateway, $this->express_checkout_helper ] )
- ->setMethods( [ 'is_product', 'get_product' ] )
->getMock();
- $mock_pr->method( 'is_product' )
- ->willReturn( true );
- $mock_pr->method( 'get_product' )
- ->willReturn( $this->simple_product );
-
- $get_product_data_result = $mock_pr->get_product_data();
+ $get_product_data_result = $this->pr->get_product_data();
foreach ( $get_product_data_result['displayItems'] as $key => $display_item ) {
if ( isset( $display_item['pending'] ) ) {
@@ -567,4 +561,21 @@ public function test_filter_cart_needs_shipping_address_returns_true() {
$this->assertTrue( $this->pr->filter_cart_needs_shipping_address( true ) );
}
+
+ public function test_get_button_settings() {
+ $this->express_checkout_helper
+ ->method( 'is_product' )
+ ->willReturn( true );
+
+ $this->assertEquals(
+ [
+ 'type' => 'buy',
+ 'theme' => 'dark',
+ 'height' => '48',
+ 'locale' => 'en',
+ 'branded_type' => 'long',
+ ],
+ $this->pr->get_button_settings()
+ );
+ }
}
diff --git a/tests/unit/test-class-wc-payments-woopay-button-handler.php b/tests/unit/test-class-wc-payments-woopay-button-handler.php
index 161c5796101..6bb3f488e89 100644
--- a/tests/unit/test-class-wc-payments-woopay-button-handler.php
+++ b/tests/unit/test-class-wc-payments-woopay-button-handler.php
@@ -49,6 +49,13 @@ class WC_Payments_WooPay_Button_Handler_Test extends WCPAY_UnitTestCase {
*/
private $mock_woopay_utilities;
+ /**
+ * Express Checkout Helper instance.
+ *
+ * @var WC_Payments_Express_Checkout_Button_Helper
+ */
+ private $mock_express_checkout_helper;
+
/**
* Sets up things all tests need.
*/
@@ -79,17 +86,15 @@ public function set_up() {
->setMethods( [ 'is_country_available' ] )
->getMock();
- $this->mock_pr = $this->getMockBuilder( WC_Payments_WooPay_Button_Handler::class )
+ $this->mock_express_checkout_helper = $this->getMockBuilder( WC_Payments_Express_Checkout_Button_Helper::class )
->setConstructorArgs(
[
- $this->mock_wcpay_account,
$this->mock_wcpay_gateway,
- $this->mock_woopay_utilities,
+ $this->mock_wcpay_account,
]
)
->setMethods(
[
- 'is_woopay_enabled',
'is_cart',
'is_checkout',
'is_product',
@@ -98,6 +103,22 @@ public function set_up() {
)
->getMock();
+ $this->mock_pr = $this->getMockBuilder( WC_Payments_WooPay_Button_Handler::class )
+ ->setConstructorArgs(
+ [
+ $this->mock_wcpay_account,
+ $this->mock_wcpay_gateway,
+ $this->mock_woopay_utilities,
+ $this->mock_express_checkout_helper,
+ ]
+ )
+ ->setMethods(
+ [
+ 'is_woopay_enabled',
+ ]
+ )
+ ->getMock();
+
$simple_product = WC_Helper_Product::create_simple_product();
WC()->session->init();
@@ -156,11 +177,11 @@ public function test_should_show_woopay_button_all_good_at_cart() {
->method( 'is_woopay_enabled' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->method( 'is_cart' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->expects( $this->once() )
->method( 'is_available_at' )
->with( 'cart' )
@@ -179,11 +200,11 @@ public function test_should_show_woopay_button_not_available_at_cart() {
->method( 'is_country_available' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->method( 'is_cart' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->expects( $this->once() )
->method( 'is_available_at' )
->with( 'cart' )
@@ -204,11 +225,11 @@ public function test_should_show_woopay_button_all_good_at_checkout() {
->method( 'is_country_available' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->method( 'is_checkout' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->expects( $this->once() )
->method( 'is_available_at' )
->with( 'checkout' )
@@ -229,11 +250,11 @@ public function test_should_show_woopay_button_unsupported_product_at_checkout()
->method( 'is_country_available' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->method( 'is_checkout' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->expects( $this->once() )
->method( 'is_available_at' )
->with( 'checkout' )
@@ -254,11 +275,11 @@ public function test_should_show_woopay_button_all_good_at_product() {
->method( 'is_country_available' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->method( 'is_product' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->expects( $this->once() )
->method( 'is_available_at' )
->with( 'product' )
@@ -279,11 +300,11 @@ public function test_should_show_woopay_button_unsupported_product_at_product()
->method( 'is_country_available' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->method( 'is_product' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->expects( $this->once() )
->method( 'is_available_at' )
->with( 'product' )
@@ -304,11 +325,11 @@ public function test_should_show_woopay_button_not_available_at_product() {
->method( 'is_country_available' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->method( 'is_product' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->expects( $this->once() )
->method( 'is_available_at' )
->with( 'product' )
@@ -322,19 +343,19 @@ public function test_should_show_woopay_button_page_not_supported() {
->expects( $this->never() )
->method( 'is_country_available' );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->method( 'is_product' )
->willReturn( false );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->method( 'is_cart' )
->willReturn( false );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->method( 'is_checkout' )
->willReturn( false );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->expects( $this->never() )
->method( 'is_available_at' );
@@ -351,19 +372,19 @@ public function test_should_show_woopay_button_country_not_supported() {
->method( 'is_country_available' )
->willReturn( false );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->method( 'is_product' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->method( 'is_cart' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->method( 'is_checkout' )
->willReturn( true );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->expects( $this->never() )
->method( 'is_available_at' );
@@ -377,7 +398,7 @@ public function test_should_show_woopay_button_unavailable_wcpay() {
->expects( $this->never() )
->method( 'is_country_available' );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->expects( $this->never() )
->method( 'is_product' );
@@ -393,15 +414,32 @@ public function test_should_show_woopay_button_woopay_not_enabled() {
->expects( $this->never() )
->method( 'is_country_available' );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->expects( $this->never() )
->method( 'is_cart' );
- $this->mock_pr
+ $this->mock_express_checkout_helper
->expects( $this->never() )
->method( 'is_available_at' )
->with( 'cart' );
$this->assertFalse( $this->mock_pr->should_show_woopay_button() );
}
+
+ public function test_get_button_settings() {
+ $this->mock_express_checkout_helper
+ ->method( 'is_product' )
+ ->willReturn( true );
+
+ $this->assertEquals(
+ [
+ 'type' => 'buy',
+ 'theme' => 'dark',
+ 'height' => '48',
+ 'size' => 'medium',
+ 'context' => 'product',
+ ],
+ $this->mock_pr->get_button_settings()
+ );
+ }
}
diff --git a/tests/unit/test-class-woopay-tracker.php b/tests/unit/test-class-woopay-tracker.php
index 94df55b5e11..ee88d46ce12 100644
--- a/tests/unit/test-class-woopay-tracker.php
+++ b/tests/unit/test-class-woopay-tracker.php
@@ -61,7 +61,7 @@ public function test_tracks_obeys_woopay_flag() {
$this->set_account_connected( true );
WC_Payments::set_account_service( $this->mock_account );
$this->set_is_woopay_eligible( false );
- $this->assertFalse( $this->tracker->should_enable_tracking( null, null ) );
+ $this->assertFalse( $this->tracker->should_enable_tracking( null ) );
}
public function test_does_not_track_admin_pages() {
@@ -70,7 +70,7 @@ public function test_does_not_track_admin_pages() {
$this->set_account_connected( true );
WC_Payments::set_account_service( $this->mock_account );
$this->set_is_admin( true );
- $this->assertFalse( $this->tracker->should_enable_tracking( null, null ) );
+ $this->assertFalse( $this->tracker->should_enable_tracking( null ) );
}
public function test_does_track_non_admins() {
@@ -87,7 +87,7 @@ public function test_does_track_non_admins() {
foreach ( $all_roles as $role ) {
wp_get_current_user()->set_role( $role );
- $this->assertTrue( $this->tracker->should_enable_tracking( null, null ) );
+ $this->assertTrue( $this->tracker->should_enable_tracking( null ) );
}
}
@@ -96,9 +96,8 @@ public function test_does_not_track_when_account_not_connected() {
$this->set_is_woopay_eligible( true );
$this->set_account_connected( false );
WC_Payments::set_account_service( $this->mock_account );
- $is_admin_event = false;
- $track_on_all_stores = true;
- $this->assertFalse( $this->tracker->should_enable_tracking( $is_admin_event, $track_on_all_stores ) );
+ $is_admin_event = false;
+ $this->assertFalse( $this->tracker->should_enable_tracking( $is_admin_event ) );
}
/**
diff --git a/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php b/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php
index b9b8e5b79ee..6ac7b680573 100644
--- a/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php
+++ b/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php
@@ -298,6 +298,7 @@ function ( $data ): bool {
'create_live_account' => true,
'progressive' => false,
'collect_payout_requirements' => false,
+ 'compatibility_data' => $this->get_mock_compatibility_data(),
]
),
true,
@@ -1288,4 +1289,29 @@ private function validate_default_remote_request_params( $data, $url, $method )
$this->assertSame( 70, $data['connect_timeout'] );
}
+
+ /**
+ * Returns the mock compatibility data.
+ *
+ * @param array $args If any values need to be overridden, the values can be added here.
+ *
+ * @return array
+ */
+ private function get_mock_compatibility_data( array $args = [] ): array {
+ return array_merge(
+ [
+ 'woopayments_version' => WCPAY_VERSION_NUMBER,
+ 'woocommerce_version' => WC_VERSION,
+ 'blog_theme' => 'default',
+ 'active_plugins' => [],
+ 'post_types_count' => [
+ 'post' => 0,
+ 'page' => 0,
+ 'attachment' => 0,
+ 'product' => 0,
+ ],
+ ],
+ $args
+ );
+ }
}
diff --git a/tests/unit/woopay/test-class-woopay-order-status-sync.php b/tests/unit/woopay/test-class-woopay-order-status-sync.php
index 987680d4bc4..c99a39762b3 100644
--- a/tests/unit/woopay/test-class-woopay-order-status-sync.php
+++ b/tests/unit/woopay/test-class-woopay-order-status-sync.php
@@ -20,8 +20,9 @@ class WooPay_Order_Status_Sync_Test extends WP_UnitTestCase {
public function set_up() {
parent::set_up();
+ $this->account_mock = $this->createMock( WC_Payments_Account::class );
$this->api_client_mock = $this->createMock( WC_Payments_API_Client::class );
- $this->webhook_sync_mock = new WCPay\WooPay\WooPay_Order_Status_Sync( $this->api_client_mock );
+ $this->webhook_sync_mock = new WCPay\WooPay\WooPay_Order_Status_Sync( $this->api_client_mock, $this->account_mock );
// Mock the main class's cache service.
$this->_cache = WC_Payments::get_database_cache();
@@ -45,6 +46,7 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
/**
* Tests that WooPay-specific webhooks are modified as expected.
+ * @group webhook
*/
public function test_woopay_specific_webhook_payload_is_updated() {
wp_set_current_user( self::$admin_user->ID );
@@ -119,6 +121,20 @@ public function test_webhook_is_created() {
$this->assertNotEmpty( WooPay_Order_Status_Sync::get_webhook() );
}
+ /**
+ * Tests that the webhook is not created for rejected WCPay accounts.
+ */
+ public function test_webhook_is_created_for_rejected() {
+ wp_set_current_user( self::$admin_user->ID );
+ $this->account_mock->method( 'is_account_rejected' )->willReturn( true );
+
+ $this->assertEmpty( WooPay_Order_Status_Sync::get_webhook() );
+
+ $this->webhook_sync_mock->maybe_create_woopay_order_webhook();
+
+ $this->assertEmpty( WooPay_Order_Status_Sync::get_webhook() );
+ }
+
/**
* Tests that the webhook is deleted succesfuly.
*/
diff --git a/webpack/shared.js b/webpack/shared.js
index 02bff20e196..c35048edb44 100644
--- a/webpack/shared.js
+++ b/webpack/shared.js
@@ -15,6 +15,8 @@ module.exports = {
woopay: './client/checkout/woopay/index.js',
'woopay-express-button':
'./client/checkout/woopay/express-button/index.js',
+ 'woopay-direct-checkout':
+ './client/checkout/woopay/direct-checkout/index.js',
checkout: './client/checkout/classic/event-handlers.js',
'payment-request': './client/payment-request/index.js',
'subscription-edit-page': './client/subscription-edit-page.js',
diff --git a/woocommerce-payments.php b/woocommerce-payments.php
index d1db912b2e6..874d1b3f450 100644
--- a/woocommerce-payments.php
+++ b/woocommerce-payments.php
@@ -5,14 +5,13 @@
* Description: Accept payments via credit card. Manage transactions within WordPress.
* Author: Automattic
* Author URI: https://woo.com/
- * Woo: 5278104:bf3cf30871604e15eec560c962593c1f
* Text Domain: woocommerce-payments
* Domain Path: /languages
* WC requires at least: 7.6
- * WC tested up to: 8.4.0
+ * WC tested up to: 8.5.2
* Requires at least: 6.0
* Requires PHP: 7.3
- * Version: 7.1.0
+ * Version: 7.2.0
*
* @package WooCommerce\Payments
*/
@@ -66,8 +65,6 @@ function wcpay_deactivated() {
return;
}
-// Subscribe to automated translations.
-add_filter( 'woocommerce_translations_updates_for_woocommerce-payments', '__return_true' );
/**
* Initialize the Jetpack functionalities: connection, identity crisis, etc.