Skip to content

Commit 41a9c89

Browse files
fix: password validation with correct password value on icon blur (#1054)
1 parent d469102 commit 41a9c89

File tree

4 files changed

+48
-36
lines changed

4 files changed

+48
-36
lines changed

src/common-components/PasswordField.jsx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,33 @@ const PasswordField = (props) => {
2424
const [showTooltip, setShowTooltip] = useState(false);
2525

2626
const handleBlur = (e) => {
27-
if (e.target?.name === 'password' && e.relatedTarget?.name === 'passwordIcon') {
28-
return; // Do not validations on password icon click
27+
const { name, value } = e.target;
28+
if (name === props.name && e.relatedTarget?.name === 'passwordIcon') {
29+
return; // Do not run validations on password icon click
30+
}
31+
32+
let passwordValue = value;
33+
if (name === 'passwordIcon') {
34+
// To validate actual password value when onBlur is triggered by focusing out the password icon
35+
passwordValue = props.value;
36+
}
37+
38+
if (props.handleBlur) {
39+
props.handleBlur({
40+
target: {
41+
name: props.name,
42+
value: passwordValue,
43+
},
44+
});
2945
}
3046

31-
if (props.handleBlur) { props.handleBlur(e); }
3247
setShowTooltip(props.showRequirements && false);
3348
if (props.handleErrorChange) { // If rendering from register page
34-
const fieldError = validatePasswordField(e.target.value, formatMessage);
49+
const fieldError = validatePasswordField(passwordValue, formatMessage);
3550
if (fieldError) {
3651
props.handleErrorChange('password', fieldError);
3752
} else if (!validationApiRateLimited) {
38-
dispatch(fetchRealtimeValidations({ password: e.target.value }));
53+
dispatch(fetchRealtimeValidations({ password: passwordValue }));
3954
}
4055
}
4156
};

src/common-components/tests/FormField.test.jsx

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ describe('PasswordField', () => {
147147
expect(props.handleBlur).toHaveBeenCalledTimes(1);
148148
});
149149

150-
it('should run validations when blur event when rendered from register page', () => {
150+
it('should run validations on blur event when rendered from register page', () => {
151151
props = {
152152
...props,
153153
handleErrorChange: jest.fn(),
@@ -225,4 +225,30 @@ describe('PasswordField', () => {
225225

226226
expect(store.dispatch).toHaveBeenCalledWith(fetchRealtimeValidations({ password: 'password123' }));
227227
});
228+
229+
it('should use password value from prop when password icon is focused out (blur due to icon)', () => {
230+
store.dispatch = jest.fn(store.dispatch);
231+
props = {
232+
...props,
233+
value: 'testPassword',
234+
handleErrorChange: jest.fn(),
235+
handleBlur: jest.fn(),
236+
};
237+
const passwordField = mount(reduxWrapper(<IntlPasswordField {...props} />));
238+
239+
passwordField.find('button[aria-label="Show password"]').simulate('blur', {
240+
target: {
241+
name: 'passwordIcon',
242+
value: undefined,
243+
},
244+
});
245+
246+
expect(props.handleBlur).toHaveBeenCalledTimes(1);
247+
expect(props.handleBlur).toHaveBeenCalledWith({
248+
target: {
249+
name: 'password',
250+
value: 'testPassword',
251+
},
252+
});
253+
});
228254
});

src/reset-password/ResetPasswordPage.jsx

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -91,20 +91,7 @@ const ResetPasswordPage = (props) => {
9191
};
9292

9393
const handleOnBlur = (event) => {
94-
let { name, value } = event.target;
95-
96-
// Do not validate when focus out from 'newPassword' and focus on 'passwordValidation' icon
97-
// for better user experience.
98-
if (event.relatedTarget
99-
&& event.relatedTarget.name === 'password'
100-
&& name === 'newPassword'
101-
) {
102-
return;
103-
}
104-
if (name === 'password') {
105-
name = 'newPassword';
106-
value = newPassword;
107-
}
94+
const { name, value } = event.target;
10895
validateInput(name, value);
10996
};
11097

src/reset-password/tests/ResetPasswordPage.test.jsx

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -184,23 +184,7 @@ describe('ResetPasswordPage', () => {
184184
resetPasswordPage.find('input#newPassword').simulate('blur', { target: { value: 'aziz156', name: 'newPassword' } });
185185
expect(resetPasswordPage.find('div[feedback-for="newPassword"]').text()).toEqual(expectedText);
186186
});
187-
it('should not call validation when typing and click on show icon button', async () => {
188-
const resetPasswordPage = mount(reduxWrapper(<IntlResetPasswordPage {...props} />));
189-
await act(async () => {
190-
await resetPasswordPage.find('input#newPassword').simulate('change', { target: { value: 'aziz156@', name: 'newPassword' } });
191-
await resetPasswordPage.find('button[aria-label="Show password"]').at(0).simulate('click');
192-
await resetPasswordPage.find('button[aria-label="Hide password"]').at(0).simulate('blur');
193-
});
194187

195-
expect(resetPasswordPage.find('div[feedback-for="newPassword"]').exists()).toBe(false);
196-
});
197-
it('should call validation click on show icon button and then focus out', () => {
198-
const resetPasswordPage = mount(reduxWrapper(<IntlResetPasswordPage {...props} />));
199-
resetPasswordPage.find('input#newPassword').simulate('focus', { target: { value: 'aziz156@', name: 'newPassword' } });
200-
resetPasswordPage.find('input#newPassword').simulate('blur', { relatedTarget: { name: 'password' } });
201-
resetPasswordPage.find('button[aria-label="Show password"]').at(0).simulate('click');
202-
expect(resetPasswordPage.find('div[feedback-for="newPassword"]').exists()).toBe(false);
203-
});
204188
it('show spinner when api call is pending', () => {
205189
store.dispatch = jest.fn(store.dispatch);
206190
props = {

0 commit comments

Comments
 (0)