From 06ccfd5a435f3f057204d9e01db3ea427825f543 Mon Sep 17 00:00:00 2001 From: Timur Karimov Date: Fri, 19 Jan 2024 08:48:12 +0100 Subject: [PATCH] Merge split UPE tests with main gateway tests (#7954) Co-authored-by: Timur Karimov --- .github/workflows/e2e-pull-request.yml | 7 +- .github/workflows/e2e-tests-atomic.yml | 6 +- changelog/merge-upe-non-upe-tests | 4 + tests/e2e/config/jest.config.js | 2 - .../shopper-upe-enabled-all-flows.spec.js | 117 -- .../shopper-upe-enabled-all-flows.spec.js | 112 -- .../shopper/shopper-bnpls-checkout.spec.js | 0 ...heckout-purchase-with-upe-methods.spec.js} | 79 +- ...er-checkout-save-card-and-purchase.spec.js | 11 + ...r-myaccount-save-card-and-checkout.spec.js | 3 + tests/e2e/utils/payments.js | 21 +- .../test-class-upe-payment-gateway.php | 1026 ------------- .../test-class-upe-split-payment-gateway.php | 1290 ---------------- .../test-class-wc-payment-gateway-wcpay.php | 1302 +++++++++++++++-- 14 files changed, 1211 insertions(+), 2769 deletions(-) create mode 100644 changelog/merge-upe-non-upe-tests delete mode 100644 tests/e2e/specs/upe-split/shopper/shopper-upe-enabled-all-flows.spec.js delete mode 100644 tests/e2e/specs/upe/shopper/shopper-upe-enabled-all-flows.spec.js rename tests/e2e/specs/{upe-split => wcpay}/shopper/shopper-bnpls-checkout.spec.js (100%) rename tests/e2e/specs/{upe-split/shopper/shopper-deferred-intent-creation-upe-enabled.spec.js => wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js} (62%) delete mode 100644 tests/unit/payment-methods/test-class-upe-payment-gateway.php delete mode 100644 tests/unit/payment-methods/test-class-upe-split-payment-gateway.php diff --git a/.github/workflows/e2e-pull-request.yml b/.github/workflows/e2e-pull-request.yml index ab0cd702a86..020ce16c0bd 100644 --- a/.github/workflows/e2e-pull-request.yml +++ b/.github/workflows/e2e-pull-request.yml @@ -47,13 +47,8 @@ jobs: strategy: fail-fast: false matrix: - test_groups: [ 'wcpay', 'subscriptions', 'upe', 'upeSplit' ] # [TODO] Unskip blocks tests after investigating constant failures. + test_groups: [ 'wcpay', 'subscriptions' ] # [TODO] Unskip blocks tests after investigating constant failures. test_branches: [ 'merchant', 'shopper' ] - exclude: - - test_groups: 'upe' - test_branches: 'merchant' - - test_groups: 'upeSplit' - test_branches: 'merchant' name: WC - latest | ${{ matrix.test_groups }} - ${{ matrix.test_branches }} diff --git a/.github/workflows/e2e-tests-atomic.yml b/.github/workflows/e2e-tests-atomic.yml index bf31de432f0..55cbe67e04a 100644 --- a/.github/workflows/e2e-tests-atomic.yml +++ b/.github/workflows/e2e-tests-atomic.yml @@ -26,16 +26,12 @@ jobs: fail-fast: false max-parallel: 1 matrix: - test_groups: [ 'wcpay', 'subscriptions', 'upe', 'upeSplit' ] + test_groups: [ 'wcpay', 'subscriptions' ] test_branches: [ 'merchant', 'shopper' ] exclude: - test_groups: 'subscriptions' - test_groups: 'wcpay' test_branches: 'merchant' - - test_groups: 'upe' - test_branches: 'merchant' - - test_groups: 'upeSplit' - test_branches: 'merchant' env: E2E_GROUP: ${{ matrix.test_groups }} diff --git a/changelog/merge-upe-non-upe-tests b/changelog/merge-upe-non-upe-tests new file mode 100644 index 00000000000..2e6ed78762f --- /dev/null +++ b/changelog/merge-upe-non-upe-tests @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +Merge UPE tests into the single and main gateway test file for unit and E2E tests. diff --git a/tests/e2e/config/jest.config.js b/tests/e2e/config/jest.config.js index 8e6c3a446f8..b150629cdf1 100644 --- a/tests/e2e/config/jest.config.js +++ b/tests/e2e/config/jest.config.js @@ -11,8 +11,6 @@ const e2ePaths = { wcpay: path.resolve( __dirname, '../specs/wcpay' ), subscriptions: path.resolve( __dirname, '../specs/subscriptions' ), blocks: path.resolve( __dirname, '../specs/blocks' ), - upe: path.resolve( __dirname, '../specs/upe' ), - upeSplit: path.resolve( __dirname, '../specs/upe-split' ), }; // Allow E2E tests to run specific tests - wcpay, subscriptions, blocks, all (default). diff --git a/tests/e2e/specs/upe-split/shopper/shopper-upe-enabled-all-flows.spec.js b/tests/e2e/specs/upe-split/shopper/shopper-upe-enabled-all-flows.spec.js deleted file mode 100644 index 78642474eb1..00000000000 --- a/tests/e2e/specs/upe-split/shopper/shopper-upe-enabled-all-flows.spec.js +++ /dev/null @@ -1,117 +0,0 @@ -/** - * External dependencies - */ -import config from 'config'; - -/** - * Internal dependencies - */ -import { merchantWCP, shopperWCP } from '../../../utils/flows'; -import { fillCardDetails, setupProductCheckout } from '../../../utils/payments'; -const { shopper, merchant, uiUnblocked } = require( '@woocommerce/e2e-utils' ); - -const MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS = 20000; -const UPE_METHOD_CHECKBOXES = [ - '#inspector-checkbox-control-3', // bancontact - '#inspector-checkbox-control-4', // eps - '#inspector-checkbox-control-5', // giropay - '#inspector-checkbox-control-6', // ideal - '#inspector-checkbox-control-7', // sofort -]; -const card = config.get( 'cards.basic' ); - -describe( 'Enabled Split UPE', () => { - beforeAll( async () => { - await merchant.login(); - await merchantWCP.enablePaymentMethod( UPE_METHOD_CHECKBOXES ); - await merchant.logout(); - await shopper.login(); - await shopperWCP.changeAccountCurrencyTo( 'EUR' ); - } ); - - afterAll( async () => { - await shopperWCP.changeAccountCurrencyTo( 'USD' ); - await shopperWCP.logout(); - await merchant.login(); - await merchantWCP.disablePaymentMethod( UPE_METHOD_CHECKBOXES ); - await merchant.logout(); - } ); - - describe( 'Shortcode checkout', () => { - it( 'should save the card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await shopperWCP.selectNewPaymentMethod(); - await fillCardDetails( page, card ); - await shopperWCP.toggleSavePaymentMethod(); - await shopper.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - - // validate that the payment method has been added to the customer. - await shopperWCP.goToPaymentMethods(); - await expect( page ).toMatch( card.label ); - await expect( page ).toMatch( - `${ card.expires.month }/${ card.expires.year }` - ); - } ); - - it( 'should process a payment with the saved card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await shopper.goToCheckout(); - await uiUnblocked(); - await shopperWCP.selectSavedPaymentMethod( - `${ card.label } (expires ${ card.expires.month }/${ card.expires.year })` - ); - await shopper.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - } ); - - it( 'should delete the card', async () => { - await shopperWCP.goToPaymentMethods(); - await shopperWCP.deleteSavedPaymentMethod( card.label ); - await expect( page ).toMatch( 'Payment method deleted' ); - } ); - } ); - - describe( 'My Account', () => { - let timeAdded; - it( 'should add the card as a new payment method', async () => { - await shopperWCP.goToPaymentMethods(); - await shopperWCP.addNewPaymentMethod( 'basic', card ); - - // Take note of the time when we added this card - timeAdded = Date.now(); - - // Verify that the card was added - await expect( page ).not.toMatch( - 'You cannot add a new payment method so soon after the previous one. Please wait for 20 seconds.' - ); - await expect( page ).toMatch( 'Payment method successfully added' ); - await expect( page ).toMatch( - `${ card.expires.month }/${ card.expires.year }` - ); - } ); - - it( 'should be able to delete the card', async () => { - await shopperWCP.deleteSavedPaymentMethod( card.label ); - await expect( page ).toMatch( 'Payment method deleted.' ); - } ); - - afterAll( async () => { - // Make sure that at least 20s had already elapsed since the last card was added. - // Otherwise, you will get the error message, - // "You cannot add a new payment method so soon after the previous one." - const timeTestFinished = Date.now(); - const elapsedWaitTime = timeTestFinished - timeAdded; - const remainingWaitTime = - MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS > elapsedWaitTime - ? MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS - elapsedWaitTime - : 0; - - await new Promise( ( r ) => setTimeout( r, remainingWaitTime ) ); - } ); - } ); -} ); diff --git a/tests/e2e/specs/upe/shopper/shopper-upe-enabled-all-flows.spec.js b/tests/e2e/specs/upe/shopper/shopper-upe-enabled-all-flows.spec.js deleted file mode 100644 index c5ba0caa81e..00000000000 --- a/tests/e2e/specs/upe/shopper/shopper-upe-enabled-all-flows.spec.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * External dependencies - */ -import config from 'config'; - -/** - * Internal dependencies - */ -import { merchantWCP, shopperWCP } from '../../../utils/flows'; -import { fillCardDetails, setupProductCheckout } from '../../../utils/payments'; -const { shopper, merchant } = require( '@woocommerce/e2e-utils' ); - -const MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS = 20000; - -const sepaPaymentMethod = '#inspector-checkbox-control-8'; -const card = config.get( 'cards.basic' ); - -describe( 'Enabled UPE', () => { - beforeAll( async () => { - await merchant.login(); - // enable SEPA - await merchantWCP.enablePaymentMethod( [ sepaPaymentMethod ] ); - await merchant.logout(); - await shopper.login(); - await shopperWCP.changeAccountCurrencyTo( 'EUR' ); - } ); - - afterAll( async () => { - await shopperWCP.changeAccountCurrencyTo( 'USD' ); - await shopperWCP.logout(); - await merchant.login(); - //disable SEPA - await merchantWCP.disablePaymentMethod( [ sepaPaymentMethod ] ); - await merchant.logout(); - } ); - - describe( 'Shortcode checkout', () => { - it( 'should save the card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await shopperWCP.selectNewPaymentMethod(); - await fillCardDetails( page, card ); - await shopperWCP.toggleSavePaymentMethod(); - await shopper.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - - // validate that the payment method has been added to the customer. - await shopperWCP.goToPaymentMethods(); - await expect( page ).toMatch( card.label ); - await expect( page ).toMatch( - `${ card.expires.month }/${ card.expires.year }` - ); - } ); - - it( 'should process a payment with the saved card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await shopperWCP.selectSavedPaymentMethod( - `${ card.label } (expires ${ card.expires.month }/${ card.expires.year })` - ); - await shopper.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - } ); - - it( 'should delete the card', async () => { - await shopperWCP.goToPaymentMethods(); - await shopperWCP.deleteSavedPaymentMethod( card.label ); - await expect( page ).toMatch( 'Payment method deleted' ); - } ); - } ); - - describe( 'My Account', () => { - let timeAdded; - it( 'should add the card as a new payment method', async () => { - await shopperWCP.goToPaymentMethods(); - await shopperWCP.addNewPaymentMethod( 'basic', card ); - - // Take note of the time when we added this card - timeAdded = Date.now(); - - // Verify that the card was added - await expect( page ).not.toMatch( - 'You cannot add a new payment method so soon after the previous one. Please wait for 20 seconds.' - ); - await expect( page ).toMatch( 'Payment method successfully added' ); - await expect( page ).toMatch( - `${ card.expires.month }/${ card.expires.year }` - ); - } ); - - it( 'should be able to delete the card', async () => { - await shopperWCP.deleteSavedPaymentMethod( card.label ); - await expect( page ).toMatch( 'Payment method deleted.' ); - } ); - - afterAll( async () => { - // Make sure that at least 20s had already elapsed since the last card was added. - // Otherwise, you will get the error message, - // "You cannot add a new payment method so soon after the previous one." - const timeTestFinished = Date.now(); - const elapsedWaitTime = timeTestFinished - timeAdded; - const remainingWaitTime = - MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS > elapsedWaitTime - ? MIN_WAIT_TIME_BETWEEN_PAYMENT_METHODS - elapsedWaitTime - : 0; - - await new Promise( ( r ) => setTimeout( r, remainingWaitTime ) ); - } ); - } ); -} ); diff --git a/tests/e2e/specs/upe-split/shopper/shopper-bnpls-checkout.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-bnpls-checkout.spec.js similarity index 100% rename from tests/e2e/specs/upe-split/shopper/shopper-bnpls-checkout.spec.js rename to tests/e2e/specs/wcpay/shopper/shopper-bnpls-checkout.spec.js diff --git a/tests/e2e/specs/upe-split/shopper/shopper-deferred-intent-creation-upe-enabled.spec.js b/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js similarity index 62% rename from tests/e2e/specs/upe-split/shopper/shopper-deferred-intent-creation-upe-enabled.spec.js rename to tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js index e1062f6d1ca..3f122226c13 100644 --- a/tests/e2e/specs/upe-split/shopper/shopper-deferred-intent-creation-upe-enabled.spec.js +++ b/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.js @@ -8,17 +8,15 @@ import config from 'config'; */ import { merchantWCP, shopperWCP } from '../../../utils/flows'; import { - confirmCardAuthentication, - fillCardDetails, setupProductCheckout, - selectGiropayOnCheckout, - completeGiropayPayment, + selectOnCheckout, + completeRedirectedPayment, } from '../../../utils/payments'; -import { uiUnblocked } from '@woocommerce/e2e-utils/build/page-utils'; const { shopper, merchant } = require( '@woocommerce/e2e-utils' ); const UPE_METHOD_CHECKBOXES = [ - '#inspector-checkbox-control-7', // giropay + "//label[contains(text(), 'Bancontact')]/preceding-sibling::span/input[@type='checkbox']", + "//label[contains(text(), 'giropay')]/preceding-sibling::span/input[@type='checkbox']", ]; const card = config.get( 'cards.basic' ); const card2 = config.get( 'cards.basic2' ); @@ -30,6 +28,7 @@ describe( 'Enabled UPE with deferred intent creation', () => { await merchantWCP.enablePaymentMethod( UPE_METHOD_CHECKBOXES ); await merchant.logout(); await shopper.login(); + await shopperWCP.changeAccountCurrencyTo( 'EUR' ); } ); afterAll( async () => { @@ -41,88 +40,30 @@ describe( 'Enabled UPE with deferred intent creation', () => { describe( 'Enabled UPE with deferred intent creation', () => { it( 'should successfully place order with Giropay', async () => { - await shopperWCP.goToShopWithCurrency( 'EUR' ); await setupProductCheckout( config.get( 'addresses.customer.billing' ) ); - await selectGiropayOnCheckout( page ); + await selectOnCheckout( 'giropay', page ); await shopper.placeOrder(); - await completeGiropayPayment( page, 'success' ); + await completeRedirectedPayment( page, 'success' ); await page.waitForNavigation( { waitUntil: 'networkidle0', } ); await expect( page ).toMatch( 'Order received' ); } ); - it( 'should successfully place order with the default card', async () => { + it( 'should successfully place order with Bancontact', async () => { await setupProductCheckout( config.get( 'addresses.customer.billing' ) ); - await fillCardDetails( page, card ); + await selectOnCheckout( 'bancontact', page ); await shopper.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - } ); - - it( 'should process a payment with authentication for the 3DS card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await fillCardDetails( page, config.get( 'cards.3ds' ) ); - await shopper.placeOrder(); - await confirmCardAuthentication( page, '3DS' ); + await completeRedirectedPayment( page, 'success' ); await page.waitForNavigation( { waitUntil: 'networkidle0', } ); await expect( page ).toMatch( 'Order received' ); } ); - - it( 'should successfully save the card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await fillCardDetails( page, card ); - await shopperWCP.toggleSavePaymentMethod(); - await shopper.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - - // validate that the payment method has been added to the customer. - await shopperWCP.goToPaymentMethods(); - await expect( page ).toMatch( card.label ); - await expect( page ).toMatch( - `${ card.expires.month }/${ card.expires.year }` - ); - } ); - - it( 'should process a payment with the saved card', async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - await shopper.goToCheckout(); - await uiUnblocked(); - await shopperWCP.selectSavedPaymentMethod( - `${ card.label } (expires ${ card.expires.month }/${ card.expires.year })` - ); - await shopper.placeOrder(); - await expect( page ).toMatch( 'Order received' ); - } ); - - it( 'should delete the card', async () => { - await shopperWCP.goToPaymentMethods(); - await shopperWCP.deleteSavedPaymentMethod( card.label ); - await expect( page ).toMatch( 'Payment method deleted' ); - } ); - - it( 'should not allow guest user to save the card', async () => { - await shopperWCP.logout(); - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - - await expect( page ).not.toMatchElement( - 'input#wc-woocommerce_payments-new-payment-method' - ); - await shopper.login(); - } ); } ); describe( 'My Account', () => { 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 df04f592763..341b52cf516 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 @@ -87,6 +87,17 @@ describe( 'Saved cards ', () => { await shopperWCP.deleteSavedPaymentMethod( card.label ); await expect( page ).toMatch( 'Payment method deleted' ); } ); + + it( 'should not allow guest user to save the card', async () => { + await shopperWCP.logout(); + await setupProductCheckout( + config.get( 'addresses.customer.billing' ) + ); + + await expect( page ).not.toMatchElement( + 'input#wc-woocommerce_payments-new-payment-method' + ); + } ); } ); } ); 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 9eaea6e86ac..8def9e54824 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 @@ -37,6 +37,9 @@ describe( 'Saved cards ', () => { await expect( page ).toMatch( 'Payment method successfully added' ); + await expect( page ).toMatch( + `${ card.expires.month }/${ card.expires.year }` + ); } ); it( 'should process a payment with the saved card', async () => { diff --git a/tests/e2e/utils/payments.js b/tests/e2e/utils/payments.js index 3c8084c0811..c98b70a7fa7 100644 --- a/tests/e2e/utils/payments.js +++ b/tests/e2e/utils/payments.js @@ -298,26 +298,31 @@ export async function setupCheckout( billingDetails ) { } /** - * Selects the Giropay payment method on the checkout page. + * Selects the payment method on the checkout page. * + * @param {*} paymentMethod The payment method to select. * @param {*} page The page reference object. */ -export async function selectGiropayOnCheckout( page ) { - await page.$( '#payment .payment_method_woocommerce_payments_giropay' ); - const giropayRadioLabel = await page.waitForSelector( - '#payment .payment_method_woocommerce_payments_giropay label' +export async function selectOnCheckout( paymentMethod, page ) { + await page.$( + '#payment .payment_method_woocommerce_payments_' + paymentMethod ); - giropayRadioLabel.click(); + const radioLabel = await page.waitForSelector( + '#payment .payment_method_woocommerce_payments_' + + paymentMethod + + ' label' + ); + radioLabel.click(); await page.waitFor( 1000 ); } /** - * Authorizes or fails a Giropay payment. + * Authorizes or fails a redirected payment. * * @param {*} page The page reference object. * @param {string} action Either of 'success' or 'failure'. */ -export async function completeGiropayPayment( page, action ) { +export async function completeRedirectedPayment( page, action ) { await page.$( '.actions .common-ButtonGroup' ); const actionButton = await page.waitForSelector( `.actions .common-ButtonGroup a[name=${ action }]` diff --git a/tests/unit/payment-methods/test-class-upe-payment-gateway.php b/tests/unit/payment-methods/test-class-upe-payment-gateway.php deleted file mode 100644 index 7c013e2b858..00000000000 --- a/tests/unit/payment-methods/test-class-upe-payment-gateway.php +++ /dev/null @@ -1,1026 +0,0 @@ - '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() ); - $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->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->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->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->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->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->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->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->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->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->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->assertTrue( $afterpay_method->is_enabled_at_checkout( 'US' ) ); - $this->assertFalse( $afterpay_method->is_reusable() ); - } - - 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 deleted file mode 100644 index 8671ab35be0..00000000000 --- a/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php +++ /dev/null @@ -1,1290 +0,0 @@ - '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() ); - $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->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->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->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->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->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->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->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->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->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/test-class-wc-payment-gateway-wcpay.php b/tests/unit/test-class-wc-payment-gateway-wcpay.php index 02505f94d51..62dd5c2f83a 100644 --- a/tests/unit/test-class-wc-payment-gateway-wcpay.php +++ b/tests/unit/test-class-wc-payment-gateway-wcpay.php @@ -15,9 +15,11 @@ use WCPay\Core\Server\Request\Get_Setup_Intention; use WCPay\Constants\Order_Status; use WCPay\Constants\Intent_Status; +use WCPay\Constants\Payment_Method; use WCPay\Duplicate_Payment_Prevention_Service; use WCPay\Exceptions\Amount_Too_Small_Exception; use WCPay\Exceptions\API_Exception; +use WCPay\Exceptions\Process_Payment_Exception; use WCPay\Fraud_Prevention\Fraud_Prevention_Service; use WCPay\Internal\Payment\Factor; use WCPay\Internal\Payment\Router; @@ -26,8 +28,20 @@ use WCPay\Internal\Service\OrderService; use WCPay\Internal\Service\PaymentProcessingService; use WCPay\Payment_Information; +use WCPay\Payment_Methods\Affirm_Payment_Method; +use WCPay\Payment_Methods\Afterpay_Payment_Method; +use WCPay\Payment_Methods\Bancontact_Payment_Method; +use WCPay\Payment_Methods\Becs_Payment_Method; use WCPay\Payment_Methods\CC_Payment_Method; +use WCPay\Payment_Methods\Eps_Payment_Method; +use WCPay\Payment_Methods\Giropay_Payment_Method; +use WCPay\Payment_Methods\Ideal_Payment_Method; +use WCPay\Payment_Methods\Klarna_Payment_Method; +use WCPay\Payment_Methods\Link_Payment_Method; +use WCPay\Payment_Methods\P24_Payment_Method; use WCPay\Payment_Methods\Sepa_Payment_Method; +use WCPay\Payment_Methods\Sofort_Payment_Method; +use WCPay\Payment_Methods\WC_Helper_Site_Currency; use WCPay\WooPay\WooPay_Utilities; use WCPay\Session_Rate_Limiter; @@ -45,9 +59,30 @@ class WC_Payment_Gateway_WCPay_Test extends WCPAY_UnitTestCase { /** * System under test. * + * The card gateway is predominantly used for testing compared to other gateways, + * therefore it is assigned its own variable. + * * @var WC_Payment_Gateway_WCPay */ - private $wcpay_gateway; + private $card_gateway; + + /** + * Arrays of system under test. + * + * Useful when testing operations involving multiple gateways. + * + * @var WC_Payment_Gateway_WCPay[] + */ + private $gateways; + + /** + * Arrays of payment methods. + * + * Useful when testing operations involving multiple payment methods. + * + * @var WCPay\Payment_Methods\UPE_Payment_Method[] + */ + private $payment_methods; /** * Mock WC_Payments_API_Client. @@ -168,16 +203,6 @@ public function set_up() { $this->mock_api_client->expects( $this->any() )->method( 'get_blog_id' )->willReturn( 1234567 ); $this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class ); - $this->mock_wcpay_account - ->expects( $this->any() ) - ->method( 'get_fees' ) - ->willReturn( - [ - 'card' => [ - 'base' => 0.1, - ], - ] - ); // Mock the main class's cache service. $this->_cache = WC_Payments::get_database_cache(); @@ -211,22 +236,11 @@ public function set_up() { ->setMethods( [ 'is_subscription_item_in_cart' ] ) ->getMock(); - $this->wcpay_gateway = new WC_Payment_Gateway_WCPay( - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $this->mock_payment_method, - [ 'card' => $this->mock_payment_method ], - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service - ); + $this->init_gateways(); - WC_Payments::set_gateway( $this->wcpay_gateway ); + // Replace the main class's gateway for testing purposes. + $this->_gateway = WC_Payments::get_gateway(); + WC_Payments::set_gateway( $this->card_gateway ); $this->woopay_utilities = new WooPay_Utilities(); @@ -256,9 +270,12 @@ public function tear_down() { // Restore the cache service in the main class. WC_Payments::set_database_cache( $this->_cache ); + // Restore the gateway in the main class. + WC_Payments::set_gateway( $this->_gateway ); + // Fall back to an US store. update_option( 'woocommerce_store_postcode', '94110' ); - $this->wcpay_gateway->update_option( 'saved_cards', 'yes' ); + $this->card_gateway->update_option( 'saved_cards', 'yes' ); // Some tests simulate payment method parameters. $payment_method_keys = [ @@ -277,6 +294,890 @@ public function tear_down() { wcpay_get_test_container()->reset_all_replacements(); } + 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, + ] + ); + + $request = $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id ); + + $request->expects( $this->once() ) + ->method( 'format_response' ) + ->will( $this->returnValue( $payment_intent ) ); + + $this->mock_customer_service + ->expects( $this->once() ) + ->method( 'get_customer_id_by_user_id' ) + ->will( $this->returnValue( $customer_id ) ); + + $this->card_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_wcpay_request( Get_Intention::class, 1, $intent_id ) + ->expects( $this->once() ) + ->method( 'format_response' ) + ->willReturn( $payment_intent ); + + $this->mock_customer_service + ->expects( $this->once() ) + ->method( 'get_customer_id_by_user_id' ) + ->will( $this->returnValue( $customer_id ) ); + + $this->card_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->card_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->card_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->card_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', + ]; + + $card_method = $this->payment_methods['card']; + $giropay_method = $this->payment_methods['giropay']; + $p24_method = $this->payment_methods['p24']; + $sofort_method = $this->payment_methods['sofort']; + $bancontact_method = $this->payment_methods['bancontact']; + $eps_method = $this->payment_methods['eps']; + $sepa_method = $this->payment_methods['sepa_debit']; + $ideal_method = $this->payment_methods['ideal']; + $becs_method = $this->payment_methods['au_becs_debit']; + $affirm_method = $this->payment_methods['affirm']; + $afterpay_method = $this->payment_methods['afterpay_clearpay']; + + $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->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->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->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->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->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->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->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->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->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->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->assertTrue( $afterpay_method->is_enabled_at_checkout( 'US' ) ); + $this->assertFalse( $afterpay_method->is_reusable() ); + } + + public function test_only_reusabled_payment_methods_enabled_with_subscription_item_present() { + // Simulate is_changing_payment_method_for_subscription being true so that is_enabled_at_checkout() checks if the payment method is reusable(). + $_GET['change_payment_method'] = 10; + WC_Subscriptions::set_wcs_is_subscription( + function ( $order ) { + return true; + } + ); + + $card_method = $this->payment_methods['card']; + $giropay_method = $this->payment_methods['giropay']; + $sofort_method = $this->payment_methods['sofort']; + $bancontact_method = $this->payment_methods['bancontact']; + $eps_method = $this->payment_methods['eps']; + $sepa_method = $this->payment_methods['sepa_debit']; + $p24_method = $this->payment_methods['p24']; + $ideal_method = $this->payment_methods['ideal']; + $becs_method = $this->payment_methods['au_becs_debit']; + $affirm_method = $this->payment_methods['affirm']; + $afterpay_method = $this->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->payment_methods['card']; + $giropay_method = $this->payment_methods['giropay']; + $sofort_method = $this->payment_methods['sofort']; + $bancontact_method = $this->payment_methods['bancontact']; + $eps_method = $this->payment_methods['eps']; + $sepa_method = $this->payment_methods['sepa_debit']; + $p24_method = $this->payment_methods['p24']; + $ideal_method = $this->payment_methods['ideal']; + $becs_method = $this->payment_methods['au_becs_debit']; + $affirm_method = $this->payment_methods['affirm']; + $afterpay_method = $this->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->payment_methods['card']; + $giropay_method = $this->payment_methods['giropay']; + $sofort_method = $this->payment_methods['sofort']; + $bancontact_method = $this->payment_methods['bancontact']; + $eps_method = $this->payment_methods['eps']; + $sepa_method = $this->payment_methods['sepa_debit']; + $p24_method = $this->payment_methods['p24']; + $ideal_method = $this->payment_methods['ideal']; + $becs_method = $this->payment_methods['au_becs_debit']; + $affirm_method = $this->payment_methods['affirm']; + $afterpay_method = $this->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 ) ); + + WC_Helper_Site_Currency::$mock_site_currency = 'USD'; + $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->card_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->card_gateway->process_payment( $order->get_id() ); + } + + public function test_remove_link_payment_method_if_card_disabled() { + $link_gateway = $this->get_gateway( Payment_Method::LINK ); + $link_gateway->settings['upe_enabled_payment_method_ids'] = [ 'link' ]; + + $this->mock_wcpay_account + ->expects( $this->any() ) + ->method( 'get_cached_account_data' ) + ->willReturn( + [ + 'capabilities' => [ + 'link_payments' => 'active', + ], + 'capability_requirements' => [ + 'link_payments' => [], + ], + ] + ); + + $this->assertSame( $link_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 ) { + $this->mock_wcpay_account + ->expects( $this->once() ) + ->method( 'get_fees' ) + ->willReturn( $payment_methods ); + + $this->assertEquals( $expected_result, $this->card_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' => [ + [], + [], + ], + ]; + } + + // This test uses a mock of the gateway class due to get_selected_payment_method()'s reliance on the static method WC_Payments::get_payment_method_map(), which can't be mocked. Refactoring the gateway class to avoid using this static method would allow mocking it in tests. + public function test_process_redirect_setup_intent_succeded() { + $order = WC_Helper_Order::create_order(); + + /** @var WC_Payment_Gateway_WCPay */ + $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->payment_methods['card'], + [ $this->payment_methods ], + $this->mock_rate_limiter, + $this->order_service, + $this->mock_dpps, + $this->mock_localization_service, + $this->mock_fraud_service, + ] + ) + ->onlyMethods( + [ + 'manage_customer_details_for_order', + 'get_selected_payment_method', + ] + ) + ->getMock(); + + $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->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_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_gateway->expects( $this->any() ) + ->method( 'get_selected_payment_method' ) + ->willReturn( $card_method ); + + // Simulate is_changing_payment_method_for_subscription being true so that is_enabled_at_checkout() checks if the payment method is reusable(). + $_GET['change_payment_method'] = 10; + WC_Subscriptions::set_wcs_is_subscription( + function ( $order ) { + return true; + } + ); + + $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( $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() ) ); + } + + // This test uses a mock of the gateway class due to get_selected_payment_method()'s reliance on the static method WC_Payments::get_payment_method_map(), which can't be mocked. Refactoring the gateway class to avoid using this static method would allow mocking it in tests. + public function test_process_redirect_payment_save_payment_token() { + /** @var WC_Payment_Gateway_WCPay */ + $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->payment_methods['card'], + [ $this->payment_methods ], + $this->mock_rate_limiter, + $this->order_service, + $this->mock_dpps, + $this->mock_localization_service, + $this->mock_fraud_service, + ] + ) + ->onlyMethods( + [ + 'manage_customer_details_for_order', + 'get_selected_payment_method', + ] + ) + ->getMock(); + + $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->payment_methods['card']; + + $payment_intent = WC_Helper_Intention::create_intention( + [ + 'status' => $intent_status, + 'metadata' => $intent_metadata, + ] + ); + + $mock_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_gateway->expects( $this->any() ) + ->method( 'get_selected_payment_method' ) + ->willReturn( $card_method ); + + // Simulate is_changing_payment_method_for_subscription being true so that is_enabled_at_checkout() checks if the payment method is reusable(). + $_GET['change_payment_method'] = 10; + WC_Subscriptions::set_wcs_is_subscription( + function ( $order ) { + return true; + } + ); + + $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() ); + $this->assertEquals( 1, count( $result_order->get_payment_tokens() ) ); + } + + public function test_get_payment_methods_with_post_request_context() { + $order = WC_Helper_Order::create_order(); + $payment_information = new Payment_Information( 'pm_mock', $order ); + + $_POST['payment_method'] = 'woocommerce_payments'; + + $payment_methods = $this->card_gateway->get_payment_method_types( $payment_information ); + + $this->assertSame( [ Payment_Method::CARD ], $payment_methods ); + + unset( $_POST['payment_method'] ); // phpcs:ignore WordPress.Security.NonceVerification + } + + public function test_get_payment_methods_without_post_request_context() { + $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 + + $payment_methods = $this->card_gateway->get_payment_method_types( $payment_information ); + + $this->assertSame( [ Payment_Method::CARD ], $payment_methods ); + } + + public function test_get_payment_methods_without_request_context_or_token() { + $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( $this->card_gateway ); + + $payment_methods = $this->card_gateway->get_payment_method_types( $payment_information ); + + $this->assertSame( [ Payment_Method::CARD ], $payment_methods ); + + WC_Payments::set_gateway( $gateway ); + } + + public function test_get_payment_methods_from_gateway_id_upe() { + WC_Helper_Order::create_order(); + + $gateway = WC_Payments::get_gateway(); + + $payment_methods = $this->card_gateway->get_payment_methods_from_gateway_id( WC_Payment_Gateway_WCPay::GATEWAY_ID . '_' . Payment_Method::BANCONTACT ); + $this->assertSame( [ Payment_Method::BANCONTACT ], $payment_methods ); + + $this->mock_wcpay_account + ->expects( $this->any() ) + ->method( 'get_cached_account_data' ) + ->willReturn( + [ + 'capabilities' => [ + 'link_payments' => 'active', + 'card_payments' => 'active', + ], + 'capability_requirements' => [ + 'link_payments' => [], + 'card_payments' => [], + ], + ] + ); + $this->card_gateway->settings['upe_enabled_payment_method_ids'] = [ Payment_Method::LINK, Payment_Method::CARD ]; + WC_Payments::set_gateway( $this->card_gateway ); + $payment_methods = $this->card_gateway->get_payment_methods_from_gateway_id( WC_Payment_Gateway_WCPay::GATEWAY_ID ); + $this->assertSame( [ Payment_Method::CARD, Payment_Method::LINK ], $payment_methods ); + + $this->card_gateway->settings['upe_enabled_payment_method_ids'] = [ Payment_Method::CARD ]; + $payment_methods = $this->card_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 ); + } + + public function test_display_gateway_html() { + foreach ( $this->gateways as $gateway ) { + /** + * This tests each payment method output separately without concatenating the output + * into 1 single buffer. Each iteration has 1 assertion. + */ + ob_start(); + $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_non_card() { + foreach ( $this->get_gateways_excluding( [ Payment_Method::CARD ] ) as $gateway ) { + $this->assertFalse( $gateway->should_use_stripe_platform_on_checkout_page() ); + } + } + public function test_attach_exchange_info_to_order_with_no_conversion() { $charge_id = 'ch_mock'; @@ -290,7 +1191,7 @@ public function test_attach_exchange_info_to_order_with_no_conversion() { ->method( 'get_account_default_currency' ) ->willReturn( 'usd' ); - $this->wcpay_gateway->attach_exchange_info_to_order( $order, $charge_id ); + $this->card_gateway->attach_exchange_info_to_order( $order, $charge_id ); // The meta key should not be set. $this->assertEquals( '', $order->get_meta( '_wcpay_multi_currency_stripe_exchange_rate' ) ); @@ -309,7 +1210,7 @@ public function test_attach_exchange_info_to_order_with_different_account_curren ->method( 'get_account_default_currency' ) ->willReturn( 'jpy' ); - $this->wcpay_gateway->attach_exchange_info_to_order( $order, $charge_id ); + $this->card_gateway->attach_exchange_info_to_order( $order, $charge_id ); // The meta key should not be set. $this->assertEquals( '', $order->get_meta( '_wcpay_multi_currency_stripe_exchange_rate' ) ); @@ -345,7 +1246,7 @@ public function test_attach_exchange_info_to_order_with_zero_decimal_order_curre ] ); - $this->wcpay_gateway->attach_exchange_info_to_order( $order, $charge_id ); + $this->card_gateway->attach_exchange_info_to_order( $order, $charge_id ); $this->assertEquals( 0.009414, $order->get_meta( '_wcpay_multi_currency_stripe_exchange_rate' ) ); } @@ -378,7 +1279,7 @@ public function test_attach_exchange_info_to_order_with_different_order_currency ] ); - $this->wcpay_gateway->attach_exchange_info_to_order( $order, $charge_id ); + $this->card_gateway->attach_exchange_info_to_order( $order, $charge_id ); $this->assertEquals( 0.853, $order->get_meta( '_wcpay_multi_currency_stripe_exchange_rate' ) ); } @@ -394,7 +1295,7 @@ function ( $output ) { } ); - $this->wcpay_gateway->save_payment_method_checkbox(); + $this->card_gateway->save_payment_method_checkbox(); } public function test_save_payment_method_checkbox_not_displayed_when_force_checked() { @@ -408,13 +1309,13 @@ function ( $output ) { } ); - $this->wcpay_gateway->save_payment_method_checkbox( true ); + $this->card_gateway->save_payment_method_checkbox( true ); } public function test_save_payment_method_checkbox_not_displayed_when_stripe_platform_account_used() { // Setup the test so that should_use_stripe_platform_on_checkout_page returns true. $this->mock_cache->method( 'get' )->willReturn( [ 'platform_checkout_eligible' => true ] ); - $this->wcpay_gateway->update_option( 'platform_checkout', 'yes' ); + $this->card_gateway->update_option( 'platform_checkout', 'yes' ); add_filter( 'woocommerce_is_checkout', '__return_true' ); WC()->session->init(); WC()->cart->add_to_cart( WC_Helper_Product::create_simple_product()->get_id(), 1 ); @@ -430,7 +1331,7 @@ function ( $output ) { } ); - $this->wcpay_gateway->save_payment_method_checkbox( false ); + $this->card_gateway->save_payment_method_checkbox( false ); remove_filter( 'woocommerce_is_checkout', '__return_true' ); WC()->cart->empty_cart(); @@ -457,7 +1358,7 @@ public function test_capture_charge_success() { ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention() ); - $result = $this->wcpay_gateway->capture_charge( $order ); + $result = $this->card_gateway->capture_charge( $order ); $notes = wc_get_order_notes( [ @@ -509,7 +1410,7 @@ public function test_capture_charge_success_non_usd() { ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention( [ 'currency' => 'eur' ] ) ); - $result = $this->wcpay_gateway->capture_charge( $order ); + $result = $this->card_gateway->capture_charge( $order ); $notes = wc_get_order_notes( [ @@ -558,7 +1459,7 @@ public function test_capture_charge_failure() { ->method( 'format_response' ) ->willReturn( $mock_intent ); - $result = $this->wcpay_gateway->capture_charge( $order ); + $result = $this->card_gateway->capture_charge( $order ); $note = wc_get_order_notes( [ @@ -610,7 +1511,7 @@ public function test_capture_charge_failure_non_usd() { ->method( 'format_response' ) ->willReturn( $mock_intent ); - $result = $this->wcpay_gateway->capture_charge( $order ); + $result = $this->card_gateway->capture_charge( $order ); $note = wc_get_order_notes( [ @@ -664,7 +1565,7 @@ public function test_capture_charge_api_failure() { ->method( 'format_response' ) ->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) ); - $result = $this->wcpay_gateway->capture_charge( $order ); + $result = $this->card_gateway->capture_charge( $order ); $note = wc_get_order_notes( [ @@ -723,7 +1624,7 @@ public function test_capture_charge_api_failure_non_usd() { ->method( 'format_response' ) ->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) ); - $result = $this->wcpay_gateway->capture_charge( $order ); + $result = $this->card_gateway->capture_charge( $order ); $note = wc_get_order_notes( [ @@ -778,7 +1679,7 @@ public function test_capture_charge_expired() { ->method( 'format_response' ) ->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) ); - $result = $this->wcpay_gateway->capture_charge( $order ); + $result = $this->card_gateway->capture_charge( $order ); $note = wc_get_order_notes( [ @@ -833,7 +1734,7 @@ public function test_capture_charge_metadata() { ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention() ); - $result = $this->wcpay_gateway->capture_charge( $order, true, [] ); + $result = $this->card_gateway->capture_charge( $order, true, [] ); $note = wc_get_order_notes( [ @@ -883,7 +1784,7 @@ public function test_capture_charge_without_level3() { ->expects( $this->never() ) ->method( 'get_account_country' ); // stand-in for get_level3_data_from_order. - $result = $this->wcpay_gateway->capture_charge( $order, false ); + $result = $this->card_gateway->capture_charge( $order, false ); $notes = wc_get_order_notes( [ @@ -1075,7 +1976,7 @@ public function test_cancel_authorization_handles_api_exception_when_canceling() ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::CANCELED ] ) ); - $this->wcpay_gateway->cancel_authorization( $order ); + $this->card_gateway->cancel_authorization( $order ); $note = wc_get_order_notes( [ @@ -1110,7 +2011,7 @@ public function test_cancel_authorization_handles_all_api_exceptions() { ->method( 'format_response' ) ->will( $this->throwException( new API_Exception( 'ignore this', 'test', 123 ) ) ); - $this->wcpay_gateway->cancel_authorization( $order ); + $this->card_gateway->cancel_authorization( $order ); $note = wc_get_order_notes( [ @@ -1125,7 +2026,7 @@ public function test_cancel_authorization_handles_all_api_exceptions() { } public function test_add_payment_method_no_method() { - $result = $this->wcpay_gateway->add_payment_method(); + $result = $this->card_gateway->add_payment_method(); $this->assertEquals( 'error', $result['result'] ); } @@ -1159,7 +2060,7 @@ public function test_create_and_confirm_setup_intent_existing_customer() { ) ); - $result = $this->wcpay_gateway->create_and_confirm_setup_intent(); + $result = $this->card_gateway->create_and_confirm_setup_intent(); $this->assertSame( 'seti_mock_123', $result->get_id() ); } @@ -1186,13 +2087,13 @@ public function test_create_and_confirm_setup_intent_no_customer() { ) ); - $result = $this->wcpay_gateway->create_and_confirm_setup_intent(); + $result = $this->card_gateway->create_and_confirm_setup_intent(); $this->assertSame( 'seti_mock_123', $result->get_id() ); } public function test_add_payment_method_no_intent() { - $result = $this->wcpay_gateway->add_payment_method(); + $result = $this->card_gateway->add_payment_method(); $this->assertEquals( 'error', $result['result'] ); } @@ -1222,7 +2123,7 @@ public function test_add_payment_method_success() { ->method( 'add_payment_method_to_user' ) ->with( 'pm_mock', wp_get_current_user() ); - $result = $this->wcpay_gateway->add_payment_method(); + $result = $this->card_gateway->add_payment_method(); $this->assertEquals( 'success', $result['result'] ); } @@ -1241,7 +2142,7 @@ public function test_add_payment_method_no_customer() { ->expects( $this->never() ) ->method( 'add_payment_method_to_user' ); - $result = $this->wcpay_gateway->add_payment_method(); + $result = $this->card_gateway->add_payment_method(); $this->assertEquals( 'error', $result['result'] ); } @@ -1263,7 +2164,7 @@ public function test_add_payment_method_cancelled_intent() { ->expects( $this->never() ) ->method( 'add_payment_method_to_user' ); - $result = $this->wcpay_gateway->add_payment_method(); + $result = $this->card_gateway->add_payment_method(); $this->assertEquals( 'error', $result['result'] ); wc_clear_notices(); @@ -1278,7 +2179,7 @@ public function test_schedule_order_tracking_with_wrong_payment_gateway() { ->expects( $this->never() ) ->method( 'schedule_job' ); - $this->wcpay_gateway->schedule_order_tracking( $order->get_id(), $order ); + $this->card_gateway->schedule_order_tracking( $order->get_id(), $order ); } public function test_schedule_order_tracking_with_sift_disabled() { @@ -1297,7 +2198,7 @@ public function test_schedule_order_tracking_with_sift_disabled() { ] ); - $this->wcpay_gateway->schedule_order_tracking( $order->get_id(), $order ); + $this->card_gateway->schedule_order_tracking( $order->get_id(), $order ); } public function test_schedule_order_tracking_with_no_payment_method_id() { @@ -1319,7 +2220,7 @@ public function test_schedule_order_tracking_with_no_payment_method_id() { ] ); - $this->wcpay_gateway->schedule_order_tracking( $order->get_id(), $order ); + $this->card_gateway->schedule_order_tracking( $order->get_id(), $order ); } public function test_schedule_order_tracking() { @@ -1343,7 +2244,7 @@ public function test_schedule_order_tracking() { ] ); - $this->wcpay_gateway->schedule_order_tracking( $order->get_id(), $order ); + $this->card_gateway->schedule_order_tracking( $order->get_id(), $order ); } public function test_schedule_order_tracking_on_already_created_order() { @@ -1367,12 +2268,12 @@ public function test_schedule_order_tracking_on_already_created_order() { ] ); - $this->wcpay_gateway->schedule_order_tracking( $order->get_id(), $order ); + $this->card_gateway->schedule_order_tracking( $order->get_id(), $order ); } public function test_outputs_payments_settings_screen() { ob_start(); - $this->wcpay_gateway->output_payments_settings_screen(); + $this->card_gateway->output_payments_settings_screen(); $output = ob_get_clean(); $this->assertStringMatchesFormat( '%aid="wcpay-account-settings-container"%a', $output ); } @@ -1380,7 +2281,7 @@ public function test_outputs_payments_settings_screen() { public function test_outputs_express_checkout_settings_screen() { $_GET['method'] = 'foo'; ob_start(); - $this->wcpay_gateway->output_payments_settings_screen(); + $this->card_gateway->output_payments_settings_screen(); $output = ob_get_clean(); $this->assertStringMatchesFormat( '%aid="wcpay-express-checkout-settings-container"%a', $output ); $this->assertStringMatchesFormat( '%adata-method-id="foo"%a', $output ); @@ -1394,11 +2295,11 @@ public function test_outputs_express_checkout_settings_screen() { public function test_validate_account_statement_descriptor_field( $is_valid, $value, $expected = null ) { $key = 'account_statement_descriptor'; if ( $is_valid ) { - $validated_value = $this->wcpay_gateway->validate_account_statement_descriptor_field( $key, $value ); + $validated_value = $this->card_gateway->validate_account_statement_descriptor_field( $key, $value ); $this->assertEquals( $expected ?? $value, $validated_value ); } else { $this->expectExceptionMessage( 'Customer bank statement is invalid.' ); - $this->wcpay_gateway->validate_account_statement_descriptor_field( $key, $value ); + $this->card_gateway->validate_account_statement_descriptor_field( $key, $value ); } } @@ -1435,14 +2336,14 @@ public function test_payment_request_form_field_defaults() { 'cart', 'checkout', ], - $this->wcpay_gateway->get_option( 'payment_request_button_locations' ) + $this->card_gateway->get_option( 'payment_request_button_locations' ) ); $this->assertEquals( 'medium', - $this->wcpay_gateway->get_option( 'payment_request_button_size' ) + $this->card_gateway->get_option( 'payment_request_button_size' ) ); - $form_fields = $this->wcpay_gateway->get_form_fields(); + $form_fields = $this->card_gateway->get_form_fields(); $this->assertEquals( [ @@ -1472,7 +2373,7 @@ public function test_payment_gateway_enabled_for_supported_currency() { ] ) ); - $this->assertTrue( $this->wcpay_gateway->is_available_for_current_currency() ); + $this->assertTrue( $this->card_gateway->is_available_for_current_currency() ); } public function test_payment_gateway_enabled_for_empty_supported_currency_list() { @@ -1482,7 +2383,7 @@ public function test_payment_gateway_enabled_for_empty_supported_currency_list() [] ) ); - $this->assertTrue( $this->wcpay_gateway->is_available_for_current_currency() ); + $this->assertTrue( $this->card_gateway->is_available_for_current_currency() ); } public function test_payment_gateway_disabled_for_unsupported_currency() { @@ -1493,7 +2394,7 @@ public function test_payment_gateway_disabled_for_unsupported_currency() { ] ) ); - $this->assertFalse( $this->wcpay_gateway->is_available_for_current_currency() ); + $this->assertFalse( $this->card_gateway->is_available_for_current_currency() ); } public function test_process_payment_for_order_not_from_request() { @@ -1519,7 +2420,7 @@ public function test_process_payment_for_order_not_from_request() { ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention( [ 'status' => 'success' ] ) ); - $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); + $this->card_gateway->process_payment_for_order( WC()->cart, $pi ); } public function test_process_payment_for_order_rejects_with_cached_minimum_amount() { @@ -1534,10 +2435,10 @@ public function test_process_payment_for_order_rejects_with_cached_minimum_amoun $this->expectException( Exception::class ); $this->expectExceptionMessage( 'The selected payment method requires a total amount of at least $0.50.' ); - $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); + $this->card_gateway->process_payment_for_order( WC()->cart, $pi ); } - public function test_mandate_data_not_added_to_payment_intent_if_not_required() { + public function test_set_mandate_data_to_payment_intent_if_not_required() { $payment_method = 'woocommerce_payments_sepa_debit'; $order = WC_Helper_Order::create_order(); $order->set_currency( 'USD' ); @@ -1555,13 +2456,13 @@ public function test_mandate_data_not_added_to_payment_intent_if_not_required() $request->expects( $this->never() ) ->method( 'set_mandate_data' ); - // Mandate data is required for SEPA and Stripe Link only, $this->wcpay_gateway is created with card hence mandate data should not be added. - $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); + // Mandate data is required for SEPA and Stripe Link only, $this->card_gateway is created with card hence mandate data should not be added. + $this->card_gateway->process_payment_for_order( WC()->cart, $pi ); } - public function test_mandate_data_added_to_payment_intent_if_required() { + public function test_set_mandate_data_to_payment_intent_if_required() { // Mandate data is required for SEPA and Stripe Link, hence creating the gateway with a SEPA payment method should add mandate data. - $gateway = $this->create_gateway_with( new Sepa_Payment_Method( $this->mock_token_service ) ); + $gateway = $this->get_gateway( Payment_Method::SEPA ); $payment_method = 'woocommerce_payments_sepa_debit'; $order = WC_Helper_Order::create_order(); $order->set_currency( 'USD' ); @@ -1593,9 +2494,9 @@ function ( $data ) { $gateway->process_payment_for_order( WC()->cart, $pi ); } - public function test_mandate_data_not_added_to_setup_intent_request_when_link_is_disabled() { + public function test_set_mandate_data_with_setup_intent_request_when_link_is_disabled() { // Disabled link is reflected in upe_enabled_payment_method_ids: when link is disabled, the array contains only card. - $this->wcpay_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card' ]; + $this->card_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card' ]; $payment_method = 'woocommerce_payments'; $order = WC_Helper_Order::create_order(); @@ -1631,11 +2532,11 @@ public function test_mandate_data_not_added_to_setup_intent_request_when_link_is $request->expects( $this->never() ) ->method( 'set_mandate_data' ); - $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); + $this->card_gateway->process_payment_for_order( WC()->cart, $pi ); } - public function test_mandate_data_added_to_setup_intent_request_when_link_is_enabled() { - $this->wcpay_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card', 'link' ]; + public function test_set_mandate_data_with_setup_intent_request_when_link_is_enabled() { + $this->card_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card', 'link' ]; $payment_method = 'woocommerce_payments'; $order = WC_Helper_Order::create_order(); @@ -1681,8 +2582,38 @@ function ( $data ) { ) ); - $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); - $this->wcpay_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card' ]; + $this->card_gateway->process_payment_for_order( WC()->cart, $pi ); + $this->card_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card' ]; + } + + public function test_is_mandate_data_required_card_and_link() { + $this->card_gateway->update_option( 'upe_enabled_payment_method_ids', [ Payment_Method::LINK ] ); + $this->assertTrue( $this->card_gateway->is_mandate_data_required() ); + } + + public function test_is_mandate_data_required_sepa() { + $sepa = $this->get_gateway( Payment_Method::SEPA ); + $this->assertTrue( $sepa->is_mandate_data_required() ); + } + + public function test_is_mandate_data_required_returns_false() { + foreach ( $this->get_gateways_excluding( [ Payment_Method::SEPA, Payment_Method::CARD ] ) as $gateway ) { + $this->assertFalse( $gateway->is_mandate_data_required() ); + } + } + + public function test_non_reusable_gateways_not_available_when_changing_payment_method_for_card() { + // Simulate is_changing_payment_method_for_subscription being true so that is_enabled_at_checkout() checks if the payment method is reusable(). + $_GET['change_payment_method'] = 10; + WC_Subscriptions::set_wcs_is_subscription( + function ( $order ) { + return true; + } + ); + + foreach ( $this->get_gateways_excluding( [ Payment_Method::CARD ] ) as $gateway ) { + $this->assertFalse( $gateway->is_available() ); + } } public function test_process_payment_for_order_cc_payment_method() { @@ -1705,7 +2636,7 @@ public function test_process_payment_for_order_cc_payment_method() { ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention( [ 'status' => 'success' ] ) ); - $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); + $this->card_gateway->process_payment_for_order( WC()->cart, $pi ); } public function test_process_payment_for_order_upe_payment_method() { @@ -1728,7 +2659,7 @@ public function test_process_payment_for_order_upe_payment_method() { ->method( 'format_response' ) ->willReturn( WC_Helper_Intention::create_intention( [ 'status' => 'success' ] ) ); - $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi ); + $this->card_gateway->process_payment_for_order( WC()->cart, $pi ); } public function test_process_payment_caches_mimimum_amount_and_displays_error_upon_exception() { @@ -1780,7 +2711,7 @@ public function test_process_payment_caches_mimimum_amount_and_displays_error_up $this->expectExceptionMessage( $message ); try { - $this->wcpay_gateway->process_payment( $order->get_id() ); + $this->card_gateway->process_payment( $order->get_id() ); } catch ( Exception $e ) { $this->assertEquals( '6000', get_transient( 'wcpay_minimum_amount_usd' ) ); throw $e; @@ -1799,7 +2730,7 @@ public function test_process_payment_rejects_if_missing_fraud_prevention_token() $this->expectException( Exception::class ); $this->expectExceptionMessage( "We're not able to process this payment. Please refresh the page and try again." ); - $this->wcpay_gateway->process_payment( $order->get_id() ); + $this->card_gateway->process_payment( $order->get_id() ); } public function test_process_payment_rejects_if_invalid_fraud_prevention_token() { @@ -1822,7 +2753,7 @@ public function test_process_payment_rejects_if_invalid_fraud_prevention_token() $this->expectException( Exception::class ); $this->expectExceptionMessage( "We're not able to process this payment. Please refresh the page and try again." ); - $this->wcpay_gateway->process_payment( $order->get_id() ); + $this->card_gateway->process_payment( $order->get_id() ); } public function test_process_payment_continues_if_valid_fraud_prevention_token() { @@ -1872,7 +2803,7 @@ public function test_get_upe_enabled_payment_method_statuses_with_empty_cache() 'requirements' => [], ], ], - $this->wcpay_gateway->get_upe_enabled_payment_method_statuses() + $this->card_gateway->get_upe_enabled_payment_method_statuses() ); } @@ -1906,7 +2837,7 @@ public function test_get_upe_enabled_payment_method_statuses_with_cache() { 'requirements' => [], ], ], - $this->wcpay_gateway->get_upe_enabled_payment_method_statuses() + $this->card_gateway->get_upe_enabled_payment_method_statuses() ); } @@ -1920,36 +2851,36 @@ public function test_woopay_form_field_defaults() { 'cart', 'checkout', ], - $this->wcpay_gateway->get_option( 'platform_checkout_button_locations' ) + $this->card_gateway->get_option( 'platform_checkout_button_locations' ) ); $this->assertEquals( 'By placing this order, you agree to our [terms] and understand our [privacy_policy].', - $this->wcpay_gateway->get_option( 'platform_checkout_custom_message' ) + $this->card_gateway->get_option( 'platform_checkout_custom_message' ) ); } public function test_is_woopay_enabled_returns_true() { $this->mock_cache->method( 'get' )->willReturn( [ 'platform_checkout_eligible' => true ] ); - $this->wcpay_gateway->update_option( 'platform_checkout', 'yes' ); + $this->card_gateway->update_option( 'platform_checkout', 'yes' ); wp_set_current_user( 1 ); add_filter( 'woocommerce_is_checkout', '__return_true' ); - $this->assertTrue( $this->woopay_utilities->should_enable_woopay( $this->wcpay_gateway ) ); + $this->assertTrue( $this->woopay_utilities->should_enable_woopay( $this->card_gateway ) ); remove_filter( 'woocommerce_is_checkout', '__return_true' ); } public function test_should_use_stripe_platform_on_checkout_page_not_woopay_eligible() { $this->mock_cache->method( 'get' )->willReturn( [ 'platform_checkout_eligible' => false ] ); - $this->assertFalse( $this->wcpay_gateway->should_use_stripe_platform_on_checkout_page() ); + $this->assertFalse( $this->card_gateway->should_use_stripe_platform_on_checkout_page() ); } public function test_should_use_stripe_platform_on_checkout_page_not_woopay() { $this->mock_cache->method( 'get' )->willReturn( [ 'platform_checkout_eligible' => true ] ); - $this->wcpay_gateway->update_option( 'platform_checkout', 'no' ); + $this->card_gateway->update_option( 'platform_checkout', 'no' ); - $this->assertFalse( $this->wcpay_gateway->should_use_stripe_platform_on_checkout_page() ); + $this->assertFalse( $this->card_gateway->should_use_stripe_platform_on_checkout_page() ); } public function is_woopay_falsy_value_provider() { @@ -1971,13 +2902,13 @@ public function test_is_in_dev_mode() { $mode = WC_Payments::mode(); $mode->dev(); - $this->assertTrue( $this->wcpay_gateway->is_in_dev_mode() ); + $this->assertTrue( $this->card_gateway->is_in_dev_mode() ); $mode->test(); - $this->assertFalse( $this->wcpay_gateway->is_in_dev_mode() ); + $this->assertFalse( $this->card_gateway->is_in_dev_mode() ); $mode->live(); - $this->assertFalse( $this->wcpay_gateway->is_in_dev_mode() ); + $this->assertFalse( $this->card_gateway->is_in_dev_mode() ); } /** @@ -1987,13 +2918,13 @@ public function test_is_in_test_mode() { $mode = WC_Payments::mode(); $mode->dev(); - $this->assertTrue( $this->wcpay_gateway->is_in_test_mode() ); + $this->assertTrue( $this->card_gateway->is_in_test_mode() ); $mode->test(); - $this->assertTrue( $this->wcpay_gateway->is_in_test_mode() ); + $this->assertTrue( $this->card_gateway->is_in_test_mode() ); $mode->live(); - $this->assertFalse( $this->wcpay_gateway->is_in_test_mode() ); + $this->assertFalse( $this->card_gateway->is_in_test_mode() ); } /** @@ -2060,7 +2991,7 @@ public function test_should_use_new_process_requires_dev_mode() { $mock_router->expects( $this->never() ) ->method( 'should_use_new_payment_process' ); - $this->assertFalse( $this->wcpay_gateway->should_use_new_process( $order ) ); + $this->assertFalse( $this->card_gateway->should_use_new_process( $order ) ); } public function test_should_use_new_process_returns_false_if_feature_unavailable() { @@ -2078,7 +3009,7 @@ public function test_should_use_new_process_returns_false_if_feature_unavailable ->willReturn( false ); // Act: Call the method. - $result = $this->wcpay_gateway->should_use_new_process( $order ); + $result = $this->card_gateway->should_use_new_process( $order ); $this->assertFalse( $result ); } @@ -2099,7 +3030,7 @@ public function test_should_use_new_process_uses_the_new_process() { ->willReturn( true ); // Act: Call the method. - $result = $this->wcpay_gateway->should_use_new_process( $order ); + $result = $this->card_gateway->should_use_new_process( $order ); $this->assertTrue( $result ); } @@ -2110,7 +3041,7 @@ public function test_should_use_new_process_adds_base_factor() { $order = WC_Helper_Order::create_order( 1, 0 ); $this->expect_router_factor( Factor::NEW_PAYMENT_PROCESS(), true ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_positive_no_payment() { @@ -2120,7 +3051,7 @@ public function test_should_use_new_process_determines_positive_no_payment() { $order = WC_Helper_Order::create_order( 1, 0 ); $this->expect_router_factor( Factor::NO_PAYMENT(), true ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_negative_no_payment() { @@ -2132,7 +3063,7 @@ public function test_should_use_new_process_determines_negative_no_payment() { $order->save(); $this->expect_router_factor( Factor::NO_PAYMENT(), false ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_negative_no_payment_when_saving_pm() { @@ -2145,7 +3076,7 @@ public function test_should_use_new_process_determines_negative_no_payment_when_ $_POST['wc-woocommerce_payments-new-payment-method'] = 'pm_XYZ'; $this->expect_router_factor( Factor::NO_PAYMENT(), false ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_positive_use_saved_pm() { @@ -2160,7 +3091,7 @@ public function test_should_use_new_process_determines_positive_use_saved_pm() { $_POST['wc-woocommerce_payments-payment-token'] = $token->get_id(); $this->expect_router_factor( Factor::USE_SAVED_PM(), true ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_negative_use_saved_pm() { @@ -2174,7 +3105,7 @@ public function test_should_use_new_process_determines_negative_use_saved_pm() { $_POST['wc-woocommerce_payments-payment-token'] = 'new'; $this->expect_router_factor( Factor::USE_SAVED_PM(), false ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_positive_save_pm() { @@ -2186,7 +3117,7 @@ public function test_should_use_new_process_determines_positive_save_pm() { $_POST['wc-woocommerce_payments-new-payment-method'] = '1'; $this->expect_router_factor( Factor::SAVE_PM(), true ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_positive_save_pm_for_subscription() { @@ -2198,7 +3129,7 @@ public function test_should_use_new_process_determines_positive_save_pm_for_subs WC_Subscriptions::$wcs_order_contains_subscription = '__return_true'; $this->expect_router_factor( Factor::SAVE_PM(), true ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_negative_save_pm() { @@ -2214,7 +3145,7 @@ public function test_should_use_new_process_determines_negative_save_pm() { $_POST['wc-woocommerce_payments-payment-token'] = $token->get_id(); $this->expect_router_factor( Factor::SAVE_PM(), false ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_positive_subscription_signup() { @@ -2226,7 +3157,7 @@ public function test_should_use_new_process_determines_positive_subscription_sig WC_Subscriptions::$wcs_order_contains_subscription = '__return_true'; $this->expect_router_factor( Factor::SUBSCRIPTION_SIGNUP(), true ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_negative_subscription_signup() { @@ -2238,7 +3169,7 @@ public function test_should_use_new_process_determines_negative_subscription_sig WC_Subscriptions::$wcs_order_contains_subscription = '__return_false'; $this->expect_router_factor( Factor::SUBSCRIPTION_SIGNUP(), false ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_positive_woopay_payment() { @@ -2250,7 +3181,7 @@ public function test_should_use_new_process_determines_positive_woopay_payment() $_POST['platform-checkout-intent'] = 'pi_ZYX'; $this->expect_router_factor( Factor::WOOPAY_PAYMENT(), true ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_should_use_new_process_determines_negative_woopay_payment() { @@ -2263,7 +3194,7 @@ public function test_should_use_new_process_determines_negative_woopay_payment() unset( $_POST['platform-checkout-intent'] ); $this->expect_router_factor( Factor::WOOPAY_PAYMENT(), false ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } /** @@ -2281,7 +3212,7 @@ public function test_should_use_new_process_determines_negative_wcpay_subscripti add_filter( 'wcpay_is_wcpay_subscriptions_enabled', '__return_true' ); $this->expect_router_factor( Factor::WCPAY_SUBSCRIPTION_SIGNUP(), false ); - $this->wcpay_gateway->should_use_new_process( $order ); + $this->card_gateway->should_use_new_process( $order ); } public function test_new_process_payment() { @@ -2306,7 +3237,7 @@ public function test_new_process_payment() { ->with( $order->get_id() ) ->willReturn( $mock_state ); - $result = $this->wcpay_gateway->process_payment( $order->get_id() ); + $result = $this->card_gateway->process_payment( $order->get_id() ); $this->assertSame( [ 'result' => 'success', @@ -2316,6 +3247,55 @@ public function test_new_process_payment() { ); } + public function test_process_payment_returns_correct_redirect() { + $order = WC_Helper_Order::create_order(); + $_POST = [ 'wcpay-payment-method' => 'pm_mock' ]; + + $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->mock_token_service + ->expects( $this->once() ) + ->method( 'add_payment_method_to_user' ) + ->willReturn( new WC_Payment_Token_CC() ); + + $result = $this->card_gateway->process_payment( $order->get_id() ); + + $this->assertEquals( 'success', $result['result'] ); + $this->assertEquals( $order->get_checkout_order_received_url(), $result['redirect'] ); + } + + public function test_process_payment_returns_correct_redirect_when_using_payment_request() { + $order = WC_Helper_Order::create_order(); + $_POST['payment_request_type'] = 'google_pay'; + $_POST = [ 'wcpay-payment-method' => 'pm_mock' ]; + + $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->mock_token_service + ->expects( $this->once() ) + ->method( 'add_payment_method_to_user' ) + ->willReturn( new WC_Payment_Token_CC() ); + + $result = $this->card_gateway->process_payment( $order->get_id() ); + + $this->assertEquals( 'success', $result['result'] ); + $this->assertEquals( $order->get_checkout_order_received_url(), $result['redirect'] ); + } + + public function is_proper_intent_used_with_order_returns_false() { + $this->assertFalse( $this->card_gateway->is_proper_intent_used_with_order( WC_Helper_Order::create_order(), 'wrong_intent_id' ) ); + } + /** * Sets up the expectation for a certain factor for the new payment * process to be either set or unset. @@ -2359,20 +3339,74 @@ private function create_charge_object() { return new WC_Payments_API_Charge( $this->mock_charge_id, 1500, $created ); } - private function create_gateway_with( $payment_method ) { - return new WC_Payment_Gateway_WCPay( - $this->mock_api_client, - $this->mock_wcpay_account, - $this->mock_customer_service, - $this->mock_token_service, - $this->mock_action_scheduler_service, - $payment_method, - [ $payment_method ], - $this->mock_rate_limiter, - $this->order_service, - $this->mock_dpps, - $this->mock_localization_service, - $this->mock_fraud_service + private function init_payment_methods() { + $payment_methods = []; + + $payment_method_classes = [ + CC_Payment_Method::class, + Bancontact_Payment_Method::class, + Sepa_Payment_Method::class, + Giropay_Payment_Method::class, + Sofort_Payment_Method::class, + P24_Payment_Method::class, + Ideal_Payment_Method::class, + Becs_Payment_Method::class, + Eps_Payment_Method::class, + Link_Payment_Method::class, + Affirm_Payment_Method::class, + Afterpay_Payment_Method::class, + Klarna_Payment_Method::class, + ]; + + foreach ( $payment_method_classes as $payment_method_class ) { + $payment_method = new $payment_method_class( $this->mock_token_service ); + $payment_methods[ $payment_method->get_id() ] = new $payment_method_class( $this->mock_token_service ); + } + $this->payment_methods = $payment_methods; + } + + private function init_gateways() { + $this->init_payment_methods(); + $gateways = []; + + foreach ( $this->payment_methods as $payment_method ) { + $gateways[] = new WC_Payment_Gateway_WCPay( + $this->mock_api_client, + $this->mock_wcpay_account, + $this->mock_customer_service, + $this->mock_token_service, + $this->mock_action_scheduler_service, + $payment_method, + $this->payment_methods, + $this->mock_rate_limiter, + $this->order_service, + $this->mock_dpps, + $this->mock_localization_service, + $this->mock_fraud_service + ); + } + + $this->gateways = $gateways; + $this->card_gateway = $gateways[0]; + } + + private function get_gateways_excluding( $excluded_payment_method_ids ) { + return array_filter( + $this->gateways, + function( $gateway ) use ( $excluded_payment_method_ids ) { + return ! in_array( $gateway->get_payment_method()->get_id(), $excluded_payment_method_ids, true ); + } ); } + + private function get_gateway( $payment_method_id ) { + return ( array_values( + array_filter( + $this->gateways, + function( $gateway ) use ( $payment_method_id ) { + return $payment_method_id === $gateway->get_payment_method()->get_id(); + } + ) + ) )[0] ?? null; + } }