diff --git a/app/lib/main/app.dart b/app/lib/main/app.dart index 1f2c601..3e3f732 100644 --- a/app/lib/main/app.dart +++ b/app/lib/main/app.dart @@ -24,7 +24,7 @@ class App extends StatelessWidget { return MultiBlocProvider( providers: [ BlocProvider(create: (_) => getIt()), - BlocProvider(create: (_) => getIt()), + BlocProvider(create: (_) => getIt()), ], child: BlocBuilder( builder: (context, state) { @@ -39,7 +39,7 @@ class App extends StatelessWidget { GlobalCupertinoLocalizations.delegate, ], builder: (context, child) { - return BlocListener( + return BlocListener( listener: (_, state) { if (state is Success) { switch (state.data) { diff --git a/app/lib/presentation/ui/pages/login/login_page.dart b/app/lib/presentation/ui/pages/login/login_page.dart index 3086dd3..8eb2545 100644 --- a/app/lib/presentation/ui/pages/login/login_page.dart +++ b/app/lib/presentation/ui/pages/login/login_page.dart @@ -56,7 +56,7 @@ class _Loading extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocBuilder( + return BlocBuilder( builder: (context, state) { return LoadingScreen( isLoading: state is Loading, diff --git a/modules/domain/lib/bloc/auth/auth_cubit.dart b/modules/domain/lib/bloc/auth/auth_cubit.dart index 7df2327..95a7d3d 100644 --- a/modules/domain/lib/bloc/auth/auth_cubit.dart +++ b/modules/domain/lib/bloc/auth/auth_cubit.dart @@ -1,11 +1,10 @@ import 'package:common/core/failure/failure.dart'; import 'package:common/core/resource.dart'; -import 'package:common/core/result_type.dart'; import 'package:domain/bloc/BaseBlocState.dart'; import 'package:domain/bloc/auth/auth_state.dart'; -class SessionCubit extends BaseBlocState { - SessionCubit() : super(Success(AuthStateUnknown())); +class AuthCubit extends BaseBlocState { + AuthCubit() : super(Success(AuthStateUnknown())); void isLogin() { isSuccess(AuthStateAuthenticated()); @@ -18,14 +17,4 @@ class SessionCubit extends BaseBlocState { void isUnknown() { isSuccess(AuthStateUnknown()); } - - @override - void onResult(ResultType result) { - switch (result) { - case TSuccess _: - isLogin(); - case TError _: - isError(result.error); - } - } } diff --git a/modules/domain/lib/bloc/auth/auth_state.dart b/modules/domain/lib/bloc/auth/auth_state.dart index a3e9573..4695c22 100644 --- a/modules/domain/lib/bloc/auth/auth_state.dart +++ b/modules/domain/lib/bloc/auth/auth_state.dart @@ -16,3 +16,8 @@ class AuthStateAuthenticated extends AuthState { class AuthStateUnauthenticated extends AuthState { AuthStateUnauthenticated() : super._(AuthStatus.unauthenticated); } + +class AuthStateError extends AuthState { + final String message; + AuthStateError(this.message) : super._(AuthStatus.unknown); +} diff --git a/modules/domain/lib/init.dart b/modules/domain/lib/init.dart index cdaaadc..90fbf2e 100644 --- a/modules/domain/lib/init.dart +++ b/modules/domain/lib/init.dart @@ -7,7 +7,7 @@ class DomainInit { static Future initialize(GetIt getIt) async { //Cubits getIt.registerSingleton(AppCubit(getIt())); - getIt.registerSingleton(SessionCubit()); + getIt.registerSingleton(AuthCubit()); //Services getIt.registerLazySingleton(() => AuthService(getIt(), getIt())); diff --git a/modules/domain/lib/services/AuthService.dart b/modules/domain/lib/services/AuthService.dart index 389ebe5..6680d3c 100644 --- a/modules/domain/lib/services/AuthService.dart +++ b/modules/domain/lib/services/AuthService.dart @@ -1,16 +1,23 @@ +import 'package:common/core/failure/failure.dart'; +import 'package:common/core/result_type.dart'; import 'package:domain/bloc/auth/auth_cubit.dart'; import 'package:domain/repositories/auth_repository.dart'; class AuthService { final AuthRepository _authRepository; - final SessionCubit _sessionCubit; + final AuthCubit _sessionCubit; AuthService(this._authRepository, this._sessionCubit); - void logInWithCredentials(String username, String password) async { + Future logInWithCredentials(String username, String password) async { _sessionCubit.isLoading(); final result = await _authRepository.login(username, password); - _sessionCubit.onResult(result); + switch (result) { + case TSuccess _: + _sessionCubit.isLogin(); + case TError _: + _sessionCubit.isError(result.error); + } } void onValidate() { @@ -21,7 +28,7 @@ class AuthService { } } - void onLogout() async { + Future onLogout() async { await _authRepository.logout(); _sessionCubit.isLogOut(); } diff --git a/modules/domain/pubspec.yaml b/modules/domain/pubspec.yaml index e09f918..d8f2535 100644 --- a/modules/domain/pubspec.yaml +++ b/modules/domain/pubspec.yaml @@ -24,7 +24,7 @@ dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 - + mocktail: ^1.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/modules/domain/test/auth_cubit_test.dart b/modules/domain/test/auth_cubit_test.dart new file mode 100644 index 0000000..5c7d271 --- /dev/null +++ b/modules/domain/test/auth_cubit_test.dart @@ -0,0 +1,48 @@ +import 'package:common/core/resource.dart'; +import 'package:domain/bloc/auth/auth_cubit.dart'; +import 'package:domain/bloc/auth/auth_state.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('AuthCubit', () { + late AuthCubit cubit; + + setUp(() { + cubit = AuthCubit(); + }); + + tearDown(() { + cubit.close(); + }); + + test('emits AuthStateAuthenticated when isLogin is called', () { + cubit.isLogin(); + + expect(cubit.state, isA>()); + + final successState = cubit.state as Success; + + expect(successState.data, isA()); + }); + + test('emits AuthStateUnauthenticated when isLogOut is called', () { + cubit.isLogOut(); + + expect(cubit.state, isA>()); + + final successState = cubit.state as Success; + + expect(successState.data, isA()); + }); + + test('emits AuthStateUnknown when isUnknown is called', () { + cubit.isUnknown(); + + expect(cubit.state, isA>()); + + final successState = cubit.state as Success; + + expect(successState.data, isA()); + }); + }); +} diff --git a/modules/domain/test/auth_service_test.dart b/modules/domain/test/auth_service_test.dart new file mode 100644 index 0000000..eb6f284 --- /dev/null +++ b/modules/domain/test/auth_service_test.dart @@ -0,0 +1,87 @@ +import 'package:common/core/failure/failure.dart'; +import 'package:common/core/result_type.dart'; +import 'package:domain/bloc/auth/auth_cubit.dart'; +import 'package:domain/repositories/auth_repository.dart'; +import 'package:domain/services/AuthService.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class MockAuthRepository extends Mock implements AuthRepository {} + +class MockSessionCubit extends Mock implements AuthCubit {} + +void main() { + late AuthRepository mockAuthRepository; + late AuthCubit mockSessionCubit; + late AuthService authService; + + const username = 'testuser'; + const password = 'password123'; + final failure = Exception('Invalid credentials'); + + setUp(() { + mockAuthRepository = MockAuthRepository(); + mockSessionCubit = MockSessionCubit(); + authService = AuthService(mockAuthRepository, mockSessionCubit); + }); + + group('AuthService', () { + test('logInWithCredentials calls isLogin on success', () async { + when(() => mockAuthRepository.login(username, password)) + .thenAnswer((_) async => TSuccess(null)); + when(() => mockSessionCubit.isLoading()).thenReturn(null); + when(() => mockSessionCubit.isLogin()).thenReturn(null); + + await authService.logInWithCredentials(username, password); + + verify(() => mockSessionCubit.isLoading()).called(1); + verify(() => mockSessionCubit.isLogin()).called(1); + verifyNever(() => mockSessionCubit.isError(any())); + }); + + test('logInWithCredentials calls isError on failure', () async { + when(() => mockAuthRepository.login(username, password)) + .thenAnswer((_) async => TError(failure)); + when(() => mockSessionCubit.isLoading()).thenReturn(null); + when(() => mockSessionCubit.isError(failure)).thenReturn(null); + + await authService.logInWithCredentials(username, password); + + verify(() => mockSessionCubit.isLoading()).called(1); + verify(() => mockSessionCubit.isError(failure)).called(1); + verifyNever(() => mockSessionCubit.isLogin()); + }); + + test('onValidate calls isLogin when user is logged in', () { + when(() => mockAuthRepository.isLoggedIn()).thenReturn(true); + when(() => mockSessionCubit.isLogin()).thenReturn(null); + + authService.onValidate(); + + verify(() => mockAuthRepository.isLoggedIn()).called(1); + verify(() => mockSessionCubit.isLogin()).called(1); + verifyNever(() => mockSessionCubit.isLogOut()); + }); + + test('onValidate calls isLogOut when user is not logged in', () { + when(() => mockAuthRepository.isLoggedIn()).thenReturn(false); + when(() => mockSessionCubit.isLogOut()).thenReturn(null); + + authService.onValidate(); + + verify(() => mockAuthRepository.isLoggedIn()).called(1); + verify(() => mockSessionCubit.isLogOut()).called(1); + verifyNever(() => mockSessionCubit.isLogin()); + }); + + test('onLogout calls logout and then isLogOut', () async { + when(() => mockAuthRepository.logout()).thenAnswer((_) async => {}); + when(() => mockSessionCubit.isLogOut()).thenReturn(null); + + await authService.onLogout(); + + verify(() => mockAuthRepository.logout()).called(1); + verify(() => mockSessionCubit.isLogOut()).called(1); + }); + }); +}