Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(ui-react-native): Add RN Authenticator fields validations #4107

Merged
merged 16 commits into from
Jul 17, 2023
Merged
6 changes: 6 additions & 0 deletions .changeset/rotten-lies-promise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@aws-amplify/ui-react-native': patch
'@aws-amplify/ui-react-core': patch
---

chore(ui-react-native): Add Authenticator fields validations
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ Scenario: Sign up with a new email & password
And I click the "Create Account" button
Then I see "Confirmation Code"

@react-native
Scenario: Sign up using invalid email
When I type a new "email" with value ''
Then I see "This field is required"
When I type a new "email" with value 'inv'
Then I see "Please enter a valid email"

@angular @react @vue
Scenario: Email field autocompletes username

Expand Down
21 changes: 14 additions & 7 deletions packages/react-core/src/Authenticator/hooks/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,21 @@ export type ConfirmSignInBaseProps<FieldType = {}> = {
challengeName: AuthChallengeName;
toSignIn: UseAuthenticator['toSignIn'];
} & CommonRouteProps &
ComponentSlots<FieldType>;
ComponentSlots<FieldType> &
ValidationProps;

export type ConfirmSignUpBaseProps<FieldType = {}> = {
codeDeliveryDetails: UseAuthenticator['codeDeliveryDetails'];
resendCode: UseAuthenticator['resendCode'];
} & CommonRouteProps &
ComponentSlots<FieldType>;
ComponentSlots<FieldType> &
ValidationProps;

export type ConfirmVerifyUserProps<FieldType = {}> = {
skipVerification: UseAuthenticator['skipVerification'];
} & CommonRouteProps &
ComponentSlots<FieldType>;
ComponentSlots<FieldType> &
ValidationProps;

