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 commit 7bc3312ab7.

* 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 commit 20d578a9d6.

* 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:
Tarun Vijwani 2024-02-16 16:10:51 +04:00 committed by GitHub
parent 5ecea1b8c2
commit 506499dec4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 195 additions and 0 deletions

View File

@ -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.
*

View File

@ -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 );
}
} }
/>

View File

@ -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 );
}
}
} );
} );

View File

@ -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'

View File

@ -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.