Skip to content

Added unit test for auth_cubit and auth_service #101

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

Merged
merged 3 commits into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/lib/main/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class App extends StatelessWidget {
return MultiBlocProvider(
providers: [
BlocProvider(create: (_) => getIt<AppCubit>()),
BlocProvider(create: (_) => getIt<SessionCubit>()),
BlocProvider(create: (_) => getIt<AuthCubit>()),
],
child: BlocBuilder<AppCubit, AppState>(
builder: (context, state) {
Expand All @@ -39,7 +39,7 @@ class App extends StatelessWidget {
GlobalCupertinoLocalizations.delegate,
],
builder: (context, child) {
return BlocListener<SessionCubit, Resource>(
return BlocListener<AuthCubit, Resource>(
listener: (_, state) {
if (state is Success<AuthState>) {
switch (state.data) {
Expand Down
2 changes: 1 addition & 1 deletion app/lib/presentation/ui/pages/login/login_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class _Loading extends StatelessWidget {

@override
Widget build(BuildContext context) {
return BlocBuilder<SessionCubit, Resource>(
return BlocBuilder<AuthCubit, Resource>(
builder: (context, state) {
return LoadingScreen(
isLoading: state is Loading,
Expand Down
15 changes: 2 additions & 13 deletions modules/domain/lib/bloc/auth/auth_cubit.dart
Original file line number Diff line number Diff line change
@@ -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<AuthState, Failure> {
SessionCubit() : super(Success(AuthStateUnknown()));
class AuthCubit extends BaseBlocState<AuthState, Failure> {
AuthCubit() : super(Success(AuthStateUnknown()));

void isLogin() {
isSuccess(AuthStateAuthenticated());
Expand All @@ -18,14 +17,4 @@ class SessionCubit extends BaseBlocState<AuthState, Failure> {
void isUnknown() {
isSuccess(AuthStateUnknown());
}

@override
void onResult(ResultType<void, Failure> result) {
switch (result) {
case TSuccess<void, Failure> _:
isLogin();
case TError<void, Failure> _:
isError(result.error);
}
}
}
5 changes: 5 additions & 0 deletions modules/domain/lib/bloc/auth/auth_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
2 changes: 1 addition & 1 deletion modules/domain/lib/init.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class DomainInit {
static Future<void> initialize(GetIt getIt) async {
//Cubits
getIt.registerSingleton(AppCubit(getIt()));
getIt.registerSingleton(SessionCubit());
getIt.registerSingleton(AuthCubit());

//Services
getIt.registerLazySingleton(() => AuthService(getIt(), getIt()));
Expand Down
15 changes: 11 additions & 4 deletions modules/domain/lib/services/AuthService.dart
Original file line number Diff line number Diff line change
@@ -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<void> logInWithCredentials(String username, String password) async {
_sessionCubit.isLoading();
final result = await _authRepository.login(username, password);
_sessionCubit.onResult(result);
switch (result) {
case TSuccess<void, Failure> _:
_sessionCubit.isLogin();
case TError<void, Failure> _:
_sessionCubit.isError(result.error);
}
}

void onValidate() {
Expand All @@ -21,7 +28,7 @@ class AuthService {
}
}

void onLogout() async {
Future<void> onLogout() async {
await _authRepository.logout();
_sessionCubit.isLogOut();
}
Expand Down
2 changes: 1 addition & 1 deletion modules/domain/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
48 changes: 48 additions & 0 deletions modules/domain/test/auth_cubit_test.dart
Original file line number Diff line number Diff line change
@@ -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<Success<AuthState>>());

final successState = cubit.state as Success<AuthState>;

expect(successState.data, isA<AuthStateAuthenticated>());
});

test('emits AuthStateUnauthenticated when isLogOut is called', () {
cubit.isLogOut();

expect(cubit.state, isA<Success<AuthState>>());

final successState = cubit.state as Success<AuthState>;

expect(successState.data, isA<AuthStateUnauthenticated>());
});

test('emits AuthStateUnknown when isUnknown is called', () {
cubit.isUnknown();

expect(cubit.state, isA<Success<AuthState>>());

final successState = cubit.state as Success<AuthState>;

expect(successState.data, isA<AuthStateUnknown>());
});
});
}
87 changes: 87 additions & 0 deletions modules/domain/test/auth_service_test.dart
Original file line number Diff line number Diff line change
@@ -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);
});
});
}
Loading