export type ForceResetPasswordBaseProps<FieldType = {}> = {
toSignIn: UseAuthenticator['toSignIn'];
Expand All @@ -117,21 +120,24 @@ export type ForceResetPasswordBaseProps<FieldType = {}> = {
export type ResetPasswordBaseProps<FieldType = {}> = {
toSignIn: UseAuthenticator['toSignIn'];
} & CommonRouteProps &
ComponentSlots<FieldType>;
ComponentSlots<FieldType> &
ValidationProps;

export type SetupTOTPBaseProps<FieldType = {}> = {
toSignIn: UseAuthenticator['toSignIn'];
totpSecretCode: UseAuthenticator['totpSecretCode'];
} & CommonRouteProps &
ComponentSlots<FieldType>;
ComponentSlots<FieldType> &
ValidationProps;

export type SignInBaseProps<FieldType = {}> = {
hideSignUp?: boolean;
toFederatedSignIn: UseAuthenticator['toFederatedSignIn'];
toResetPassword: UseAuthenticator['toResetPassword'];
toSignUp: UseAuthenticator['toSignUp'];
} & CommonRouteProps &
ComponentSlots<FieldType>;
ComponentSlots<FieldType> &
ValidationProps;

export type SignUpBaseProps<FieldType = {}> = {
hideSignIn?: boolean;
Expand All @@ -144,7 +150,8 @@ export type SignUpBaseProps<FieldType = {}> = {
export type VerifyUserProps<FieldType = {}> = {
skipVerification: UseAuthenticator['skipVerification'];
} & CommonRouteProps &
ComponentSlots<FieldType>;
ComponentSlots<FieldType> &
ValidationProps;

export interface DefaultProps<FieldType = {}> {
ConfirmSignIn: ConfirmSignInBaseProps<FieldType>;
Expand Down
3 changes: 3 additions & 0 deletions packages/react-native/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
module.exports = {
preset: 'react-native',
modulePathIgnorePatterns: ['<rootDir>/dist/'],
collectCoverage: true,
collectCoverageFrom: [
'<rootDir>/src/**/*.{js,jsx,ts,tsx}',
'!<rootDir>/src/**/*{c,C}onstants.ts',
],
// ignore coverage for top level "export" and style files
coveragePathIgnorePatterns: ['<rootDir>/src/(index|styles).(ts|tsx)'],
calebpollman marked this conversation as resolved.
Show resolved Hide resolved
moduleNameMapper: {
'^react$': '<rootDir>/node_modules/react',
'^react-native$': '<rootDir>/node_modules/react-native',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,21 @@ const ConfirmResetPassword: DefaultConfirmResetPasswordComponent = ({
hasValidationErrors,
isPending,
resendCode,
validationErrors,
...rest
}) => {
const {
disableFormSubmit,
fields: fieldsWithHandlers,
fieldValidationErrors,
handleFormSubmit,
} = useFieldValues({
componentName: COMPONENT_NAME,
fields,
handleBlur,
handleChange,
handleSubmit,
validationErrors,
});

const disabled = hasValidationErrors || disableFormSubmit;
Expand Down Expand Up @@ -72,6 +75,7 @@ const ConfirmResetPassword: DefaultConfirmResetPasswordComponent = ({
headerText={headerText}
fields={fieldsWithHandlers}
isPending={isPending}
validationErrors={fieldValidationErrors}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,21 @@ const ConfirmSignIn: DefaultConfirmSignInComponent = ({
handleSubmit,
isPending,
toSignIn,
validationErrors,
...rest
}) => {
const {
disableFormSubmit: disabled,
fields: fieldsWithHandlers,
fieldValidationErrors,
handleFormSubmit,
} = useFieldValues({
componentName: COMPONENT_NAME,
fields,
handleBlur,
handleChange,
handleSubmit,
validationErrors,
});

const headerText = getChallengeText(challengeName);
Expand Down Expand Up @@ -71,6 +74,7 @@ const ConfirmSignIn: DefaultConfirmSignInComponent = ({
headerText={headerText}
fields={fieldsWithHandlers}
isPending={isPending}
validationErrors={fieldValidationErrors}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const props = {
handleBlur: jest.fn(),
handleChange: jest.fn(),
handleSubmit: jest.fn(),
hasValidationErrors: false,
Header: ConfirmSignIn.Header,
isPending: false,
toSignIn: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,21 @@ const ConfirmSignUp: DefaultConfirmSignUpComponent = ({
handleSubmit,
isPending,
resendCode,
validationErrors,
...rest
}) => {
const {
disableFormSubmit: disabled,
fields: fieldsWithHandlers,
fieldValidationErrors,
handleFormSubmit,
} = useFieldValues({
componentName: COMPONENT_NAME,
fields,
handleBlur,
handleChange,
handleSubmit,
validationErrors,
});

const headerText = getDeliveryMethodText(codeDeliveryDetails);
Expand Down Expand Up @@ -74,6 +77,7 @@ const ConfirmSignUp: DefaultConfirmSignUpComponent = ({
headerText={headerText}
fields={fieldsWithHandlers}
isPending={isPending}
validationErrors={fieldValidationErrors}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const props = {
handleBlur: jest.fn(),
handleChange: jest.fn(),
handleSubmit: jest.fn(),
hasValidationErrors: false,
Header: ConfirmSignUp.Header,
isPending: false,
resendCode: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,21 @@ const ConfirmVerifyUser: DefaultConfirmVerifyUserComponent = ({
handleSubmit,
isPending,
skipVerification,
validationErrors,
...rest
}) => {
const {
disableFormSubmit: disabled,
fields: fieldsWithHandlers,
fieldValidationErrors,
handleFormSubmit,
} = useFieldValues({
componentName: COMPONENT_NAME,
fields,
handleBlur,
handleChange,
handleSubmit,
validationErrors,
});

const headerText = getAccountRecoveryInfoText();
Expand Down Expand Up @@ -70,6 +73,7 @@ const ConfirmVerifyUser: DefaultConfirmVerifyUserComponent = ({
headerText={headerText}
fields={fieldsWithHandlers}
isPending={isPending}
validationErrors={fieldValidationErrors}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const props = {
handleBlur: jest.fn(),
handleChange: jest.fn(),
handleSubmit: jest.fn(),
hasValidationErrors: false,
Header: ConfirmVerifyUser.Header,
isPending: false,
skipVerification: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,21 @@ const ForceNewPassword: DefaultForceNewPasswordComponent = ({
hasValidationErrors,
isPending,
toSignIn,
validationErrors,
...rest
}) => {
const {
disableFormSubmit,
fields: fieldsWithHandlers,
fieldValidationErrors,
handleFormSubmit,
} = useFieldValues({
componentName: COMPONENT_NAME,
fields,
handleBlur,
handleChange,
handleSubmit,
validationErrors,
});

const disabled = hasValidationErrors || disableFormSubmit;
Expand Down Expand Up @@ -70,6 +73,7 @@ const ForceNewPassword: DefaultForceNewPasswordComponent = ({
headerText={headerText}
fields={fieldsWithHandlers}
isPending={isPending}
validationErrors={fieldValidationErrors}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,21 @@ const ResetPassword: DefaultResetPasswordComponent = ({
handleSubmit,
isPending,
toSignIn,
validationErrors,
...rest
}) => {
const {
disableFormSubmit: disabled,
fields: fieldsWithHandlers,
fieldValidationErrors,
handleFormSubmit,
} = useFieldValues({
componentName: COMPONENT_NAME,
fields,
handleBlur,
handleChange,
handleSubmit,
validationErrors,
});

const headerText = getResetYourPasswordText();
Expand Down Expand Up @@ -69,6 +72,7 @@ const ResetPassword: DefaultResetPasswordComponent = ({
headerText={headerText}
fields={fieldsWithHandlers}
isPending={isPending}
validationErrors={fieldValidationErrors}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const props = {
handleBlur: jest.fn(),
handleChange: jest.fn(),
handleSubmit: jest.fn(),
hasValidationErrors: false,
Header: ResetPassword.Header,
isPending: false,
toSignIn: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,21 @@ const SetupTOTP: DefaultSetupTOTPComponent = ({
isPending,
toSignIn,
totpSecretCode,
validationErrors,
...rest
}) => {
const {
disableFormSubmit: disabled,
fields: fieldsWithHandlers,
fieldValidationErrors,
handleFormSubmit,
} = useFieldValues({
componentName: COMPONENT_NAME,
fields,
handleBlur,
handleChange,
handleSubmit,
validationErrors,
});

const headerText = getSetupTOTPText();
Expand Down Expand Up @@ -88,6 +91,7 @@ const SetupTOTP: DefaultSetupTOTPComponent = ({
headerText={headerText}
fields={fieldsWithHandlers}
isPending={isPending}
validationErrors={fieldValidationErrors}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const props = {
handleBlur: jest.fn(),
handleChange: jest.fn(),
handleSubmit: jest.fn(),
hasValidationErrors: false,
isPending: false,
toSignIn,
totpSecretCode: "Let's keep it hush hush",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const SignIn: DefaultSignInComponent = ({
hideSignUp,
toResetPassword,
toSignUp,
validationErrors,
...rest
}) => {
const {
Expand All @@ -33,13 +34,15 @@ const SignIn: DefaultSignInComponent = ({
const {
disableFormSubmit: disabled,
fields: fieldsWithHandlers,
fieldValidationErrors,
handleFormSubmit,
} = useFieldValues({
componentName: COMPONENT_NAME,
fields,
handleBlur,
handleChange,
handleSubmit,
validationErrors,
});

const headerText = getSignInTabText();
Expand Down Expand Up @@ -75,6 +78,7 @@ const SignIn: DefaultSignInComponent = ({
buttons={buttons}
fields={fieldsWithHandlers}
headerText={headerText}
validationErrors={fieldValidationErrors}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const props = {
handleBlur: jest.fn(),
handleChange: jest.fn(),
handleSubmit: jest.fn(),
hasValidationErrors: false,
Header: SignIn.Header,
isPending: false,
socialProviders: undefined,
Expand Down
Loading