Skip to content

Commit c11633b

Browse files
authored
Update express checkout section UI (#2464)
* Update express checkout section
1 parent d199c2b commit c11633b

File tree

18 files changed

+649
-351
lines changed

18 files changed

+649
-351
lines changed

changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
*** Changelog ***
22

33
= 7.0.0 - 2022-xx-xx =
4+
* Add - Update Express Checkout section UI.
45
* Add - Auto-complete first and last name on checkout form when using Link payment method.
56
* Add - Allow subscription orders to be paid with Link payment method.
67
* Add - Add inbox notification for Link payment method.
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import { render, screen } from '@testing-library/react';
2+
import userEvent from '@testing-library/user-event';
3+
import PaymentRequestsSettingsSection from '../payment-request-settings-section';
4+
import PaymentRequestButtonPreview from '../payment-request-button-preview';
5+
import {
6+
usePaymentRequestEnabledSettings,
7+
usePaymentRequestLocations,
8+
} from 'wcstripe/data';
9+
10+
jest.mock( 'wcstripe/data', () => ( {
11+
usePaymentRequestEnabledSettings: jest.fn(),
12+
usePaymentRequestLocations: jest.fn(),
13+
usePaymentRequestButtonType: jest.fn().mockReturnValue( [ 'buy' ] ),
14+
usePaymentRequestButtonSize: jest.fn().mockReturnValue( [ 'default' ] ),
15+
usePaymentRequestButtonTheme: jest.fn().mockReturnValue( [ 'dark' ] ),
16+
} ) );
17+
18+
jest.mock( 'wcstripe/data/account/hooks', () => ( {
19+
useAccount: jest.fn().mockReturnValue( { data: {} } ),
20+
} ) );
21+
jest.mock( 'wcstripe/data/account-keys/hooks', () => ( {
22+
useAccountKeys: jest.fn().mockReturnValue( {} ),
23+
useAccountKeysPublishableKey: jest.fn().mockReturnValue( [ '' ] ),
24+
useAccountKeysTestPublishableKey: jest.fn().mockReturnValue( [ '' ] ),
25+
} ) );
26+
27+
jest.mock( '../payment-request-button-preview' );
28+
PaymentRequestButtonPreview.mockImplementation( () => '<></>' );
29+
30+
jest.mock( '../utils/utils', () => ( {
31+
getPaymentRequestData: jest.fn().mockReturnValue( {
32+
publishableKey: 'pk_test_123',
33+
accountId: '0001',
34+
locale: 'en',
35+
} ),
36+
} ) );
37+
38+
const getMockPaymentRequestEnabledSettings = (
39+
isEnabled,
40+
updateIsPaymentRequestEnabledHandler
41+
) => [ isEnabled, updateIsPaymentRequestEnabledHandler ];
42+
43+
const getMockPaymentRequestLocations = (
44+
isCheckoutEnabled,
45+
isProductPageEnabled,
46+
isCartEnabled,
47+
updatePaymentRequestLocationsHandler
48+
) => [
49+
[
50+
isCheckoutEnabled && 'checkout',
51+
isProductPageEnabled && 'product',
52+
isCartEnabled && 'cart',
53+
].filter( Boolean ),
54+
updatePaymentRequestLocationsHandler,
55+
];
56+
57+
describe( 'PaymentRequestsSettingsSection', () => {
58+
beforeEach( () => {
59+
usePaymentRequestEnabledSettings.mockReturnValue(
60+
getMockPaymentRequestEnabledSettings( true, jest.fn() )
61+
);
62+
63+
usePaymentRequestLocations.mockReturnValue(
64+
getMockPaymentRequestLocations( true, true, true, jest.fn() )
65+
);
66+
} );
67+
68+
it( 'should enable express checkout locations when express checkout is enabled', () => {
69+
render( <PaymentRequestsSettingsSection /> );
70+
71+
const [
72+
checkoutCheckbox,
73+
productPageCheckbox,
74+
cartCheckbox,
75+
] = screen.getAllByRole( 'checkbox' );
76+
77+
expect( checkoutCheckbox ).not.toBeDisabled();
78+
expect( checkoutCheckbox ).toBeChecked();
79+
expect( productPageCheckbox ).not.toBeDisabled();
80+
expect( productPageCheckbox ).toBeChecked();
81+
expect( cartCheckbox ).not.toBeDisabled();
82+
expect( cartCheckbox ).toBeChecked();
83+
} );
84+
85+
it( 'should trigger an action to save the checked locations when un-checking the location checkboxes', () => {
86+
const updatePaymentRequestLocationsHandler = jest.fn();
87+
usePaymentRequestEnabledSettings.mockReturnValue( [ true, jest.fn() ] );
88+
usePaymentRequestLocations.mockReturnValue(
89+
getMockPaymentRequestLocations(
90+
true,
91+
true,
92+
true,
93+
updatePaymentRequestLocationsHandler
94+
)
95+
);
96+
97+
render( <PaymentRequestsSettingsSection /> );
98+
99+
// Uncheck each checkbox, and verify them what kind of action should have been called
100+
userEvent.click( screen.getByText( 'Product page' ) );
101+
expect(
102+
updatePaymentRequestLocationsHandler
103+
).toHaveBeenLastCalledWith( [ 'checkout', 'cart' ] );
104+
105+
userEvent.click( screen.getByText( 'Checkout' ) );
106+
expect(
107+
updatePaymentRequestLocationsHandler
108+
).toHaveBeenLastCalledWith( [ 'product', 'cart' ] );
109+
110+
userEvent.click( screen.getByText( 'Cart' ) );
111+
expect(
112+
updatePaymentRequestLocationsHandler
113+
).toHaveBeenLastCalledWith( [ 'checkout', 'product' ] );
114+
} );
115+
116+
it( 'should trigger an action to save the checked locations when checking the location checkboxes', () => {
117+
const updatePaymentRequestLocationsHandler = jest.fn();
118+
usePaymentRequestEnabledSettings.mockReturnValue( [ true, jest.fn() ] );
119+
usePaymentRequestLocations.mockReturnValue(
120+
getMockPaymentRequestLocations(
121+
false,
122+
false,
123+
false,
124+
updatePaymentRequestLocationsHandler
125+
)
126+
);
127+
128+
render( <PaymentRequestsSettingsSection /> );
129+
130+
userEvent.click( screen.getByText( 'Cart' ) );
131+
expect(
132+
updatePaymentRequestLocationsHandler
133+
).toHaveBeenLastCalledWith( [ 'cart' ] );
134+
135+
userEvent.click( screen.getByText( 'Product page' ) );
136+
expect(
137+
updatePaymentRequestLocationsHandler
138+
).toHaveBeenLastCalledWith( [ 'product' ] );
139+
140+
userEvent.click( screen.getByText( 'Checkout' ) );
141+
expect(
142+
updatePaymentRequestLocationsHandler
143+
).toHaveBeenLastCalledWith( [ 'checkout' ] );
144+
} );
145+
} );

client/entrypoints/payment-request-settings/__tests__/payment-request-section.test.js renamed to client/entrypoints/payment-request-settings/__tests__/payment-request-settings.test.js

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import { render, screen } from '@testing-library/react';
22
import userEvent from '@testing-library/user-event';
3-
import PaymentRequestSection from '../payment-request-section';
3+
import PaymentRequestsSettingsSection from '../payment-request-settings-section';
44
import PaymentRequestButtonPreview from '../payment-request-button-preview';
55
import {
6+
usePaymentRequestEnabledSettings,
7+
usePaymentRequestLocations,
68
usePaymentRequestButtonType,
79
usePaymentRequestButtonSize,
810
usePaymentRequestButtonTheme,
911
} from 'wcstripe/data';
1012

1113
jest.mock( 'wcstripe/data', () => ( {
14+
usePaymentRequestEnabledSettings: jest.fn(),
15+
usePaymentRequestLocations: jest.fn(),
1216
usePaymentRequestButtonType: jest.fn().mockReturnValue( [ 'buy' ] ),
1317
usePaymentRequestButtonSize: jest.fn().mockReturnValue( [ 'default' ] ),
1418
usePaymentRequestButtonTheme: jest.fn().mockReturnValue( [ 'dark' ] ),
@@ -33,25 +37,48 @@ jest.mock( '../utils/utils', () => ( {
3337
} ),
3438
} ) );
3539

36-
jest.mock( 'wcstripe/data', () => ( {
37-
usePaymentRequestButtonType: jest.fn().mockReturnValue( [ 'buy' ] ),
38-
usePaymentRequestButtonSize: jest.fn().mockReturnValue( [ 'default' ] ),
39-
usePaymentRequestButtonTheme: jest.fn().mockReturnValue( [ 'dark' ] ),
40-
} ) );
40+
const getMockPaymentRequestEnabledSettings = (
41+
isEnabled,
42+
updateIsPaymentRequestEnabledHandler
43+
) => [ isEnabled, updateIsPaymentRequestEnabledHandler ];
44+
45+
const getMockPaymentRequestLocations = (
46+
isCheckoutEnabled,
47+
isProductPageEnabled,
48+
isCartEnabled,
49+
updatePaymentRequestLocationsHandler
50+
) => [
51+
[
52+
isCheckoutEnabled && 'checkout',
53+
isProductPageEnabled && 'product',
54+
isCartEnabled && 'cart',
55+
].filter( Boolean ),
56+
updatePaymentRequestLocationsHandler,
57+
];
58+
59+
describe( 'PaymentRequestsSettingsSection', () => {
60+
beforeEach( () => {
61+
usePaymentRequestEnabledSettings.mockReturnValue(
62+
getMockPaymentRequestEnabledSettings( true, jest.fn() )
63+
);
64+
65+
usePaymentRequestLocations.mockReturnValue(
66+
getMockPaymentRequestLocations( true, true, true, jest.fn() )
67+
);
68+
} );
4169

42-
describe( 'PaymentRequestSection', () => {
4370
it( 'renders settings with defaults', () => {
44-
render( <PaymentRequestSection /> );
71+
render( <PaymentRequestsSettingsSection /> );
4572

46-
// confirm settings headings
73+
// confirm settings headings.
4774
expect(
4875
screen.queryByRole( 'heading', { name: 'Call to action' } )
4976
).toBeInTheDocument();
5077
expect(
5178
screen.queryByRole( 'heading', { name: 'Appearance' } )
5279
).toBeInTheDocument();
5380

54-
// confirm radio button groups displayed
81+
// confirm radio button groups displayed.
5582
const [ ctaRadio, sizeRadio, themeRadio ] = screen.queryAllByRole(
5683
'radio'
5784
);
@@ -60,7 +87,7 @@ describe( 'PaymentRequestSection', () => {
6087
expect( sizeRadio ).toBeInTheDocument();
6188
expect( themeRadio ).toBeInTheDocument();
6289

63-
// confirm default values
90+
// confirm default values.
6491
expect( screen.getByLabelText( 'Buy' ) ).toBeChecked();
6592
expect( screen.getByLabelText( 'Default (40 px)' ) ).toBeChecked();
6693
expect( screen.getByLabelText( /Dark/ ) ).toBeChecked();
@@ -70,6 +97,7 @@ describe( 'PaymentRequestSection', () => {
7097
const setButtonTypeMock = jest.fn();
7198
const setButtonSizeMock = jest.fn();
7299
const setButtonThemeMock = jest.fn();
100+
73101
usePaymentRequestButtonType.mockReturnValue( [
74102
'buy',
75103
setButtonTypeMock,
@@ -82,8 +110,9 @@ describe( 'PaymentRequestSection', () => {
82110
'dark',
83111
setButtonThemeMock,
84112
] );
113+
usePaymentRequestEnabledSettings.mockReturnValue( [ true, jest.fn() ] );
85114

86-
render( <PaymentRequestSection /> );
115+
render( <PaymentRequestsSettingsSection /> );
87116

88117
expect( setButtonTypeMock ).not.toHaveBeenCalled();
89118
expect( setButtonSizeMock ).not.toHaveBeenCalled();
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { __ } from '@wordpress/i18n';
2+
import React from 'react';
3+
import { Card, CheckboxControl } from '@wordpress/components';
4+
import { usePaymentRequestEnabledSettings } from 'wcstripe/data';
5+
import CardBody from 'wcstripe/settings/card-body';
6+
const PaymentRequestsEnableSection = () => {
7+
const [
8+
isPaymentRequestEnabled,
9+
updateIsPaymentRequestEnabled,
10+
] = usePaymentRequestEnabledSettings();
11+
12+
return (
13+
<Card className="express-checkout-settings">
14+
<CardBody>
15+
<CheckboxControl
16+
checked={ isPaymentRequestEnabled }
17+
onChange={ updateIsPaymentRequestEnabled }
18+
label={ __(
19+
'Enable Apple Pay / Google Pay',
20+
'woocommerce-gateway-stripe'
21+
) }
22+
help={ __(
23+
'When enabled, customers who have configured Apple Pay or Google Pay enabled devices ' +
24+
'will be able to pay with their respective choice of Wallet.',
25+
'woocommerce-gateway-stripe'
26+
) }
27+
/>
28+
</CardBody>
29+
</Card>
30+
);
31+
};
32+
33+
export default PaymentRequestsEnableSection;

client/entrypoints/payment-request-settings/payment-request-page.js

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import { __ } from '@wordpress/i18n';
22
import React from 'react';
3-
import { ExternalLink } from '@wordpress/components';
4-
import PaymentRequestsSection from './payment-request-section';
3+
import PaymentRequestIcon from '../../payment-method-icons/payment-request';
4+
import PaymentRequestsEnableSection from './payment-request-enable-section';
5+
import PaymentRequestsSettingsSection from './payment-request-settings-section';
56
import SettingsSection from 'wcstripe/settings/settings-section';
67
import SettingsLayout from 'wcstripe/settings/settings-layout';
78
import LoadableSettingsSection from 'wcstripe/settings/loadable-settings-section';
89
import SaveSettingsSection from 'wcstripe/settings/save-settings-section';
910
import './style.scss';
1011

11-
const Description = () => (
12+
const EnableDescription = () => (
1213
<>
13-
<h2>
14-
{ __( 'Google Pay / Apple Pay', 'woocommerce-gateway-stripe' ) }
15-
</h2>
14+
<div className="express-checkout-settings__icon">
15+
<PaymentRequestIcon size="medium" />
16+
</div>
1617
<p>
1718
{ __(
1819
'Decide how buttons for digital wallets Apple Pay and ' +
@@ -23,31 +24,33 @@ const Description = () => (
2324
'woocommerce-gateway-stripe'
2425
) }
2526
</p>
27+
</>
28+
);
29+
30+
const SettingsDescription = () => (
31+
<>
32+
<h2>{ __( 'Settings', 'woocommerce-gateway-stripe' ) }</h2>
2633
<p>
27-
<ExternalLink href="https://developer.apple.com/design/human-interface-guidelines/apple-pay/overview/introduction/">
28-
{ __(
29-
'View Apple Pay Guidelines',
30-
'woocommerce-gateway-stripe'
31-
) }
32-
</ExternalLink>
33-
</p>
34-
<p>
35-
<ExternalLink href="https://developers.google.com/pay/api/web/guides/brand-guidelines">
36-
{ __(
37-
'View Google Pay Guidelines',
38-
'woocommerce-gateway-stripe'
39-
) }
40-
</ExternalLink>
34+
{ __(
35+
'Configure the display of Apple Pay and Google Pay buttons on your store.',
36+
'woocommerce-gateway-stripe'
37+
) }
4138
</p>
4239
</>
4340
);
4441

4542
const PaymentRequestsPage = () => {
4643
return (
4744
<SettingsLayout>
48-
<SettingsSection Description={ Description }>
45+
<SettingsSection Description={ EnableDescription }>
46+
<LoadableSettingsSection numLines={ 30 }>
47+
<PaymentRequestsEnableSection />
48+
</LoadableSettingsSection>
49+
</SettingsSection>
50+
51+
<SettingsSection Description={ SettingsDescription }>
4952
<LoadableSettingsSection numLines={ 30 }>
50-
<PaymentRequestsSection />
53+
<PaymentRequestsSettingsSection />
5154
</LoadableSettingsSection>
5255
</SettingsSection>
5356

0 commit comments

Comments
 (0)