Migrate StateInput, CountryInput and custom fields to native `<select>` (#48180)

This commit is contained in:
Sam Seay 2024-07-13 05:17:54 +08:00 committed by GitHub
parent c31e274616
commit 9fa32b4f2b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 338 additions and 131 deletions

View File

@ -33,9 +33,9 @@ import { AddressFormProps, AddressFormFields } from './types';
import prepareFormFields from './prepare-form-fields';
import validateShippingCountry from './validate-shipping-country';
import customValidationHandler from './custom-validation-handler';
import Combobox from '../../combobox';
import AddressLineFields from './address-line-fields';
import { createFieldProps, getFieldData } from './utils';
import { Select } from '../../select';
/**
* Checkout form.
@ -228,9 +228,10 @@ const Form = < T extends AddressFormValues | ContactFormValues >( {
}
return (
<Combobox
<Select
key={ field.key }
{ ...fieldProps }
label={ fieldProps.label || '' }
className={ clsx(
'wc-block-components-select-input',
`wc-block-components-select-input-${ field.key }`.replaceAll(

View File

@ -46,7 +46,7 @@ const primaryAddress = {
};
const secondaryAddress = {
country: 'Austria', // We use Austria because it doesn't have states.
countryKey: 'AU',
countryKey: 'AT',
city: 'Vienna',
postcode: 'DCBA',
};
@ -57,23 +57,29 @@ const tertiaryAddress = {
state: 'Ontario',
postcode: 'EFGH',
};
const quaternaryAddress = {
country: 'Japan',
countryKey: 'JP',
city: 'Tokyo',
postcode: 'IJKL',
};
const countryRegExp = /country/i;
const cityRegExp = /city/i;
const stateRegExp = /county|province|state/i;
const postalCodeRegExp = /postal code|postcode|zip/i;
const inputAddress = async ( {
country = null,
countryKey = null,
city = null,
state = null,
postcode = null,
} ) => {
if ( country ) {
const countryInput = screen.queryByRole( 'combobox', {
name: countryRegExp,
} );
await userEvent.type( countryInput, country + '{arrowdown}{enter}' );
if ( countryKey ) {
const countryInput = screen.getByLabelText( 'Country/Region' );
if ( countryInput ) {
await userEvent.selectOptions( countryInput, countryKey );
}
}
if ( city ) {
const cityInput = screen.getByLabelText( cityRegExp );
@ -81,15 +87,12 @@ const inputAddress = async ( {
}
if ( state ) {
const stateButton = screen.queryByRole( 'combobox', {
name: stateRegExp,
const stateButton = screen.queryByLabelText( stateRegExp, {
selector: 'select',
} );
// State input might be a select or a text input.
if ( stateButton ) {
await userEvent.click( stateButton );
await userEvent.click(
screen.getByRole( 'option', { name: state } )
);
await userEvent.selectOptions( stateButton, state );
} else {
const stateInput = screen.getByLabelText( stateRegExp );
await userEvent.type( stateInput, state );
@ -182,24 +185,16 @@ describe( 'Form Component', () => {
it( 'input values are reset after changing the country', async () => {
renderInCheckoutProvider( <WrappedAddressForm type="shipping" /> );
// First enter an address with no state, but fill the city.
await act( async () => {
await inputAddress( secondaryAddress );
} );
// Only update `country` to verify other values are reset.
// Update country to another country without state.
await act( async () => {
await inputAddress( { country: primaryAddress.country } );
await inputAddress( { countryKey: quaternaryAddress.countryKey } );
} );
expect( screen.getByLabelText( stateRegExp ).value ).toBe( '' );
// Repeat the test with an address which has a select for the state.
await act( async () => {
await inputAddress( tertiaryAddress );
} );
await act( async () => {
await inputAddress( { country: primaryAddress.country } );
} );
expect( screen.getByLabelText( stateRegExp ).value ).toBe( '' );
expect( screen.getByLabelText( postalCodeRegExp ).value ).toBe( '' );
} );
} );

View File

@ -10,7 +10,10 @@ import CountryInput from './country-input';
import type { CountryInputProps } from './CountryInputProps';
const BillingCountryInput = ( props: CountryInputProps ): JSX.Element => {
return <CountryInput countries={ ALLOWED_COUNTRIES } { ...props } />;
// TODO - are errorMessage and errorId still relevant when select always has a value?
const { errorMessage: _, errorId: __, ...restOfProps } = props;
return <CountryInput countries={ ALLOWED_COUNTRIES } { ...restOfProps } />;
};
export default BillingCountryInput;

View File

@ -2,16 +2,15 @@
* External dependencies
*/
import { useMemo } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { decodeEntities } from '@wordpress/html-entities';
import clsx from 'clsx';
/**
* Internal dependencies
*/
import Combobox from '../combobox';
import './style.scss';
import type { CountryInputWithCountriesProps } from './CountryInputProps';
import { Select } from '../select';
export const CountryInput = ( {
className,
@ -22,8 +21,6 @@ export const CountryInput = ( {
value = '',
autoComplete = 'off',
required = false,
errorId,
errorMessage = __( 'Please select a country', 'woocommerce' ),
}: CountryInputWithCountriesProps ): JSX.Element => {
const options = useMemo(
() =>
@ -40,14 +37,12 @@ export const CountryInput = ( {
<div
className={ clsx( className, 'wc-block-components-country-input' ) }
>
<Combobox
<Select
id={ id }
label={ label }
label={ label || '' }
onChange={ onChange }
options={ options }
value={ value }
errorId={ errorId }
errorMessage={ errorMessage }
required={ required }
autoComplete={ autoComplete }
/>

View File

@ -23,6 +23,7 @@ export * from './product-rating';
export * from './quantity-selector';
export * from './read-more';
export * from './reviews';
export * from './select';
export * from './sidebar-layout';
export * from './snackbar-list';
export * from './state-input';

View File

@ -0,0 +1,71 @@
/**
* External dependencies
*/
import { Icon, chevronDown } from '@wordpress/icons';
import { useCallback, useId } from '@wordpress/element';
/**
* Internal dependencies
*/
import './style.scss';
type SelectProps = Omit<
React.SelectHTMLAttributes< HTMLSelectElement >,
'onChange'
> & {
options: { value: string; label: string }[];
label: string;
onChange: ( newVal: string ) => void;
};
export const Select = ( props: SelectProps ) => {
const { onChange, options, label, value, className, size, ...restOfProps } =
props;
const selectOnChange = useCallback(
( event: React.ChangeEvent< HTMLSelectElement > ) => {
onChange( event.target.value );
},
[ onChange ]
);
const generatedId = useId();
const inputId =
restOfProps.id || `wc-blocks-components-select-${ generatedId }`;
return (
<div className={ `wc-blocks-components-select ${ className || '' }` }>
<div className="wc-blocks-components-select__container">
<label
htmlFor={ inputId }
className="wc-blocks-components-select__label"
>
{ label }
</label>
<select
className="wc-blocks-components-select__select"
id={ inputId }
size={ size !== undefined ? size : 1 }
onChange={ selectOnChange }
value={ value }
{ ...restOfProps }
>
{ options.map( ( option ) => (
<option
key={ option.value }
value={ option.value }
data-alternate-values={ `[${ option.label }]` }
>
{ option.label }
</option>
) ) }
</select>
<Icon
className="wc-blocks-components-select__expand"
icon={ chevronDown }
/>
</div>
</div>
);
};

View File

@ -0,0 +1,78 @@
.wc-blocks-components-select {
width: 100%;
.wc-blocks-components-select__container {
border-radius: $universal-border-radius;
box-sizing: border-box;
border: 1px solid $universal-border-light;
background: #fff;
width: 100%;
height: 50px;
position: relative;
.has-dark-controls & {
background-color: $input-background-dark;
border-color: $input-border-dark;
color: $input-text-dark;
&:focus {
background-color: $input-background-dark;
color: $input-text-dark;
box-shadow: 0 0 0 2px $input-border-gray;
}
}
}
.wc-blocks-components-select__select {
@include reset-typography();
@include font-size(regular);
border-radius: $universal-border-radius;
width: 100%;
height: 100%;
appearance: none;
background: none;
padding: em($gap) em($gap-smaller) 0;
color: currentColor;
&:focus {
outline: 0;
box-shadow: 0 0 0 1px currentColor;
}
}
.wc-blocks-components-select__label {
@include reset-typography();
@include font-size(regular);
position: absolute;
line-height: 1.25; // =20px when font-size is 16px.
left: em($gap-smaller);
top: 0;
transform-origin: top left;
transition: all 200ms ease;
color: currentColor;
z-index: 1;
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
max-width: calc(100% - #{2 * $gap});
white-space: nowrap;
.has-dark-controls & {
color: $input-placeholder-dark;
}
@media screen and (prefers-reduced-motion: reduce) {
transition: none;
}
transform: translateY(15%) scale(0.75);
}
.wc-blocks-components-select__expand {
position: absolute;
transform: translate(0%, -50%);
top: 50%;
right: $gap-small;
pointer-events: none;
fill: currentColor;
}
}

View File

@ -10,7 +10,10 @@ import StateInput from './state-input';
import type { StateInputProps } from './StateInputProps';
const BillingStateInput = ( props: StateInputProps ): JSX.Element => {
return <StateInput states={ ALLOWED_STATES } { ...props } />;
// TODO - are errorMessage and errorId still relevant when select always has a value?
const { errorMessage: _, errorId: __, ...restOfProps } = props;
return <StateInput states={ ALLOWED_STATES } { ...restOfProps } />;
};
export default BillingStateInput;

View File

@ -1,18 +1,16 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { decodeEntities } from '@wordpress/html-entities';
import { useCallback, useMemo, useEffect, useRef } from '@wordpress/element';
import clsx from 'clsx';
import { ValidatedTextInput } from '@woocommerce/blocks-components';
/**
* Internal dependencies
*/
import Combobox from '../combobox';
import './style.scss';
import type { StateInputWithStatesProps } from './StateInputProps';
import { Select } from '../select';
const optionMatcher = (
value: string,
@ -36,7 +34,6 @@ const StateInput = ( {
autoComplete = 'off',
value = '',
required = false,
errorId = '',
}: StateInputWithStatesProps ): JSX.Element => {
const countryStates = states[ country ];
const options = useMemo(
@ -91,20 +88,17 @@ const StateInput = ( {
if ( options.length > 0 ) {
return (
<Combobox
className={ clsx(
className,
'wc-block-components-state-input'
) }
id={ id }
label={ label }
onChange={ onChangeState }
<Select
options={ options }
label={ label || '' }
className={ `wc-block-components-state-input ${
className || ''
}` }
id={ id }
onChange={ onChangeState }
value={ value }
errorMessage={ __( 'Please select a state.', 'woocommerce' ) }
errorId={ errorId }
required={ required }
autoComplete={ autoComplete }
required={ required }
/>
);
}

View File

@ -1,3 +1,3 @@
.wc-block-components-state-input {
.wc-blocks-components-select__container {
margin-top: $gap;
}

View File

@ -14,8 +14,7 @@ class AddSplitChunkDependencies {
apply( compiler ) {
compiler.hooks.thisCompilation.tap(
'AddStableChunksToAssets',
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- not used.
( compilation, callback ) => {
( compilation ) => {
compilation.hooks.processAssets.tap(
{
name: 'AddStableChunksToAssets',

View File

@ -330,8 +330,7 @@ const getFrontConfig = ( options = {} ) => {
// translations which we must avoid.
// @see https://github.com/Automattic/jetpack/pull/20926
chunkFilename: `[name]-frontend${ fileSuffix }.js?ver=[contenthash]`,
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- not used.
filename: ( pathData ) => {
filename: () => {
return `[name]-frontend${ fileSuffix }.js`;
},
uniqueName: 'webpackWcBlocksFrontendJsonp',

View File

@ -76,11 +76,6 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
'Please enter a valid government id'
)
).toBeVisible();
await expect(
checkoutPageObject.page.getByText(
'Please select a valid option'
)
).toBeVisible();
} );
test( 'Shopper can fill in the checkout form with additional fields and can have different value for same field in shipping and billing address', async ( {
@ -122,13 +117,13 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
name: 'Shipping address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'wide' );
.selectOption( 'wide' );
await checkoutPageObject.page
.getByRole( 'group', {
name: 'Billing address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'narrow' );
.selectOption( 'narrow' );
await checkoutPageObject.page.evaluate(
'document.activeElement.blur()'
@ -217,7 +212,7 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
.getByLabel(
'Is this a personal purchase or a business purchase?'
)
).toHaveValue( 'Business' );
).toHaveValue( 'business' );
await expect(
checkoutPageObject.page
.getByRole( 'group', {
@ -252,7 +247,7 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
name: 'Shipping address',
} )
.getByLabel( 'How wide is your road?' )
).toHaveValue( 'Wide' );
).toHaveValue( 'wide' );
await expect(
checkoutPageObject.page
.getByRole( 'group', {
@ -280,7 +275,7 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
name: 'Billing address',
} )
.getByLabel( 'How wide is your road?' )
).toHaveValue( 'Narrow' );
).toHaveValue( 'narrow' );
} );
} );
} );

View File

@ -70,13 +70,13 @@ test.describe( 'Merchant → Additional Checkout Fields', () => {
name: 'Shipping address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'wide' );
.selectOption( 'wide' );
await checkoutPageObject.page
.getByRole( 'group', {
name: 'Billing address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'narrow' );
.selectOption( 'narrow' );
await checkoutPageObject.page.evaluate(
'document.activeElement.blur()'
@ -206,13 +206,13 @@ test.describe( 'Merchant → Additional Checkout Fields', () => {
name: 'Shipping address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'wide' );
.selectOption( 'wide' );
await checkoutPageObject.page
.getByRole( 'group', {
name: 'Billing address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'narrow' );
.selectOption( 'narrow' );
await checkoutPageObject.page.evaluate(
'document.activeElement.blur()'

View File

@ -73,13 +73,13 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
name: 'Shipping address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'wide' );
.selectOption( 'wide' );
await checkoutPageObject.page
.getByRole( 'group', {
name: 'Billing address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'narrow' );
.selectOption( 'narrow' );
await checkoutPageObject.page.evaluate(
'document.activeElement.blur()'
@ -155,7 +155,7 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
.getByLabel(
'Is this a personal purchase or a business purchase?'
)
).toHaveValue( 'Business' );
).toHaveValue( 'business' );
await expect(
checkoutPageObject.page
.getByRole( 'group', {
@ -190,7 +190,7 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
name: 'Shipping address',
} )
.getByLabel( 'How wide is your road?' )
).toHaveValue( 'Wide' );
).toHaveValue( 'wide' );
await expect(
checkoutPageObject.page
.getByRole( 'group', {
@ -218,7 +218,7 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
name: 'Billing address',
} )
.getByLabel( 'How wide is your road?' )
).toHaveValue( 'Narrow' );
).toHaveValue( 'narrow' );
} );
test( 'Shopper can change the values of fields multiple times and place the order', async ( {
@ -261,13 +261,13 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
name: 'Shipping address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'wide' );
.selectOption( 'wide' );
await checkoutPageObject.page
.getByRole( 'group', {
name: 'Billing address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'narrow' );
.selectOption( 'narrow' );
await checkoutPageObject.waitForCustomerDataUpdate();
// Change the shipping and billing select fields again.
@ -276,13 +276,13 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
name: 'Billing address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'wide' );
.selectOption( 'wide' );
await checkoutPageObject.page
.getByRole( 'group', {
name: 'Shipping address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'super-wide' );
.selectOption( 'super-wide' );
await checkoutPageObject.waitForCustomerDataUpdate();
await checkoutPageObject.page
@ -354,11 +354,9 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
.getByRole( 'group', {
name: 'Additional order information',
} )
.locator(
'ul.components-form-token-field__suggestions-list > li'
)
.locator( 'select' )
.first()
.click();
.selectOption( { index: 0 } );
await checkoutPageObject.waitForCustomerDataUpdate();
await checkoutPageObject.placeOrder();
@ -445,13 +443,13 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
name: 'Shipping address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'wide' );
.selectOption( 'wide' );
await checkoutPageObject.page
.getByRole( 'group', {
name: 'Billing address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'narrow' );
.selectOption( 'narrow' );
await checkoutPageObject.page.evaluate(
'document.activeElement.blur()'
@ -527,7 +525,7 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
.getByLabel(
'Is this a personal purchase or a business purchase?'
)
).toHaveValue( 'Business' );
).toHaveValue( 'business' );
await expect(
checkoutPageObject.page
.getByRole( 'group', {
@ -562,7 +560,7 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
name: 'Shipping address',
} )
.getByLabel( 'How wide is your road?' )
).toHaveValue( 'Wide' );
).toHaveValue( 'wide' );
await expect(
checkoutPageObject.page
.getByRole( 'group', {
@ -590,7 +588,7 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
name: 'Billing address',
} )
.getByLabel( 'How wide is your road?' )
).toHaveValue( 'Narrow' );
).toHaveValue( 'narrow' );
} );
test( 'Shopper can see server-side validation errors', async ( {
@ -682,13 +680,13 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
name: 'Shipping address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'wide' );
.selectOption( 'wide' );
await checkoutPageObject.page
.getByRole( 'group', {
name: 'Billing address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'narrow' );
.selectOption( 'narrow' );
await checkoutPageObject.page.evaluate(
'document.activeElement.blur()'
);
@ -766,13 +764,13 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
name: 'Shipping address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'wide' );
.selectOption( 'wide' );
await checkoutPageObject.page
.getByRole( 'group', {
name: 'Billing address',
} )
.getByLabel( 'How wide is your road?' )
.fill( 'narrow' );
.selectOption( 'narrow' );
// Blur after editing the select fields since they need to be blurred to save.
await checkoutPageObject.page.evaluate(
@ -925,7 +923,7 @@ test.describe( 'Shopper → Additional Checkout Fields', () => {
await govIdInput.fill( '11111' );
await confirmGovIdInput.fill( '11111' );
await shippingTruckFittingCheckbox.uncheck();
await shippingRoadSizeSelect.selectOption( 'Narrow' );
await shippingRoadSizeSelect.selectOption( 'narrow' );
await checkoutPageObject.page.getByText( 'Save address' ).click();
// Check the updated values are visible in the addresses.

View File

@ -228,6 +228,7 @@ test.describe( 'Shopper → Shipping and Billing Addresses', () => {
city: 'San Francisco',
state: 'California',
country: 'United Kingdom',
countryKey: 'GB',
postcode: 'SW1 1AA',
phone: '123456789',
email: 'john.doe@example.com',
@ -241,6 +242,7 @@ test.describe( 'Shopper → Shipping and Billing Addresses', () => {
city: 'Los Angeles',
phone: '987654321',
country: 'Albania',
countryKey: 'AL',
state: 'Berat',
postcode: '1234',
};
@ -349,7 +351,7 @@ test.describe( 'Shopper → Shipping (customer user)', () => {
lastname: 'Perez',
addressfirstline: '123 Test Street',
addresssecondline: 'Apartment 6',
country: 'ES',
countryKey: 'ES',
city: 'Madrid',
postcode: '08830',
state: 'M',
@ -546,6 +548,7 @@ test.describe( 'Billing Address Form', () => {
addressfirstline: '123 Easy Street',
addresssecondline: 'Testville',
country: 'United States (US)',
countryKey: 'US',
city: 'New York',
state: 'New York',
postcode: '90210',
@ -571,14 +574,14 @@ test.describe( 'Billing Address Form', () => {
shippingForm.getByLabel( 'Apartment, suite, etc. (optional)' )
).toHaveValue( 'Testville' );
await expect(
shippingForm.getByLabel( 'United States (US), Country/' )
).toHaveValue( 'United States (US)' );
shippingForm.getByLabel( 'Country/Region' )
).toHaveValue( 'US' );
await expect( shippingForm.getByLabel( 'City' ) ).toHaveValue(
'New York'
);
await expect(
shippingForm.getByLabel( 'New York, State' )
).toHaveValue( 'New York' );
await expect( shippingForm.getByLabel( 'State' ) ).toHaveValue(
'NY'
);
await expect( shippingForm.getByLabel( 'ZIP Code' ) ).toHaveValue(
'90210'
);
@ -605,12 +608,12 @@ test.describe( 'Billing Address Form', () => {
} )
).toBeVisible();
await expect(
billingForm.getByLabel( 'United States (US), Country/' )
).toHaveValue( 'United States (US)' );
billingForm.getByLabel( 'Country/Region' )
).toHaveValue( 'US' );
await expect( billingForm.getByLabel( 'City' ) ).toHaveValue( '' );
await expect(
billingForm.getByLabel( 'New York, State' )
).toHaveValue( 'New York' );
await expect( billingForm.getByLabel( 'State' ) ).toHaveValue(
'NY'
);
await expect( billingForm.getByLabel( 'ZIP Code' ) ).toHaveValue(
''
);

View File

@ -23,6 +23,7 @@ export class CheckoutPage {
addressfirstline: '123 Easy Street',
addresssecondline: 'Testville',
country: 'United States (US)',
countryKey: 'US',
city: 'New York',
state: 'New York',
postcode: '90210',
@ -124,7 +125,16 @@ export class CheckoutPage {
// Rest of additional data passed in from the overrideData object.
for ( const [ label, value ] of Object.entries( additionalFields ) ) {
const field = contactSection.getByLabel( label );
await field.fill( value );
const tagName = await field.evaluate( ( element ) =>
element.tagName.toLowerCase()
);
if ( tagName === 'select' ) {
await field.selectOption( value );
} else {
await field.fill( value );
}
}
}
@ -138,7 +148,16 @@ export class CheckoutPage {
// Rest of additional data passed in from the overrideData object.
for ( const [ label, value ] of Object.entries( additionalFields ) ) {
const field = contactSection.getByLabel( label );
await field.fill( value );
const tagName = await field.evaluate( ( element ) =>
element.tagName.toLowerCase()
);
if ( tagName === 'select' ) {
await field.selectOption( value );
} else {
await field.fill( value );
}
}
}
@ -151,7 +170,16 @@ export class CheckoutPage {
// Rest of additional data passed in from the overrideData object.
for ( const { label, value } of additionalFields ) {
const field = this.page.getByLabel( label );
await field.fill( value );
const tagName = await field.evaluate( ( element ) =>
element.tagName.toLowerCase()
);
if ( tagName === 'select' ) {
await field.selectOption( value );
} else {
await field.fill( value );
}
}
}
@ -337,7 +365,7 @@ export class CheckoutPage {
await email.fill( customerBillingDetails.email );
await firstName.fill( customerBillingDetails.firstname );
await lastName.fill( customerBillingDetails.lastname );
await country.fill( customerBillingDetails.country );
await country.selectOption( customerBillingDetails.countryKey );
await address1.fill( customerBillingDetails.addressfirstline );
if ( customerBillingDetails.addresssecondline ) {
@ -360,10 +388,17 @@ export class CheckoutPage {
} );
const county = billingForm.getByLabel( 'County' );
await state
.or( province )
.or( county )
.fill( customerBillingDetails.state );
const elementToFill = state.or( province ).or( county );
const tagName = await elementToFill.evaluate( ( element ) =>
element.tagName.toLowerCase()
);
if ( tagName === 'select' ) {
await elementToFill.selectOption(
customerBillingDetails.state
);
} else {
await elementToFill.fill( customerBillingDetails.state );
}
}
if ( customerBillingDetails.postcode ) {
@ -376,7 +411,16 @@ export class CheckoutPage {
// Rest of additional data passed in from the overrideData object.
for ( const [ label, value ] of Object.entries( additionalFields ) ) {
const field = billingForm.getByLabel( label, { exact: true } );
await field.fill( value );
const tagName = await field.evaluate( ( element ) =>
element.tagName.toLowerCase()
);
if ( tagName === 'select' ) {
await field.selectOption( value );
} else {
await field.fill( value );
}
}
}
@ -407,7 +451,7 @@ export class CheckoutPage {
await firstName.fill( customerShippingDetails.firstname );
await lastName.fill( customerShippingDetails.lastname );
await country.fill( customerShippingDetails.country );
await country.selectOption( customerShippingDetails.country );
await address1.fill( customerShippingDetails.addressfirstline );
if ( customerShippingDetails.addresssecondline ) {
@ -430,10 +474,17 @@ export class CheckoutPage {
} );
const county = shippingForm.getByLabel( 'County' );
await state
.or( province )
.or( county )
.fill( customerShippingDetails.state );
const elementToFill = state.or( province ).or( county );
const tagName = await elementToFill.evaluate( ( element ) =>
element.tagName.toLowerCase()
);
if ( tagName === 'select' ) {
await elementToFill.selectOption(
customerShippingDetails.state
);
} else {
await elementToFill.fill( customerShippingDetails.state );
}
}
if ( customerShippingDetails.postcode ) {
@ -446,7 +497,16 @@ export class CheckoutPage {
// Rest of additional data passed in from the overrideData object.
for ( const [ label, value ] of Object.entries( additionalFields ) ) {
const field = shippingForm.getByLabel( label, { exact: true } );
await field.fill( value );
const tagName = await field.evaluate( ( element ) =>
element.tagName.toLowerCase()
);
if ( tagName === 'select' ) {
await field.selectOption( value );
} else {
await field.fill( value );
}
}
// Blur active field to trigger customer address update.

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Migrate the cart and checkout block's state, country and custom field input to a native select

View File

@ -142,7 +142,10 @@ test.describe(
// Set shipping country to Netherlands
await page.getByLabel( 'Add an address for shipping' ).click();
await page.getByRole( 'combobox' ).first().fill( 'Netherlands' );
await page
.getByRole( 'combobox' )
.first()
.selectOption( 'Netherlands' );
await page.getByLabel( 'Postal code' ).fill( '1011AA' );
await page.getByLabel( 'City' ).fill( 'Amsterdam' );
await page.getByRole( 'button', { name: 'Update' } ).click();
@ -171,7 +174,10 @@ test.describe(
// Set shipping country to Portugal
await page.getByLabel( 'Add an address for shipping' ).click();
await page.getByRole( 'combobox' ).first().fill( 'Portugal' );
await page
.getByRole( 'combobox' )
.first()
.selectOption( 'Portugal' );
await page.getByLabel( 'Postal code' ).fill( '1000-001' );
await page.getByLabel( 'City' ).fill( 'Lisbon' );
await page.getByRole( 'button', { name: 'Update' } ).click();
@ -207,7 +213,10 @@ test.describe(
// Set shipping country to Portugal
await page.getByLabel( 'Add an address for shipping' ).click();
await page.getByRole( 'combobox' ).first().fill( 'Portugal' );
await page
.getByRole( 'combobox' )
.first()
.selectOption( 'Portugal' );
await page.getByLabel( 'Postal code' ).fill( '1000-001' );
await page.getByLabel( 'City' ).fill( 'Lisbon' );
await page.getByRole( 'button', { name: 'Update' } ).click();
@ -238,7 +247,10 @@ test.describe(
// Set shipping country to Portugal
await page.getByLabel( 'Add an address for shipping' ).click();
await page.getByRole( 'combobox' ).first().fill( 'Portugal' );
await page
.getByRole( 'combobox' )
.first()
.selectOption( 'Portugal' );
await page.getByLabel( 'Postal code' ).fill( '1000-001' );
await page.getByLabel( 'City' ).fill( 'Lisbon' );
await page.getByRole( 'button', { name: 'Update' } ).click();

View File

@ -376,12 +376,8 @@ test.describe(
await expect(
page.getByText( '+ Add apartment, suite, etc.' )
).toBeEnabled();
await expect(
page.getByLabel( 'United States (US), Country/Region' )
).toBeEditable();
await expect(
page.getByLabel( 'California, State' )
).toBeEditable();
await expect( page.getByLabel( 'Country/Region' ) ).toBeEnabled();
await expect( page.getByLabel( 'State' ) ).toBeEnabled();
await expect( page.getByLabel( 'City' ) ).toBeEditable();
await expect( page.getByLabel( 'ZIP Code' ) ).toBeEnabled();
await expect(