Skip to content

Commit

Permalink
Validate PO text fields on change only after blur (Automattic#6430)
Browse files Browse the repository at this point in the history
  • Loading branch information
ismaeldcom authored Jun 2, 2023
1 parent c0f28f0 commit cb9c6e3
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 31 deletions.
5 changes: 5 additions & 0 deletions changelog/update-6407-po-form-validation-on-blur
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Significance: patch
Type: update
Comment: Minor update behind PO feature flag


7 changes: 6 additions & 1 deletion client/components/phone-number-control/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const countryCodes = window.intlTelInputGlobals
interface Props {
value: string;
onChange: ( value: string, country: string ) => void;
onBlur?: () => void;
country?: string;
className?: string;
label?: string;
Expand All @@ -36,6 +37,7 @@ const PhoneNumberControl: React.FC< Props > = ( {
value,
country,
onChange,
onBlur,
...rest
} ) => {
const [ focused, setFocused ] = useState( false );
Expand Down Expand Up @@ -107,7 +109,10 @@ const PhoneNumberControl: React.FC< Props > = ( {
value={ phoneNumber }
onChange={ handleInput }
onFocus={ () => setFocused( true ) }
onBlur={ () => setFocused( false ) }
onBlur={ () => {
setFocused( false );
onBlur?.();
} }
style={ {
paddingLeft: spanWidth + 8,
marginLeft: -spanWidth,
Expand Down
10 changes: 6 additions & 4 deletions client/onboarding-prototype/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const OnboardingTextField: React.FC< OnboardingTextFieldProps > = ( {
name,
...rest
} ) => {
const { data, setData } = useOnboardingContext();
const { data, setData, touched } = useOnboardingContext();
const { validate, error } = useValidation( name );

return (
Expand All @@ -71,8 +71,9 @@ export const OnboardingTextField: React.FC< OnboardingTextFieldProps > = ( {
value={ data[ name ] || '' }
onChange={ ( value: string ) => {
setData( { [ name ]: value } );
validate( value );
if ( touched[ name ] ) validate( value );
} }
onBlur={ () => validate() }
error={ error() }
{ ...rest }
/>
Expand All @@ -88,7 +89,7 @@ export const OnboardingPhoneNumberField: React.FC< OnboardingPhoneNumberFieldPro
name,
...rest
} ) => {
const { data, setData, temp, setTemp } = useOnboardingContext();
const { data, setData, temp, setTemp, touched } = useOnboardingContext();
const { validate, error } = useValidation( name );

return (
Expand All @@ -99,8 +100,9 @@ export const OnboardingPhoneNumberField: React.FC< OnboardingPhoneNumberFieldPro
onChange={ ( value: string, phoneCountryCode: string ) => {
setTemp( { phoneCountryCode } );
setData( { [ name ]: value } );
validate( value );
if ( touched[ name ] ) validate( value );
} }
onBlur={ () => validate() }
error={ error() }
{ ...rest }
/>
Expand Down
102 changes: 76 additions & 26 deletions client/onboarding-prototype/test/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ declare const global: {
let nextStep = jest.fn();
let data = {};
let errors = {};
let touched = {};
let temp = {};

let setData = jest.fn();
Expand All @@ -36,6 +37,7 @@ jest.mock( '../context', () => ( {
useOnboardingContext: jest.fn( () => ( {
data,
errors,
touched,
temp,
setData,
setTouched,
Expand All @@ -61,6 +63,7 @@ describe( 'Progressive Onboarding Prototype Form', () => {
nextStep = jest.fn();
data = {};
errors = {};
touched = {};
temp = {};
setData = jest.fn();
setTouched = jest.fn();
Expand Down Expand Up @@ -123,7 +126,7 @@ describe( 'Progressive Onboarding Prototype Form', () => {
expect( errorMessage ).toBeInTheDocument();
} );

it( 'calls setData and validate on change', () => {
it( 'calls setData on change', () => {
render( <OnboardingTextField name="individual.first_name" /> );

const textField = screen.getByLabelText( 'First name' );
Expand All @@ -132,8 +135,30 @@ describe( 'Progressive Onboarding Prototype Form', () => {
expect( setData ).toHaveBeenCalledWith( {
'individual.first_name': 'John',
} );

expect( validate ).not.toHaveBeenCalled();
} );

it( 'only calls validate on change if touched', () => {
touched = { 'individual.first_name': true };
render( <OnboardingTextField name="individual.first_name" /> );

const textField = screen.getByLabelText( 'First name' );
userEvent.type( textField, 'John' );

expect( validate ).toHaveBeenCalledWith( 'John' );
} );

it( 'calls validate on blur', () => {
render( <OnboardingTextField name="individual.first_name" /> );

const textField = screen.getByLabelText( 'First name' );
userEvent.type( textField, 'John' );
userEvent.tab();
fireEvent.focusOut( textField ); // Workaround for onFocus event not firing with jsdom <16.3.0

expect( validate ).toHaveBeenCalledWith();
} );
} );

describe( 'OnboardingSelectField', () => {
Expand Down Expand Up @@ -172,40 +197,65 @@ describe( 'Progressive Onboarding Prototype Form', () => {
} );
expect( validate ).toHaveBeenCalledWith( 'individual' );
} );
} );

describe( 'OnboardingPhoneNumberField', () => {
it( 'renders component with provided props ', () => {
data = { phone: '+123' };
error.mockReturnValue( 'error message' );

render( <OnboardingPhoneNumberField name="phone" /> );

const textField = screen.getByLabelText(
'What’s your mobile phone number?'
);
const errorMessage = screen.getByText( 'error message' );

expect( textField ).toHaveValue( '23' );
expect( errorMessage ).toBeInTheDocument();
} );

describe( 'OnboardingPhoneNumberField', () => {
it( 'renders component with provided props ', () => {
data = { phone: '+123' };
error.mockReturnValue( 'error message' );
it( 'calls setTemp and setData on change', () => {
render( <OnboardingPhoneNumberField name="phone" /> );

render( <OnboardingPhoneNumberField name="phone" /> );
const textField = screen.getByLabelText(
'What’s your mobile phone number?'
);
userEvent.type( textField, '23' );

const textField = screen.getByLabelText(
'What’s your mobile phone number?'
);
const errorMessage = screen.getByText( 'error message' );
expect( setTemp ).toHaveBeenCalledWith( {
phoneCountryCode: 'US',
} );

expect( textField ).toHaveValue( '23' );
expect( errorMessage ).toBeInTheDocument();
expect( setData ).toHaveBeenCalledWith( {
phone: '+123',
} );
expect( validate ).not.toHaveBeenCalledWith();
} );

it( 'calls setTemp, setData and validate on change', () => {
render( <OnboardingPhoneNumberField name="phone" /> );
it( 'only calls validate on change if touched', () => {
touched = { phone: true };
render( <OnboardingPhoneNumberField name="phone" /> );

const textField = screen.getByLabelText(
'What’s your mobile phone number?'
);
userEvent.type( textField, '23' );
const textField = screen.getByLabelText(
'What’s your mobile phone number?'
);
userEvent.type( textField, '23' );

expect( setTemp ).toHaveBeenCalledWith( {
phoneCountryCode: 'US',
} );
expect( validate ).toHaveBeenCalledWith( '+123' );
} );

expect( setData ).toHaveBeenCalledWith( {
phone: '+123',
} );
expect( validate ).toHaveBeenCalledWith( '+123' );
} );
it( 'calls validate on blur', () => {
render( <OnboardingPhoneNumberField name="phone" /> );

const textField = screen.getByLabelText(
'What’s your mobile phone number?'
);
userEvent.type( textField, '23' );
userEvent.tab();
fireEvent.focusOut( textField ); // Workaround for onFocus event not firing with jsdom <16.3.0

expect( validate ).toHaveBeenCalledWith();
} );
} );
} );

0 comments on commit cb9c6e3

Please sign in to comment.