Prevent prefilling of the billing address with the shipping address in the Checkout block for the Guest Shopper (#44347)
* Clear billing address when useShippingAsBilling checkbox is unchecked * Add billing address sync with server * Add useRef hook to store previous billing address and update sync functions * Add changefile(s) from automation for the following project(s): woocommerce-blocks * Revert "Add useRef hook to store previous billing address and update sync functions" This reverts commit7bc3312ab7
. * Added condition to clear address only for guest users * Add E2E test to check billing address form is empty for Guest shopper * Fix typo * Add changefile(s) from automation for the following project(s): woocommerce-blocks * Updated docs-manifest.json * Revert "Updated docs-manifest.json" This reverts commit20d578a9d6
. * Include company field in the E2E test * Replace beforeAll with beforeEach * Skip country reset to keep consistency with Shortcode Checkout * Remove sync billing address on server * Update E2E test to include the shipping address check * Remove unsed imports * Clear address fields except country and state * Optimize the billing and shipping address check with switch statement --------- Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: Paulo Arromba <17236129+wavvves@users.noreply.github.com>
This commit is contained in:
parent
5ecea1b8c2
commit
506499dec4
|
@ -105,6 +105,37 @@ export const emptyHiddenAddressFields = <
|
|||
return newAddress;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets fields to an empty string in an address.
|
||||
*
|
||||
* @param {Object} address The address to empty fields from.
|
||||
* @return {Object} The address with all fields values removed.
|
||||
*/
|
||||
export const emptyAddressFields = <
|
||||
T extends CartResponseBillingAddress | CartResponseShippingAddress
|
||||
>(
|
||||
address: T
|
||||
): T => {
|
||||
const addressForm = prepareFormFields(
|
||||
ADDRESS_FORM_KEYS,
|
||||
{},
|
||||
address.country
|
||||
);
|
||||
const newAddress = Object.assign( {}, address ) as T;
|
||||
|
||||
addressForm.forEach( ( { key = '' } ) => {
|
||||
// Clear address fields except country and state to keep consistency with shortcode Checkout.
|
||||
if (
|
||||
key !== 'country' &&
|
||||
key !== 'state' &&
|
||||
isValidAddressKey( key, address )
|
||||
) {
|
||||
newAddress[ key ] = '';
|
||||
}
|
||||
} );
|
||||
|
||||
return newAddress;
|
||||
};
|
||||
/*
|
||||
* Formats a shipping address for display.
|
||||
*
|
||||
|
|
|
@ -15,8 +15,11 @@ import {
|
|||
} from '@woocommerce/blocks-components';
|
||||
import Noninteractive from '@woocommerce/base-components/noninteractive';
|
||||
import type { BillingAddress, FormFieldsConfig } from '@woocommerce/settings';
|
||||
import { getSetting } from '@woocommerce/settings';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
import { CART_STORE_KEY } from '@woocommerce/block-data';
|
||||
import { emptyAddressFields } from '@woocommerce/base-utils';
|
||||
import type { CartResponseBillingAddress } from '@woocommerce/types';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -39,10 +42,12 @@ const Block = ( {
|
|||
const {
|
||||
setBillingAddress,
|
||||
shippingAddress,
|
||||
billingAddress,
|
||||
useShippingAsBilling,
|
||||
setUseShippingAsBilling,
|
||||
} = useCheckoutAddress();
|
||||
const { isEditor } = useEditorContext();
|
||||
const isGuest = getSetting( 'currentUserId' ) === 0;
|
||||
|
||||
// Syncs the billing address with the shipping address.
|
||||
const syncBillingWithShipping = () => {
|
||||
|
@ -61,6 +66,18 @@ const Block = ( {
|
|||
setBillingAddress( syncValues );
|
||||
};
|
||||
|
||||
const clearBillingAddress = ( address: BillingAddress ) => {
|
||||
// If the address is empty or the user is not a guest,
|
||||
// we don't need to clear the address.
|
||||
if ( ! address || ! isGuest ) {
|
||||
return;
|
||||
}
|
||||
const emptyAddress = emptyAddressFields(
|
||||
address as CartResponseBillingAddress
|
||||
);
|
||||
setBillingAddress( emptyAddress );
|
||||
};
|
||||
|
||||
// Run this on first render to ensure addresses sync if needed (this is not re-ran when toggling the checkbox).
|
||||
useEffectOnce( () => {
|
||||
if ( useShippingAsBilling ) {
|
||||
|
@ -129,6 +146,8 @@ const Block = ( {
|
|||
setUseShippingAsBilling( checked );
|
||||
if ( checked ) {
|
||||
syncBillingWithShipping();
|
||||
} else {
|
||||
clearBillingAddress( billingAddress );
|
||||
}
|
||||
} }
|
||||
/>
|
||||
|
|
|
@ -474,3 +474,135 @@ test.describe( 'Checkout Form Errors', () => {
|
|||
).toBeVisible();
|
||||
} );
|
||||
} );
|
||||
|
||||
test.describe( 'Billing Address Form', () => {
|
||||
const blockSelectorInEditor = blockData.selectors.editor.block as string;
|
||||
|
||||
// To make sure the company field is visible in the billing address form, we need to enable it in the editor.
|
||||
test.beforeEach( async ( { editor, admin, editorUtils } ) => {
|
||||
await admin.visitSiteEditor( {
|
||||
postId: 'woocommerce/woocommerce//page-checkout',
|
||||
postType: 'wp_template',
|
||||
} );
|
||||
await editorUtils.enterEditMode();
|
||||
await editor.openDocumentSettingsSidebar();
|
||||
await editor.selectBlocks(
|
||||
blockSelectorInEditor +
|
||||
' [data-type="woocommerce/checkout-shipping-address-block"]'
|
||||
);
|
||||
|
||||
const checkbox = editor.page.getByRole( 'checkbox', {
|
||||
name: 'Company',
|
||||
exact: true,
|
||||
} );
|
||||
await checkbox.check();
|
||||
await expect( checkbox ).toBeChecked();
|
||||
await expect(
|
||||
editor.canvas.locator(
|
||||
'div.wc-block-components-address-form__company'
|
||||
)
|
||||
).toBeVisible();
|
||||
await editorUtils.saveSiteEditorEntities();
|
||||
} );
|
||||
|
||||
const shippingTestData = {
|
||||
firstname: 'John',
|
||||
lastname: 'Doe',
|
||||
company: 'Automattic',
|
||||
addressfirstline: '123 Easy Street',
|
||||
addresssecondline: 'Testville',
|
||||
country: 'United States (US)',
|
||||
city: 'New York',
|
||||
state: 'New York',
|
||||
postcode: '90210',
|
||||
phone: '01234567890',
|
||||
};
|
||||
const billingTestData = {
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
company: '',
|
||||
address_1: '',
|
||||
address_2: '',
|
||||
country: 'United States (US)',
|
||||
city: '',
|
||||
state: 'New York',
|
||||
postcode: '',
|
||||
phone: '',
|
||||
};
|
||||
|
||||
test( 'Ensure billing is empty and shipping address is filled for guest user', async ( {
|
||||
frontendUtils,
|
||||
page,
|
||||
checkoutPageObject,
|
||||
} ) => {
|
||||
await frontendUtils.logout();
|
||||
await frontendUtils.emptyCart();
|
||||
await frontendUtils.goToShop();
|
||||
await frontendUtils.addToCart( SIMPLE_PHYSICAL_PRODUCT_NAME );
|
||||
await frontendUtils.goToCheckout();
|
||||
await checkoutPageObject.fillShippingDetails( shippingTestData );
|
||||
await page.getByLabel( 'Use same address for billing' ).uncheck();
|
||||
|
||||
// Check shipping fields are filled.
|
||||
for ( const [ key, value ] of Object.entries( shippingTestData ) ) {
|
||||
// eslint-disable-next-line playwright/no-conditional-in-test
|
||||
switch ( key ) {
|
||||
case 'firstname':
|
||||
await expect(
|
||||
page.locator( '#shipping-first_name' )
|
||||
).toHaveValue( value );
|
||||
break;
|
||||
case 'lastname':
|
||||
await expect(
|
||||
page.locator( '#shipping-last_name' )
|
||||
).toHaveValue( value );
|
||||
break;
|
||||
case 'country':
|
||||
await expect(
|
||||
page.locator( '#shipping-country input' )
|
||||
).toHaveValue( value );
|
||||
break;
|
||||
case 'addressfirstline':
|
||||
await expect(
|
||||
page.locator( '#shipping-address_1' )
|
||||
).toHaveValue( value );
|
||||
break;
|
||||
case 'addresssecondline':
|
||||
await expect(
|
||||
page.locator( '#shipping-address_2' )
|
||||
).toHaveValue( value );
|
||||
break;
|
||||
case 'state':
|
||||
await expect(
|
||||
page.locator( '#shipping-state input' )
|
||||
).toHaveValue( value );
|
||||
break;
|
||||
default:
|
||||
await expect(
|
||||
page.locator( `#shipping-${ key }` )
|
||||
).toHaveValue( value );
|
||||
}
|
||||
}
|
||||
|
||||
// Check billing fields are empty.
|
||||
for ( const [ key, value ] of Object.entries( billingTestData ) ) {
|
||||
// eslint-disable-next-line playwright/no-conditional-in-test
|
||||
switch ( key ) {
|
||||
case 'country':
|
||||
await expect(
|
||||
page.locator( '#billing-country input' )
|
||||
).toHaveValue( value );
|
||||
break;
|
||||
case 'state':
|
||||
await expect(
|
||||
page.locator( '#billing-state input' )
|
||||
).toHaveValue( value );
|
||||
break;
|
||||
default:
|
||||
await expect(
|
||||
page.locator( `#billing-${ key }` )
|
||||
).toHaveValue( value );
|
||||
}
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -68,6 +68,15 @@ export class FrontendUtils {
|
|||
} );
|
||||
}
|
||||
|
||||
async logout() {
|
||||
await this.page.goto( '/my-account', {
|
||||
waitUntil: 'domcontentloaded',
|
||||
} );
|
||||
await this.page.click(
|
||||
'.woocommerce-MyAccount-navigation-link--customer-logout a'
|
||||
);
|
||||
}
|
||||
|
||||
async emptyCart() {
|
||||
const cartResponse = await this.requestUtils.request.get(
|
||||
'/wp-json/wc/store/cart'
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: enhancement
|
||||
|
||||
Prevent prefilling of the billing address with the shipping address in the Checkout block for the Guest Shopper.
|
Loading…
Reference in New Issue