Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a new feature flag and setting to control SPE #3988

Open
wants to merge 12 commits into
base: develop
Choose a base branch
from
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*** Changelog ***

= 9.3.0 - xxxx-xx-xx =
* Add - Adds a new feature flag to handle the Single Payment Element feature.
* Add - Add logging of IP address issues when setting up mandate data.
* Fix - Fixes a fatal error that might happen when a payment method ID cannot be retrieved during the processing of an order (new checkout experience).
* Dev - Generates a code coverage report for PHP Unit tests as a comment on PRs.
Expand Down
7 changes: 7 additions & 0 deletions client/data/settings/__tests__/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
useAmazonPayLocations,
useAmazonPayButtonSize,
useSepaTokensForOtherMethods,
useIsSpeEnabled,
} from '../hooks';
import { STORE_NAME } from '../../constants';
import {
Expand Down Expand Up @@ -339,6 +340,12 @@ describe( 'Settings hooks tests', () => {
testedValue: [ 'checkout', 'cart' ],
fallbackValue: [],
},
useIsSpeEnabledSettings: {
hook: useIsSpeEnabled,
storeKey: 'is_spe_enabled',
testedValue: true,
fallbackValue: false,
},
};

describe.each( Object.entries( generatedHookExpectations ) )(
Expand Down
1 change: 1 addition & 0 deletions client/data/settings/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ export const useIsShortAccountStatementEnabled = makeSettingsHook(
);
export const useDebugLog = makeSettingsHook( 'is_debug_log_enabled' );
export const useIsUpeEnabled = makeSettingsHook( 'is_upe_enabled' );
export const useIsSpeEnabled = makeSettingsHook( 'is_spe_enabled' );

export const useIndividualPaymentMethodSettings = makeSettingsHook(
'individual_payment_method_settings',
Expand Down
23 changes: 23 additions & 0 deletions client/settings/advanced-settings-section/__tests__/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,24 @@ import {
useIsUpeEnabled,
useGetSavingError,
useSettings,
useIsSpeEnabled,
} from 'wcstripe/data';

jest.mock( 'wcstripe/data', () => ( {
useDebugLog: jest.fn(),
useIsUpeEnabled: jest.fn(),
useIsSpeEnabled: jest.fn(),
useGetSavingError: jest.fn(),
useSettings: jest.fn(),
} ) );

describe( 'AdvancedSettings', () => {
beforeEach( () => {
global.wc_stripe_settings_params = { is_spe_available: false };

useDebugLog.mockReturnValue( [ true, jest.fn() ] );
useIsUpeEnabled.mockReturnValue( [ true, jest.fn() ] );
useIsSpeEnabled.mockReturnValue( [ false, jest.fn() ] );
useGetSavingError.mockReturnValue( null );

// Set `isLoading` to false so `LoadableSettingsSection` can render.
Expand Down Expand Up @@ -52,4 +57,22 @@ describe( 'AdvancedSettings', () => {

expect( setIsLoggingCheckedMock ).toHaveBeenCalledWith( true );
} );

it( 'should not display single payment element setting if the feature flag is disabled', () => {
render( <AdvancedSettings /> );

expect(
screen.queryByText( 'Single payment element' )
).not.toBeInTheDocument();
} );

it( 'should display single payment element setting if the feature flag is enabled', () => {
global.wc_stripe_settings_params = { is_spe_available: true };

render( <AdvancedSettings /> );

expect(
screen.queryByText( 'Single payment element' )
).toBeInTheDocument();
} );
} );
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { render, screen } from '@testing-library/react';
import React, { useContext } from 'react';
import userEvent from '@testing-library/user-event';
import SinglePaymentElementFeature from 'wcstripe/settings/advanced-settings-section/single-payment-element-feature';
import UpeToggleContext from 'wcstripe/settings/upe-toggle/context';

jest.useFakeTimers();

describe( 'Single Payment Element feature setting', () => {
it( 'should render', () => {
render( <SinglePaymentElementFeature /> );

expect(
screen.queryByText( 'Single payment element' )
).toBeInTheDocument();
} );

it( 'should be disabled when UPE is disabled', () => {
const UpdateUpeDisabledFlagMock = () => {
const { setIsUpeEnabled } = useContext( UpeToggleContext );
setTimeout( () => {
setIsUpeEnabled( false );
}, 1000 );
return null;
};

render(
<div>
<UpdateUpeDisabledFlagMock />
<SinglePaymentElementFeature />
</div>
);

const checkbox = screen.getByTestId(
'single-payment-element-checkbox'
);

userEvent.click( checkbox );

jest.runAllTimers();

expect( checkbox ).toBeDisabled();
expect( checkbox ).not.toBeChecked();
} );
} );
4 changes: 4 additions & 0 deletions client/settings/advanced-settings-section/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* global wc_stripe_settings_params */
import { __ } from '@wordpress/i18n';
import React from 'react';
import { Card } from '@wordpress/components';
Expand All @@ -6,6 +7,7 @@ import CardBody from '../card-body';
import DebugMode from './debug-mode';
import ExperimentalFeatures from './experimental-features';
import LoadableSettingsSection from 'wcstripe/settings/loadable-settings-section';
import SinglePaymentElementFeature from 'wcstripe/settings/advanced-settings-section/single-payment-element-feature';

const AdvancedSettingsDescription = () => (
<>
Expand All @@ -20,13 +22,15 @@ const AdvancedSettingsDescription = () => (
);

const AdvancedSettings = () => {
const isSpeAvailable = wc_stripe_settings_params.is_spe_available; // eslint-disable-line camelcase
return (
<SettingsSection Description={ AdvancedSettingsDescription }>
<LoadableSettingsSection numLines={ 10 }>
<Card>
<CardBody>
<DebugMode />
<ExperimentalFeatures />
{ isSpeAvailable && <SinglePaymentElementFeature /> }
</CardBody>
</Card>
</LoadableSettingsSection>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { __ } from '@wordpress/i18n';
import { createInterpolateElement } from '@wordpress/element';
import { CheckboxControl, ExternalLink } from '@wordpress/components';
import React, { useEffect } from 'react';
import { useIsSpeEnabled, useIsUpeEnabled } from '../../data';

const SinglePaymentElementFeature = () => {
const [ isSpeEnabled, setIsSpeEnabled ] = useIsSpeEnabled();
const [ isUpeEnabled ] = useIsUpeEnabled();

useEffect( () => {
if ( ! isUpeEnabled ) {
setIsSpeEnabled( false );
}
}, [ isUpeEnabled, setIsSpeEnabled ] );

return (
<>
<h4>
{ __( 'Single payment element', 'woocommerce-gateway-stripe' ) }
</h4>
<CheckboxControl
data-testid="single-payment-element-checkbox"
label={ __(
'Enable the single payment element feature',
'woocommerce-gateway-stripe'
) }
help={ createInterpolateElement(
__(
"By enabling this, your store checkout form will use Stripe's dynamic payment methods. Legacy checkout must be disabled. <learnMoreLink>Learn more</learnMoreLink>.",
'woocommerce-gateway-stripe'
),
{
learnMoreLink: (
<ExternalLink href="https://docs.stripe.com/connect/dynamic-payment-methods" />
),
}
) }
checked={ isSpeEnabled }
onChange={ setIsSpeEnabled }
disabled={ ! isUpeEnabled }
/>
</>
);
};

export default SinglePaymentElementFeature;
1 change: 1 addition & 0 deletions includes/admin/class-wc-stripe-settings-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ public function admin_scripts( $hook_suffix ) {
'account_country' => $this->account->get_account_country(),
'are_apms_deprecated' => WC_Stripe_Feature_Flags::are_apms_deprecated(),
'is_amazon_pay_available' => WC_Stripe_Feature_Flags::is_amazon_pay_available(),
'is_spe_available' => WC_Stripe_Feature_Flags::is_spe_available(),
'oauth_nonce' => wp_create_nonce( 'wc_stripe_get_oauth_urls' ),
];
wp_localize_script(
Expand Down
11 changes: 11 additions & 0 deletions includes/class-wc-stripe-feature-flags.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class WC_Stripe_Feature_Flags {
const UPE_CHECKOUT_FEATURE_ATTRIBUTE_NAME = 'upe_checkout_experience_enabled';
const ECE_FEATURE_FLAG_NAME = '_wcstripe_feature_ece';
const AMAZON_PAY_FEATURE_FLAG_NAME = '_wcstripe_feature_amazon_pay';
const SPE_FEATURE_FLAG_NAME = '_wcstripe_feature_spe';
const LPM_ACH_FEATURE_FLAG_NAME = '_wcstripe_feature_lpm_ach';
const LPM_ACSS_FEATURE_FLAG_NAME = '_wcstripe_feature_lpm_acss';
const LPM_BACS_FEATURE_FLAG_NAME = '_wcstripe_feature_lpm_bacs';
Expand All @@ -22,6 +23,7 @@ class WC_Stripe_Feature_Flags {
'_wcstripe_feature_upe' => 'yes',
self::ECE_FEATURE_FLAG_NAME => 'yes',
self::AMAZON_PAY_FEATURE_FLAG_NAME => 'no',
self::SPE_FEATURE_FLAG_NAME => 'no',
self::LPM_ACH_FEATURE_FLAG_NAME => 'no',
self::LPM_ACSS_FEATURE_FLAG_NAME => 'no',
self::LPM_BACS_FEATURE_FLAG_NAME => 'no',
Expand Down Expand Up @@ -147,4 +149,13 @@ public static function did_merchant_disable_upe() {
public static function are_apms_deprecated() {
return ( new \DateTime() )->format( 'Y-m-d' ) > '2024-10-28' && ! self::is_upe_checkout_enabled();
}

/**
* Whether the Single Payment Element (SPE) feature is enabled.
*
* @return bool
*/
public static function is_spe_available() {
return 'yes' === self::get_option_with_default( self::SPE_FEATURE_FLAG_NAME );
}
}
1 change: 1 addition & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ If you get stuck, you can ask for help in the [Plugin Forum](https://wordpress.o
== Changelog ==

= 9.3.0 - xxxx-xx-xx =
* Add - Adds a new feature flag to handle the Single Payment Element feature.
* Add - Add logging of IP address issues when setting up mandate data.
* Fix - Fixes a fatal error that might happen when a payment method ID cannot be retrieved during the processing of an order (new checkout experience).
* Dev - Generates a code coverage report for PHP Unit tests as a comment on PRs.
Expand Down
42 changes: 42 additions & 0 deletions tests/phpunit/test-class-wc-stripe-feature-flags.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
/**
* These tests make assertions against the class WC_Stripe_Feature_Flags
*/

/**
* Class WC_Stripe_Feature_Flags_Test
*
* @package WooCommerce_Stripe/Tests/WC_Stripe_Feature_Flags
*/
class WC_Stripe_Feature_Flags_Test extends WP_UnitTestCase {
/**
* Test for `is_spe_available`.
*
* @param string $option_value The value of the feature flag option.
* @param bool $expected The expected result.
* @return void
* @dataProvider provide_test_is_spe_available
*/
public function test_is_spe_available( $option_value, $expected ) {
update_option( WC_Stripe_Feature_Flags::SPE_FEATURE_FLAG_NAME, $option_value );
$this->assertSame( $expected, WC_Stripe_Feature_Flags::is_spe_available() );
}

/**
* Provider for `test_is_spe_available`.
*
* @return array
*/
public function provide_test_is_spe_available() {
return [
'available' => [
'option value' => 'yes',
'expected' => true,
],
'not available' => [
'option value' => 'no',
'expected' => false,
],
];
}
}
Loading