Last active
September 22, 2021 04:17
-
-
Save prajwal27/4735ed549779b8c8bd941adab574fb12 to your computer and use it in GitHub Desktop.
widget_testing_with_cubit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:developer'; | |
import 'package:bloc/bloc.dart'; | |
import 'package:equatable/equatable.dart'; | |
import 'package:mobility_one/repositories/accounts_repository.dart'; | |
import 'package:mobility_one/repositories/authentication_repository.dart'; | |
import 'package:mobility_one/util/api_client.dart'; | |
import 'package:mobility_one/util/auth_util.dart'; | |
import 'package:mobility_one/util/util.dart'; | |
import 'package:oauth2/oauth2.dart' as oauth2; | |
import 'dart:html' as html; | |
part 'authentication_state.dart'; | |
class AuthenticationCubit extends Cubit<AuthenticationState> { | |
AuthenticationCubit({required this.authenticationRepository, required this.accountsRepository}) | |
: super(AuthenticationInitial()); | |
final AuthenticationRepository authenticationRepository; | |
final AccountsRepository accountsRepository; | |
void onAppStart({required Uri currentUrl}) async { | |
final credentials = await authenticationRepository.getCredentials(); | |
if (credentials != null && credentials.isExpired == false) { | |
emit(AuthenticationAuthenticated(credentials: credentials)); | |
} else if (credentials != null && credentials.isExpired == true) { | |
try { | |
final newCredentials = | |
await credentials.refresh(identifier: AuthUtil.clientId); | |
await authenticationRepository.setCredentials(newCredentials); | |
emit(AuthenticationAuthenticated(credentials: newCredentials)); | |
} catch (error) { | |
await authenticationRepository.deleteCredentials(); | |
await authenticationRepository.deleteGrantCodeVerifier(); | |
log('Error refreshing credentials $error'); | |
emit(AuthenticationUnauthenticated()); | |
} | |
} else { | |
final grant = await getGrant(); | |
final queryParameters = currentUrl.queryParameters; | |
if (queryParameters.containsKey('code')) { | |
try { | |
final client = | |
await grant.handleAuthorizationResponse(queryParameters); | |
await authenticationRepository.setCredentials(client.credentials); | |
emit(AuthenticationAuthenticated(credentials: client.credentials)); | |
client.close(); | |
} catch (error) { | |
await authenticationRepository.deleteCredentials(); | |
await authenticationRepository.deleteGrantCodeVerifier(); | |
log('Error checking the token $error'); | |
emit(AuthenticationUnauthenticated()); | |
} | |
} else { | |
// html.window.location.assign(authorizationUrl); | |
} | |
} | |
} | |
Future<oauth2.AuthorizationCodeGrant> getGrant() async { | |
final savedCodeVerifier = | |
await authenticationRepository.getGrantCodeVerifier(); | |
if (savedCodeVerifier != null) { | |
final savedGrant = oauth2.AuthorizationCodeGrant(AuthUtil.clientId, | |
AuthUtil.authorizationEndpoint, AuthUtil.tokenEndpoint, | |
codeVerifier: savedCodeVerifier); | |
await authenticationRepository.deleteGrantCodeVerifier(); | |
return savedGrant; | |
} | |
final newCodeVerifier = Util.createCodeVerifier(); | |
final newGrant = oauth2.AuthorizationCodeGrant(AuthUtil.clientId, | |
AuthUtil.authorizationEndpoint, AuthUtil.tokenEndpoint, | |
codeVerifier: newCodeVerifier); | |
await authenticationRepository.setGrantCodeVerifier( | |
codeVerifier: newCodeVerifier); | |
return newGrant; | |
} | |
Future<void> redirectToLoginPage() async { | |
final grant = await getGrant(); | |
final authorizationUrl = grant | |
.getAuthorizationUrl(AuthUtil.redirectUrl, scopes: AuthUtil.scopes) | |
.toString(); | |
html.window.location.assign(authorizationUrl); | |
} | |
Future<void> makeLogin( | |
{required String email, required String password}) async { | |
try { | |
emit(AuthenticationAuthenticating()); | |
final authorizationUrl = AuthUtil.tokenEndpoint; | |
var client = await oauth2.resourceOwnerPasswordGrant( | |
authorizationUrl, email, password, identifier: 'trusted-login', secret: 'trusted-secret'); | |
await authenticationRepository.setCredentials(client.credentials); | |
final userName = await accountsRepository.getCurrentAccount(); | |
await accountsRepository.setUserName(userName); | |
emit(AuthenticationAuthenticated(credentials: client.credentials)); | |
client.close(); | |
} catch (err) { | |
print('err $err'); | |
emit(AuthenticationFailed()); | |
} | |
} | |
Future<void> signup( | |
{required String email, | |
required String password, | |
required String name, | |
required String companyName, | |
required String accountName}) async { | |
try { | |
emit(AuthenticationSigningUp()); | |
final authorizationUrl = AuthUtil.tokenEndpoint; | |
var client = await oauth2.clientCredentialsGrant(authorizationUrl, 'trusted-login', 'trusted-secret', scopes: ['IdentityServerApi', 'create-users']); | |
await authenticationRepository.setAppCredentials(client.credentials); | |
await accountsRepository.signUp(requestBody: { | |
'Email': email, | |
'FullName': name, | |
'AccountName': accountName, | |
'CompanyName': companyName, | |
'Password': password | |
}); | |
emit(AuthenticationSigningUpCompleted()); | |
await makeLogin(email: email, password: password); | |
} catch (err) { | |
print('Error'); | |
print((err as MobilityOneError)); | |
emit(AuthenticationSignUpFailed()); | |
} | |
} | |
Future<void> logout() async { | |
final credentials = await authenticationRepository.getCredentials(); | |
if (credentials != null) { | |
print('deleting'); | |
print('cr3ddtials ${credentials.idToken}'); | |
print('cr3ddtials ${credentials.accessToken}'); | |
await authenticationRepository.deleteCredentials(); | |
await authenticationRepository.deleteGrantCodeVerifier(); | |
print('credentials ${credentials.idToken}'); | |
} | |
print('emiting'); | |
emit(AuthenticationUnauthenticated()); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flip_card/flip_card.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:mobility_one/ui/screens/login_screen.dart'; | |
import 'package:mobility_one/ui/screens/signup_screen.dart'; | |
import 'package:mobility_one/util/my_colors.dart'; | |
class AuthenticationScreen extends StatefulWidget { | |
const AuthenticationScreen({Key? key}) : super(key: key); | |
@override | |
_AuthenticationScreenState createState() => _AuthenticationScreenState(); | |
} | |
class _AuthenticationScreenState extends State<AuthenticationScreen> { | |
GlobalKey<FlipCardState> cardKey = | |
GlobalKey<FlipCardState>(debugLabel: 'test'); | |
var keys = Key('dc'); | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
backgroundColor: MyColors.backgroundColor, | |
body: FlipCard( | |
key: cardKey, | |
flipOnTouch: false, | |
front: LoginScreen( | |
onSignUpClick: _toggleCardFlip, | |
), | |
back: SignUpScreen( | |
onSignInClick: _toggleCardFlip, | |
), | |
), | |
); | |
} | |
void _toggleCardFlip() { | |
cardKey.currentState!.toggleCard(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:bloc_test/bloc_test.dart'; | |
import 'package:flip_card/flip_card.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_bloc/flutter_bloc.dart'; | |
import 'package:flutter_test/flutter_test.dart'; | |
import 'package:mobility_one/blocs/authentication_cubit/authentication_cubit.dart'; | |
import 'package:mobility_one/blocs/drawer_cubit/drawer_cubit.dart'; | |
import 'package:mobility_one/blocs/drawer_cubit/drawer_state.dart'; | |
import 'package:mobility_one/ui/screens/authentication_screen.dart'; | |
import 'package:mockito/mockito.dart'; | |
import 'package:mocktail/mocktail.dart' as mocktail; | |
class MockAuthenticationCubit extends MockCubit<AuthenticationState> | |
implements AuthenticationCubit {} | |
class MockDrawerCubit extends MockCubit<DrawerState> implements DrawerCubit {} | |
class AuthenticationStateFake extends Fake implements AuthenticationState {} | |
void main() { | |
group('DetailsScreen', () { | |
late MockAuthenticationCubit mockAuthenticationCubit; | |
late MockDrawerCubit mockDrawerCubit; | |
setUp(() { | |
mockAuthenticationCubit = MockAuthenticationCubit(); | |
mockDrawerCubit = MockDrawerCubit(); | |
mocktail.registerFallbackValue<AuthenticationState>( | |
AuthenticationStateFake()); | |
}); | |
var key = GlobalKey<FlipCardState>(debugLabel: 'test'); | |
testWidgets('renders properly with no todos', (WidgetTester tester) async { | |
when(() => mockAuthenticationCubit.state) | |
.thenReturn(() => AuthenticationUnauthenticated()); | |
whenListen<AuthenticationState>( | |
mockAuthenticationCubit, | |
Stream<AuthenticationState>.fromIterable( | |
[ | |
AuthenticationUnauthenticated(), | |
], | |
), | |
initialState: AuthenticationInitial(), | |
); | |
await tester.pumpWidget(MultiBlocProvider( | |
providers: [ | |
BlocProvider<AuthenticationCubit>.value( | |
value: mockAuthenticationCubit, | |
), | |
BlocProvider<DrawerCubit>.value( | |
value: mockDrawerCubit, | |
), | |
], | |
child: MaterialApp(home: AuthenticationScreen()), | |
)); | |
await tester.pumpAndSettle(); | |
var cardKey = find.byType(GlobalKey); | |
expect(cardKey, findsOneWidget); | |
//expect(find.byKey(key), findsOneWidget); | |
}); | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
part of 'authentication_cubit.dart'; | |
abstract class AuthenticationState extends Equatable { | |
const AuthenticationState(); | |
@override | |
List<Object?> get props => []; | |
} | |
class AuthenticationInitial extends AuthenticationState {} | |
class AuthenticationAuthenticating extends AuthenticationState {} | |
class AuthenticationAuthenticated extends AuthenticationState { | |
final oauth2.Credentials credentials; | |
AuthenticationAuthenticated({required this.credentials}); | |
@override | |
List<Object?> get props => [credentials]; | |
} | |
class AuthenticationFailed extends AuthenticationState {} | |
class AuthenticationUnauthenticated extends AuthenticationState {} | |
class AuthenticationSigningUp extends AuthenticationState {} | |
class AuthenticationSigningUpCompleted extends AuthenticationState {} | |
class AuthenticationSignUpFailed extends AuthenticationState {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:beamer/beamer.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_bloc/flutter_bloc.dart'; | |
import 'package:flutter_svg/flutter_svg.dart'; | |
import 'package:mobility_one/blocs/authentication_cubit/authentication_cubit.dart'; | |
import 'package:mobility_one/ui/widgets/confirm_button.dart'; | |
import 'package:mobility_one/ui/widgets/my_circular_progress_indicator.dart'; | |
import 'package:mobility_one/ui/widgets/my_text_form_field.dart'; | |
import 'package:mobility_one/util/app_routes.dart'; | |
import 'package:mobility_one/util/my_colors.dart'; | |
import 'package:mobility_one/util/my_fields_validations.dart'; | |
import 'package:mobility_one/util/my_images.dart'; | |
import 'package:mobility_one/util/my_localization.dart'; | |
import 'package:mobility_one/util/my_text_styles.dart'; | |
class LoginScreen extends StatefulWidget { | |
final Function onSignUpClick; | |
const LoginScreen({required this.onSignUpClick}); | |
@override | |
_LoginScreenState createState() => _LoginScreenState(); | |
} | |
class _LoginScreenState extends State<LoginScreen> { | |
final _emailController = TextEditingController(); | |
final _passwordController = TextEditingController(); | |
final _formKey = GlobalKey<FormState>(); | |
bool rememberLogin = false; | |
@override | |
Widget build(BuildContext context) { | |
final screenSize = MediaQuery.of(context).size; | |
return BlocListener<AuthenticationCubit, AuthenticationState>( | |
listener: (context, state) { | |
if (state is AuthenticationAuthenticated) { | |
Beamer.of(context).beamToNamed(AppRoutes.home); | |
} else { | |
Beamer.of(context).beamToNamed(AppRoutes.root); | |
} | |
if (state is AuthenticationFailed) { | |
ScaffoldMessenger.of(context).showSnackBar(SnackBar( | |
content: Text(MyLocalization.of(context)!.wrongCredentials))); | |
} | |
}, | |
child: BlocBuilder<AuthenticationCubit, AuthenticationState>( | |
builder: (context, state) { | |
return Scaffold( | |
backgroundColor: MyColors.backgroundColor, | |
body: Center( | |
child: SingleChildScrollView( | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
crossAxisAlignment: CrossAxisAlignment.center, | |
children: [_buildLoginForm(state)], | |
), | |
), | |
), | |
); | |
}, | |
), | |
); | |
} | |
Widget _buildLoginForm(AuthenticationState state) { | |
return Form( | |
key: _formKey, | |
child: Container( | |
height: 775, | |
width: 552, | |
child: Card( | |
color: MyColors.backgroundCardColor, | |
elevation: 10, | |
child: state is AuthenticationAuthenticating | |
? MyCircularProgressIndicator() | |
: Padding( | |
padding: const EdgeInsets.all(50), | |
child: Column( | |
children: [ | |
SvgPicture.asset( | |
MyImages.mobilityOneLogo, | |
width: 252, | |
), | |
Text( | |
MyLocalization.of(context)!.loginWelcomeMessage, | |
style: TextStyle( | |
color: Colors.white, | |
fontSize: 30, | |
fontFamily: 'Averta', | |
fontWeight: FontWeight.bold), | |
), | |
SizedBox( | |
height: 24, | |
), | |
Text( | |
MyLocalization.of(context)!.loginInstructionMessage, | |
style: TextStyle( | |
color: Colors.white.withOpacity(.6), | |
fontSize: 12, | |
fontFamily: 'Averta'), | |
), | |
SizedBox( | |
height: 20, | |
), | |
MyTextFormField( | |
controller: _emailController, | |
label: MyLocalization.of(context)!.email, | |
fieldValidator: MyFieldValidations.validateEmail, | |
expanded: true, | |
), | |
SizedBox( | |
height: 16, | |
), | |
MyTextFormField( | |
controller: _passwordController, | |
label: MyLocalization.of(context)!.password, | |
isPasswordField: true, | |
fieldValidator: MyFieldValidations.validatePassword, | |
expanded: true, | |
), | |
SizedBox( | |
height: 40, | |
), | |
ConfirmButton( | |
onPressed: () { | |
var error = MyFieldValidations.validateEmail( | |
context, _emailController.value.text); | |
_formKey.currentState!.validate(); | |
if (error == null) { | |
// context.read<AuthenticationCubit>().redirectToLoginPage(); | |
context.read<AuthenticationCubit>().makeLogin( | |
email: _emailController.value.text, | |
password: _passwordController.value.text); | |
} | |
}, | |
title: MyLocalization.of(context)!.login, | |
expanded: true, | |
height: 60, | |
), | |
SizedBox( | |
height: 20, | |
), | |
Row( | |
children: [ | |
..._buildRememberLoginButton(), | |
Spacer(), | |
_buildResetHereButton() | |
], | |
), | |
SizedBox( | |
height: 40, | |
), | |
_buildCreateAnAccountButton(), | |
SizedBox( | |
height: 40, | |
), | |
_buildAzureAdLoginButton() | |
], | |
), | |
), | |
), | |
), | |
); | |
} | |
List<Widget> _buildRememberLoginButton() { | |
return [ | |
Checkbox( | |
value: rememberLogin, | |
onChanged: (selected) { | |
setState( | |
() { | |
rememberLogin = selected!; | |
}, | |
); | |
}, | |
), | |
TextButton( | |
onPressed: () { | |
setState(() { | |
rememberLogin = !rememberLogin; | |
}); | |
}, | |
child: Text( | |
MyLocalization.of(context)!.rememberLoginText, | |
style: MyTextStyles.dataTableText | |
.copyWith(color: MyColors.cardTextColor), | |
), | |
) | |
]; | |
} | |
Widget _buildResetHereButton() { | |
return MouseRegion( | |
cursor: SystemMouseCursors.click, | |
child: GestureDetector( | |
onTap: () {}, | |
child: Container( | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
Text( | |
MyLocalization.of(context)!.resetHereText.toUpperCase(), | |
style: MyTextStyles.dataTableViewAll.copyWith(fontSize: 14), | |
), | |
const SizedBox( | |
height: 3, | |
), | |
Container( | |
height: 1, | |
width: 84, | |
color: MyColors.mobilityOneLightGreenColor, | |
) | |
], | |
), | |
), | |
), | |
); | |
} | |
Widget _buildCreateAnAccountButton() { | |
return MouseRegion( | |
cursor: SystemMouseCursors.click, | |
child: GestureDetector( | |
onTap: () { | |
widget.onSignUpClick(); | |
}, | |
child: Container( | |
width: double.infinity, | |
padding: EdgeInsets.all(20), | |
decoration: BoxDecoration( | |
color: Color(0xFF585876), | |
borderRadius: BorderRadius.all( | |
Radius.circular(20), | |
), | |
), | |
child: Center( | |
child: Text( | |
MyLocalization.of(context)!.createAnAccountText.toUpperCase(), | |
style: TextStyle( | |
color: Colors.white, | |
fontSize: 16, | |
fontWeight: FontWeight.bold), | |
), | |
), | |
), | |
), | |
); | |
} | |
Widget _buildAzureAdLoginButton() { | |
return MouseRegion( | |
cursor: SystemMouseCursors.click, | |
child: GestureDetector( | |
onTap: () {}, | |
child: Container( | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
Text( | |
'AZURE AD LOGIN', | |
style: MyTextStyles.dataTableViewAll.copyWith(fontSize: 14), | |
), | |
const SizedBox( | |
height: 3, | |
), | |
Container( | |
height: 1, | |
width: 110, | |
color: MyColors.mobilityOneLightGreenColor, | |
) | |
], | |
), | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment