Skip to content

Commit

Permalink
fix: Validate Email field on Blur
Browse files Browse the repository at this point in the history
  • Loading branch information
attiyaIshaque committed Jul 4, 2024
1 parent 6e1644d commit 30e23d9
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 26 deletions.
34 changes: 17 additions & 17 deletions src/forms/fields/email-field/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,10 @@ import messages from './messages';
import validateEmail from './validator';
import { useDispatch, useSelector } from '../../../data/storeHooks';
import { clearRegistrationBackendError, fetchRealtimeValidations } from '../../registration-popup/data/reducers';
import getValidationMessage from '../../reset-password-popup/forgot-password/data/utils';

import './index.scss';

/**
* Email field component. It accepts following handler(s)
* - handleChange for setting value change and
*
* It is responsible for
* - setting value on change
*/
const EmailField = forwardRef((props, ref) => {
const dispatch = useDispatch();
const { formatMessage } = useIntl();
Expand All @@ -36,17 +30,23 @@ const EmailField = forwardRef((props, ref) => {

const validationApiRateLimited = useSelector(state => state.register?.validationApiRateLimited);

const [emailSuggestion, setEmailSuggestion] = useState({ });
const [emailSuggestion, setEmailSuggestion] = useState({});

const handleOnBlur = (e) => {
const { value: fieldValue } = e.target;
const { fieldError, suggestion } = validateEmail(fieldValue, formatMessage);

setEmailSuggestion(suggestion);

if (fieldError) {
handleErrorChange('email', fieldError);
} else if (!validationApiRateLimited && validateEmailFromBackend) {
dispatch(fetchRealtimeValidations({ email: fieldValue }));
if (isRegistration) {
const { fieldError, suggestion } = validateEmail(fieldValue, formatMessage);

setEmailSuggestion(suggestion);

if (fieldError) {
handleErrorChange('email', fieldError);
} else if (!validationApiRateLimited && validateEmailFromBackend) {
dispatch(fetchRealtimeValidations({ email: fieldValue }));
}
} else {
const error = getValidationMessage(fieldValue, formatMessage);
handleErrorChange('email', error);
}
};

Expand Down Expand Up @@ -116,7 +116,7 @@ const EmailField = forwardRef((props, ref) => {
onBlur={handleOnBlur}
onFocus={handleOnFocus}
floatingLabel={floatingLabel}
ref={ref} // Forwarding the ref here
ref={ref}
/>

{errorMessage !== '' && (
Expand Down
23 changes: 23 additions & 0 deletions src/forms/fields/email-field/index.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import configureStore from 'redux-mock-store';

import { AuthnContext } from '../../../data/storeHooks';
import { clearRegistrationBackendError, fetchRealtimeValidations } from '../../registration-popup/data/reducers';
import getValidationMessage from '../../reset-password-popup/forgot-password/data/utils';
import { EmailField } from '../index';

const IntlEmailField = injectIntl(EmailField);
Expand All @@ -28,6 +29,7 @@ jest.mock('react-router-dom', () => {
mockNavigate: mockNavigation,
};
});
jest.mock('../../reset-password-popup/forgot-password/data/utils', () => jest.fn());

describe('EmailField', () => {
let props = {};
Expand Down Expand Up @@ -217,5 +219,26 @@ describe('EmailField', () => {
const closedSuggestionText = container.querySelector('.alert-danger');
expect(closedSuggestionText).toBeNull();
});

it('should use getValidationMessage for email validation in non-registration context', () => {
const mockValidationMessage = 'Enter a valid email address';
getValidationMessage.mockReturnValue(mockValidationMessage);

props.isRegistration = false;

const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));

const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'invalidemail', name: 'email' } });

expect(getValidationMessage).toHaveBeenCalledTimes(1);
expect(getValidationMessage).toHaveBeenCalledWith('invalidemail', expect.any(Function));

expect(props.handleErrorChange).toHaveBeenCalledTimes(1);
expect(props.handleErrorChange).toHaveBeenCalledWith(
'email',
mockValidationMessage,
);
});
});
});
16 changes: 7 additions & 9 deletions src/forms/reset-password-popup/forgot-password/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,14 @@ import { setCurrentOpenedForm } from '../../../authn-component/data/reducers';
import { InlineLink } from '../../../common-ui';
import { COMPLETE_STATE, DEFAULT_STATE, LOGIN_FORM } from '../../../data/constants';
import { useDispatch, useSelector } from '../../../data/storeHooks';
import {
trackForgotPasswordPageEvent,
trackForgotPasswordPageViewed,
} from '../../../tracking/trackers/forgotpassword';
import { trackForgotPasswordPageEvent, trackForgotPasswordPageViewed } from '../../../tracking/trackers/forgotpassword';
import EmailField from '../../fields/email-field';
import { NUDGE_PASSWORD_CHANGE, REQUIRE_PASSWORD_CHANGE } from '../../login-popup/data/constants';
import { loginErrorClear } from '../../login-popup/data/reducers';
import messages from '../messages';
import ResetPasswordHeader from '../ResetPasswordHeader';
import '../index.scss';

/**
* ForgotPasswordForm component for handling user password reset.
* This component provides a form for users to reset their password by entering their email.
*/
const ForgotPasswordForm = () => {
const { formatMessage } = useIntl();
const dispatch = useDispatch();
Expand All @@ -53,6 +46,9 @@ const ForgotPasswordForm = () => {
const value = event.target.type === 'checkbox' ? event.target.checked : event.target.value;
setFormFields(prevState => ({ ...prevState, [name]: value }));
};
const handleErrorChange = (fieldName, error) => {
setFormErrors(error);
};

const backToLogin = (e) => {
e.preventDefault();
Expand Down Expand Up @@ -110,7 +106,8 @@ const ForgotPasswordForm = () => {
aria-live="assertive"
ref={nudgePasswordChangeRef}
data-testid="nudge-password-change-message"
>{formatMessage(messages.vulnerablePasswordWarnedMessage)}
>
{formatMessage(messages.vulnerablePasswordWarnedMessage)}
</p>
)}
{!isSuccess && (
Expand All @@ -119,6 +116,7 @@ const ForgotPasswordForm = () => {
name="email"
value={formFields.email}
handleChange={handleOnChange}
handleErrorChange={handleErrorChange}
autoComplete="email"
errorMessage={formErrors}
floatingLabel={formatMessage(messages.forgotPasswordFormEmailFieldLabel)}
Expand Down

0 comments on commit 30e23d9

Please sign in to comment.