Skip to content

Commit

Permalink
fix(authenticator): fix validate before trim bug (#3809)
Browse files Browse the repository at this point in the history
* chore: added .trim() to other fields in the authenticator state instead of just password

* chore: moved trim before validation in methods where there is a string

* chore: revert trim additions from before and correctly added trim to the email and username validator

* chore: revert amplify_authenticator_test changes

* chore: revert all changes from authenticator_state.dart

* chore: saving tests to clean up local repo

* chore: completed auth form tests for API call

* chore: removed unnecessary variables

* chore: removed unnecessary duplication of receiver

* chore: removed the unnecessary captured password

* chore: add signInPage.expectStep back in

* chore: trimmed password, verification, phone
  • Loading branch information
khatruong2009 authored Oct 17, 2023
1 parent bac5e96 commit 5dff469
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ FormFieldValidator<String> usernameValidator({
InputResolverKey.usernameEmpty,
);
}

input = input.trim();
if (!usernameRegex.hasMatch(input)) {
return inputResolver.resolve(
context,
Expand Down Expand Up @@ -85,6 +85,7 @@ FormFieldValidator<String> Function(BuildContext) validateNewPassword({
InputResolverKey.passwordEmpty,
);
}
password = password.trim();
if (passwordProtectionSettings == null) {
return null;
}
Expand Down Expand Up @@ -128,7 +129,9 @@ FormFieldValidator<String> validatePasswordConfirmation(
context,
InputResolverKey.passwordConfirmationEmpty,
);
} else if (getPassword() != passwordConfirmation.trim()) {
}
passwordConfirmation = passwordConfirmation.trim();
if (getPassword() != passwordConfirmation.trim()) {
return inputResolver.resolve(
context,
InputResolverKey.passwordsDoNotMatch,
Expand All @@ -152,7 +155,9 @@ FormFieldValidator<String> validatePhoneNumber({
context,
InputResolverKey.phoneNumberEmpty,
);
} else if (!phoneNumberRegex.hasMatch(phoneNumber)) {
}
phoneNumber = phoneNumber.trim();
if (!phoneNumberRegex.hasMatch(phoneNumber)) {
return inputResolver.resolve(context, InputResolverKey.phoneNumberFormat);
}
return null;
Expand All @@ -173,7 +178,9 @@ FormFieldValidator<String> validateEmail({
context,
InputResolverKey.emailEmpty,
);
} else if (!emailRegex.hasMatch(email)) {
}
email = email.trim();
if (!emailRegex.hasMatch(email)) {
return inputResolver.resolve(context, InputResolverKey.emailFormat);
}
return null;
Expand All @@ -191,7 +198,9 @@ FormFieldValidator<String> validateCode({
context,
InputResolverKey.verificationCodeEmpty,
);
} else if (!_codeRegex.hasMatch(code)) {
}
code = code.trim();
if (!_codeRegex.hasMatch(code)) {
return inputResolver.resolve(
context,
InputResolverKey.verificationCodeFormat,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,59 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_authenticator/amplify_authenticator.dart';
import 'package:amplify_authenticator/src/services/amplify_auth_service.dart';
import 'package:amplify_authenticator_test/amplify_authenticator_test.dart';
import 'package:amplify_integration_test/amplify_integration_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';

class MockAuthService extends Mock implements AmplifyAuthService {
String? capturedUsername;

@override
Future<SignInResult> signIn(
String username,
String password, {
SignInOptions? options,
}) {
capturedUsername = username;
return Future.value(
const CognitoSignInResult(
isSignedIn: true,
nextStep: AuthNextSignInStep(signInStep: AuthSignInStep.done),
),
);
}
}

class MockAuthPlugin extends AmplifyAuthCognitoStub {
MockAuthPlugin(this.authService);
final MockAuthService authService;

@override
Future<SignInResult> signIn({
required String username,
String? password,
SignInOptions? options,
}) {
return authService.signIn(username, password ?? '');
}
}

void main() {
TestWidgetsFlutterBinding.ensureInitialized();

setUp(TestWidgetsFlutterBinding.ensureInitialized);

group('Sign In View', () {
group('navigation', () {
testWidgets('via TabBar', (tester) async {
await tester.pumpWidget(const MockAuthenticatorApp());
await tester.pumpAndSettle();

final signInPage = SignInPage(tester: tester);
// ignore: cascade_invocations
signInPage.expectStep(AuthenticatorStep.signIn);

// Go to Sign Up
await tester.tap(signInPage.signUpTab);
Expand All @@ -39,7 +76,8 @@ void main() {
await tester.pumpAndSettle();

final signInPage = SignInPage(tester: tester);

// ignore: cascade_invocations
signInPage.expectStep(AuthenticatorStep.signIn);
await signInPage.submitSignIn();

final usernameFieldError = find.descendant(
Expand Down Expand Up @@ -79,6 +117,52 @@ void main() {
expect(usernameFieldError, findsOneWidget);
},
);

testWidgets(
'trims the username field before validation',
(tester) async {
await tester.pumpWidget(const MockAuthenticatorApp());
await tester.pumpAndSettle();

final signInPage = SignInPage(tester: tester);

await signInPage.enterUsername('user@example.com ');
await signInPage.enterPassword('Password123');

await signInPage.submitSignIn();

final usernameFieldError = find.descendant(
of: signInPage.usernameField,
matching: find.text('Invalid email format.'),
);

expect(usernameFieldError, findsNothing);
},
);

testWidgets(
'ensures email passed to the API is trimmed',
(tester) async {
final mockAuthService = MockAuthService();
final mockAuthPlugin = MockAuthPlugin(mockAuthService);
final app = MockAuthenticatorApp(authPlugin: mockAuthPlugin);

await tester.pumpWidget(app);
await tester.pumpAndSettle();

final signInPage = SignInPage(tester: tester);

// Enter email with trailing space and a valid password
await signInPage.enterUsername('user@example.com ');
await signInPage.enterPassword('Password123');

await signInPage.submitSignIn();
await tester.pumpAndSettle();

// Verify the email was trimmed before being passed to the signIn method
expect(mockAuthService.capturedUsername, 'user@example.com');
},
);
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,55 @@

import 'dart:convert';

import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_authenticator/amplify_authenticator.dart';
import 'package:amplify_authenticator/src/services/amplify_auth_service.dart';
import 'package:amplify_authenticator_test/amplify_authenticator_test.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:amplify_integration_test/amplify_integration_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';

class MockAuthService extends Mock implements AmplifyAuthService {
String? capturedUsername;

@override
Future<SignUpResult> signUp(
String username,
String password,
Map<CognitoUserAttributeKey, String> attributes,
) {
capturedUsername = username;
// Return mock result
return Future.value(
const CognitoSignUpResult(
isSignUpComplete: true,
nextStep: AuthNextSignUpStep(signUpStep: AuthSignUpStep.done),
),
);
}
}

class MockAuthPlugin extends AmplifyAuthCognitoStub {
MockAuthPlugin(this.authService);

final MockAuthService authService;

final attributes = <CognitoUserAttributeKey, String>{};

@override
Future<SignUpResult> signUp({
required String username,
required String password,
SignUpOptions? options,
}) {
return authService.signUp(
username,
password,
attributes,
);
}
}

void main() {
TestWidgetsFlutterBinding.ensureInitialized();
Expand Down Expand Up @@ -172,6 +217,60 @@ void main() {
expect(passwordFieldErrorLine4, findsOneWidget);
},
);

testWidgets(
'trims the username field before validation',
(tester) async {
await tester.pumpWidget(
const MockAuthenticatorApp(
initialStep: AuthenticatorStep.signUp,
),
);
await tester.pumpAndSettle();

final signInPage = SignUpPage(tester: tester);

await signInPage.enterUsername('user@example.com ');
await signInPage.enterPassword('Password123');

await signInPage.submitSignUp();

final usernameFieldError = find.descendant(
of: signInPage.usernameField,
matching: find.text('Invalid email format.'),
);

expect(usernameFieldError, findsNothing);
},
);

testWidgets(
'ensures email passed to the API is trimmed',
(tester) async {
final mockAuthService = MockAuthService();
final mockAuthPlugin = MockAuthPlugin(mockAuthService);
final app = MockAuthenticatorApp(
authPlugin: mockAuthPlugin,
initialStep: AuthenticatorStep.signUp,
);

await tester.pumpWidget(app);
await tester.pumpAndSettle();

final signUpPage = SignUpPage(tester: tester);

// Enter email with trailing space
await signUpPage.enterUsername('user@example.com ');
await signUpPage.enterPassword('Password123');
await signUpPage.enterPasswordConfirmation('Password123');

await signUpPage.submitSignUp();
await tester.pumpAndSettle();

// Verify the email was trimmed before being passed to signUp
expect(mockAuthService.capturedUsername, 'user@example.com');
},
);
});
});
}
Expand Down

0 comments on commit 5dff469

Please sign in to comment.