Skip to content

Commit

Permalink
test(clerk-js): Fix tests for password validation
Browse files Browse the repository at this point in the history
  • Loading branch information
desiprisg committed Sep 28, 2023
1 parent 4522600 commit 16386f3
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 17 deletions.
8 changes: 5 additions & 3 deletions packages/clerk-js/src/ui/components/SignIn/ResetPassword.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const _ResetPassword = () => {
defaultChecked: true,
});

const { displayConfirmPasswordFeedback, isPasswordMatch } = useConfirmPassword({
const { setConfirmPasswordFeedback, isPasswordMatch } = useConfirmPassword({
passwordField,
confirmPasswordField: confirmField,
});
Expand All @@ -61,7 +61,7 @@ export const _ResetPassword = () => {

const validateForm = () => {
if (passwordField.value) {
displayConfirmPasswordFeedback(confirmField.value);
setConfirmPasswordFeedback(confirmField.value);
}
};

Expand Down Expand Up @@ -127,7 +127,9 @@ export const _ResetPassword = () => {
<Form.Control
{...confirmField.props}
onChange={e => {
displayConfirmPasswordFeedback(e.target.value);
if (e.target.value) {
setConfirmPasswordFeedback(e.target.value);
}
return confirmField.props.onChange(e);
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,13 @@ describe('ResetPassword', () => {
await userEvent.type(screen.getByLabelText(/new password/i), 'testewrewr');
const confirmField = screen.getByLabelText(/confirm password/i);
await userEvent.type(confirmField, 'testrwerrwqrwe');
fireEvent.blur(confirmField);
await waitFor(() => {
screen.getByText(`Passwords don't match.`);
expect(screen.getByText(`Passwords don't match.`)).toBeInTheDocument();
});

await userEvent.clear(confirmField);
await waitFor(() => {
screen.getByText(`Passwords don't match.`);
expect(screen.getByText(`Passwords don't match.`)).toBeInTheDocument();
});
});
}, 10000);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export const PasswordPage = withCardStateProvider(() => {
defaultChecked: true,
});

const { displayConfirmPasswordFeedback, isPasswordMatch } = useConfirmPassword({
const { setConfirmPasswordFeedback, isPasswordMatch } = useConfirmPassword({
passwordField,
confirmPasswordField: confirmField,
});
Expand All @@ -94,7 +94,7 @@ export const PasswordPage = withCardStateProvider(() => {

const validateForm = () => {
if (passwordField.value) {
displayConfirmPasswordFeedback(confirmField.value);
setConfirmPasswordFeedback(confirmField.value);
}
};

Expand Down Expand Up @@ -165,7 +165,9 @@ export const PasswordPage = withCardStateProvider(() => {
<Form.Control
{...confirmField.props}
onChange={e => {
displayConfirmPasswordFeedback(e.target.value);
if (e.target.value) {
setConfirmPasswordFeedback(e.target.value);
}
return confirmField.props.onChange(e);
}}
isDisabled={passwordEditDisabled}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,22 +269,25 @@ describe('PasswordPage', () => {

it(`Displays "Password match" when password match and removes it if they stop`, async () => {
const { wrapper } = await createFixtures(initConfig);

await runFakeTimers(async () => {
const { userEvent } = render(<PasswordPage />, { wrapper });
const passwordField = screen.getByLabelText(/new password/i);

await userEvent.type(passwordField, 'testewrewr');
const confirmField = screen.getByLabelText(/confirm password/i);
expect(screen.queryByText(`Passwords match.`)).not.toBeInTheDocument();
await waitFor(() => {
expect(screen.queryByText(`Passwords match.`)).not.toBeInTheDocument();
});

await userEvent.type(confirmField, 'testewrewr');
await waitFor(() => {
screen.getByText(`Passwords match.`);
expect(screen.getByText(`Passwords match.`)).toBeInTheDocument();
});

await userEvent.type(confirmField, 'testrwerrwqrwe');
await waitFor(() => {
expect(screen.queryByText(`Passwords match.`)).not.toBeInTheDocument();
expect(screen.queryByText(`Passwords match.`)).not.toBeVisible();
});

await userEvent.type(passwordField, 'testrwerrwqrwe');
Expand Down
4 changes: 2 additions & 2 deletions packages/clerk-js/src/ui/elements/FormControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -395,15 +395,15 @@ export const FormControl = forwardRef<HTMLInputElement, PropsWithChildren<FormCo
inputElementProps.onFocus?.(e);
setTimeout(() => {
setIsFocused(true);
}, 300);
}, 350);
}}
onBlur={e => {
inputElementProps.onBlur?.(e);
// set a timeout because new errors might appear
// and we don't want to spam layout shifts
setTimeout(() => {
setIsFocused(false);
}, 300);
}, 350);
}}
ref={ref}
placeholder={t(placeholder)}
Expand Down
4 changes: 2 additions & 2 deletions packages/clerk-js/src/ui/hooks/usePassword.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const useConfirmPassword = ({
[checkPasswordMatch, confirmPasswordField.value],
);

const displayConfirmPasswordFeedback = useCallback(
const setConfirmPasswordFeedback = useCallback(
(password: string) => {
if (checkPasswordMatch(password)) {
confirmPasswordField.setSuccess(t(localizationKeys('formFieldError__matchingPasswords')));
Expand All @@ -104,7 +104,7 @@ export const useConfirmPassword = ({
);

return {
displayConfirmPasswordFeedback,
setConfirmPasswordFeedback,
isPasswordMatch,
};
};
15 changes: 15 additions & 0 deletions packages/clerk-js/src/ui/utils/test/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
DisplayConfigJSON,
EnvironmentJSON,
OrganizationSettingsJSON,
PasswordSettingsData,
UserJSON,
UserSettingsJSON,
} from '@clerk/types';
Expand Down Expand Up @@ -154,6 +155,19 @@ const createBaseUserSettings = (): UserSettingsJSON => {
socials.map(social => [social, { enabled: false, required: false, authenticatable: false, strategy: social }]),
) as any as UserSettingsJSON['social'];

const passwordSettingsConfig = {
allowed_special_characters: '',
max_length: 0,
min_length: 8,
require_special_char: false,
require_numbers: false,
require_lowercase: false,
require_uppercase: false,
disable_hibp: true,
show_zxcvbn: false,
min_zxcvbn_strength: 0,
} as UserSettingsJSON['password_settings'];

return {
attributes: { ...attributeConfig },
actions: { delete_self: false, create_organization: false },
Expand All @@ -177,6 +191,7 @@ const createBaseUserSettings = (): UserSettingsJSON => {
enabled: false,
},
},
password_settings: passwordSettingsConfig,
};
};

Expand Down
8 changes: 7 additions & 1 deletion packages/clerk-js/src/ui/utils/useFormControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export type FormControlState<Id = string> = FieldStateProps<Id> & {
setInfo: (info: string) => void;
setValue: (val: string | undefined) => void;
setChecked: (isChecked: boolean) => void;
clearFeedback: () => void;
props: FieldStateProps<Id>;
};

Expand Down Expand Up @@ -120,10 +121,14 @@ export const useFormControl = <Id extends string>(

const setInfo: FormControlState['setInfo'] = info => {
if (info) {
setFeedback({ message: translateError(info), type: 'info' });
setFeedback({ message: info, type: 'info' });
}
};

const clearFeedback: FormControlState['clearFeedback'] = () => {
setFeedback({ message: '', type: 'info' });
};

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { defaultChecked, validatePassword: validatePasswordProp, buildErrorMessage, ...restOpts } = opts;

Expand All @@ -139,6 +144,7 @@ export const useFormControl = <Id extends string>(
feedback: feedback.message || t(opts.infoText),
feedbackType: feedback.type,
setInfo,
clearFeedback,
hasPassedComplexity,
setHasPassedComplexity,
validatePassword: opts.type === 'password' ? opts.validatePassword : undefined,
Expand Down

0 comments on commit 16386f3

Please sign in to comment.