Skip to content

Commit

Permalink
TF-2928 Write unit test for validateUrgentException and onError i…
Browse files Browse the repository at this point in the history
…n BaseController
  • Loading branch information
dab246 authored and hoangdat committed Jul 17, 2024
1 parent c62248e commit 45e4cfa
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 35 deletions.
8 changes: 4 additions & 4 deletions lib/features/base/base_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ abstract class BaseController extends GetxController
html.window.onUnload.listen(handleBrowserReloadAction);
}

Future<void> handleBrowserBeforeReloadAction(html.Event event) async {}
Future<void> handleBrowserBeforeReloadAction(html.Event event) async {}

Future<void> handleBrowserReloadAction(html.Event event) async {}

Expand Down Expand Up @@ -141,7 +141,7 @@ abstract class BaseController extends GetxController
viewState.value.fold(
(failure) {
if (failure is FeatureFailure) {
final isUrgentException = _validateUrgentException(failure.exception);
final isUrgentException = validateUrgentException(failure.exception);
if (isUrgentException) {
handleUrgentException(failure: failure, exception: failure.exception);
} else {
Expand All @@ -156,7 +156,7 @@ abstract class BaseController extends GetxController

void onError(dynamic error, StackTrace stackTrace) {
logError('$runtimeType::onError():Error: $error | StackTrace: $stackTrace');
final isUrgentException = _validateUrgentException(error);
final isUrgentException = validateUrgentException(error);
if (isUrgentException) {
handleUrgentException(exception: error);
} else {
Expand All @@ -166,7 +166,7 @@ abstract class BaseController extends GetxController

void onDone() {}

bool _validateUrgentException(dynamic exception) {
bool validateUrgentException(dynamic exception) {
return exception is NoNetworkError
|| exception is BadCredentialsException
|| exception is ConnectionError;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,10 @@ abstract class AuthenticationException extends RemoteException {

class BadCredentials extends AuthenticationException {
BadCredentials() : super(AuthenticationException.wrongCredential);

@override
List<Object?> get props => [message];
}

class BadGateway extends AuthenticationException {
BadGateway() : super(AuthenticationException.badGateway);

@override
List<Object?> get props => [message];
}

class NotFoundAuthenticatedAccountException implements Exception {}
Expand All @@ -29,9 +23,6 @@ class NotFoundStoredTokenException implements Exception {}

class InvalidBaseUrl extends AuthenticationException {
InvalidBaseUrl() : super(AuthenticationException.invalidBaseUrl);

@override
List<Object?> get props => [message];
}

class NotFoundAccessTokenException implements Exception {}
Expand Down
26 changes: 4 additions & 22 deletions lib/main/exceptions/remote_exception.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,48 +15,33 @@ abstract class RemoteException with EquatableMixin implements Exception {
final int? code;

const RemoteException({this.code, this.message});

@override
List<Object?> get props => [message, code];
}

class BadCredentialsException extends RemoteException {
const BadCredentialsException() : super(message: RemoteException.badCredentials);

@override
List<Object?> get props => [];
}

class UnknownError extends RemoteException {
const UnknownError({int? code, Object? message}) : super(code: code, message: message);

@override
List<Object?> get props => [code, message];
}

class ConnectionError extends RemoteException {
const ConnectionError({String? message}) : super(message: message ?? RemoteException.connectionError);

@override
List<Object?> get props => [code, message];
}

class ConnectionTimeout extends RemoteException {
const ConnectionTimeout({String? message}) : super(message: message ?? RemoteException.connectionTimeout);

@override
List<Object?> get props => [code, message];
}

class SocketError extends RemoteException {
const SocketError() : super(message: RemoteException.socketException);

@override
List<Object?> get props => [code, message];
}

class InternalServerError extends RemoteException {
const InternalServerError() : super(message: RemoteException.internalServerError);

@override
List<Object?> get props => [code, message];
}

class MethodLevelErrors extends RemoteException {
Expand All @@ -68,7 +53,7 @@ class MethodLevelErrors extends RemoteException {
) : super(message: message);

@override
List<Object?> get props => [type, code, message];
List<Object?> get props => [type, ...super.props];
}

class CannotCalculateChangesMethodResponseException extends MethodLevelErrors {
Expand All @@ -77,7 +62,4 @@ class CannotCalculateChangesMethodResponseException extends MethodLevelErrors {

class NoNetworkError extends RemoteException {
const NoNetworkError() : super(message: RemoteException.noNetworkError);

@override
List<Object?> get props => [code, message];
}
199 changes: 199 additions & 0 deletions test/features/base/base_controller_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import 'package:core/data/network/config/dynamic_url_interceptors.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/utils/app_toast.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/utils/application_manager.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:get/get.dart';
import 'package:mockito/annotations.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart';
import 'package:tmail_ui_user/features/caching/caching_manager.dart';
import 'package:tmail_ui_user/features/login/data/network/interceptors/authorization_interceptors.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart';
import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart';
import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart';
import 'package:tmail_ui_user/main/bindings/network/binding_tag.dart';
import 'package:tmail_ui_user/main/exceptions/remote_exception.dart';
import 'package:uuid/uuid.dart';

import 'base_controller_test.mocks.dart';

class MockBaseController extends BaseController {

bool isUrgentExceptionEnable = false;
bool isErrorViewStateEnable = false;

void resetState() {
isUrgentExceptionEnable = false;
isErrorViewStateEnable = false;
}

@override
void handleErrorViewState(Object error, StackTrace stackTrace) {
super.handleErrorViewState(error, stackTrace);
isErrorViewStateEnable = true;
}

@override
void handleUrgentException({Failure? failure, Exception? exception}) {
super.handleUrgentException(failure: failure, exception: exception);
isUrgentExceptionEnable = true;
}
}

class SomeOtherException extends RemoteException {}

@GenerateNiceMocks([
MockSpec<CachingManager>(),
MockSpec<LanguageCacheManager>(),
MockSpec<AuthorizationInterceptors>(),
MockSpec<DynamicUrlInterceptors>(),
MockSpec<DeleteCredentialInteractor>(),
MockSpec<LogoutOidcInteractor>(),
MockSpec<DeleteAuthorityOidcInteractor>(),
MockSpec<AppToast>(),
MockSpec<ImagePaths>(),
MockSpec<ResponsiveUtils>(),
MockSpec<Uuid>(),
MockSpec<ApplicationManager>(),
])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();

late MockBaseController mockBaseController;
late MockCachingManager mockCachingManager;
late MockLanguageCacheManager mockLanguageCacheManager;
late MockAuthorizationInterceptors mockAuthorizationInterceptors;
late MockDynamicUrlInterceptors mockDynamicUrlInterceptors;
late MockDeleteCredentialInteractor mockDeleteCredentialInteractor;
late MockLogoutOidcInteractor mockLogoutOidcInteractor;
late MockDeleteAuthorityOidcInteractor mockDeleteAuthorityOidcInteractor;
late MockAppToast mockAppToast;
late MockImagePaths mockImagePaths;
late MockResponsiveUtils mockResponsiveUtils;
late MockUuid mockUuid;
late MockApplicationManager mockApplicationManager;

setUpAll(() {
mockCachingManager = MockCachingManager();
mockLanguageCacheManager = MockLanguageCacheManager();
mockAuthorizationInterceptors = MockAuthorizationInterceptors();
mockDynamicUrlInterceptors = MockDynamicUrlInterceptors();
mockDeleteCredentialInteractor = MockDeleteCredentialInteractor();
mockLogoutOidcInteractor = MockLogoutOidcInteractor();
mockDeleteAuthorityOidcInteractor = MockDeleteAuthorityOidcInteractor();
mockAppToast = MockAppToast();
mockImagePaths = MockImagePaths();
mockResponsiveUtils = MockResponsiveUtils();
mockUuid = MockUuid();
mockApplicationManager = MockApplicationManager();

Get.put<CachingManager>(mockCachingManager);
Get.put<LanguageCacheManager>(mockLanguageCacheManager);
Get.put<AuthorizationInterceptors>(mockAuthorizationInterceptors);
Get.put<AuthorizationInterceptors>(
mockAuthorizationInterceptors,
tag: BindingTag.isolateTag,
);
Get.put<DynamicUrlInterceptors>(mockDynamicUrlInterceptors);
Get.put<DeleteCredentialInteractor>(mockDeleteCredentialInteractor);
Get.put<LogoutOidcInteractor>(mockLogoutOidcInteractor);
Get.put<DeleteAuthorityOidcInteractor>(mockDeleteAuthorityOidcInteractor);
Get.put<AppToast>(mockAppToast);
Get.put<ImagePaths>(mockImagePaths);
Get.put<ResponsiveUtils>(mockResponsiveUtils);
Get.put<Uuid>(mockUuid);
Get.put<ApplicationManager>(mockApplicationManager);
Get.testMode = true;

mockBaseController = MockBaseController();
});

group('BaseController::validateUrgentException', () {
test('should return true when exception is NoNetworkError', () {
expect(mockBaseController.validateUrgentException(const NoNetworkError()), isTrue);
});

test('should return true when exception is BadCredentialsException', () {
expect(mockBaseController.validateUrgentException(const BadCredentialsException()), isTrue);
});

test('should return true when exception is ConnectionError', () {
expect(mockBaseController.validateUrgentException(const ConnectionError()), isTrue);
});

test('should return false when exception is SomeOtherException', () {
expect(mockBaseController.validateUrgentException(SomeOtherException()), isFalse);
});

test('should return false when exception is null', () {
expect(mockBaseController.validateUrgentException(null), isFalse);
});

test('should return false when exceptions are other types', () {
expect(mockBaseController.validateUrgentException('StringException'), isFalse);
expect(mockBaseController.validateUrgentException(123), isFalse);
expect(mockBaseController.validateUrgentException(Object()), isFalse);
});
});

group('BaseController::onError', () {
test('handleUrgentException should called when error is NoNetworkError', () {
// arrange
const error = NoNetworkError();
final stackTrace = StackTrace.current;

// act
mockBaseController.resetState();
mockBaseController.onError(error, stackTrace);

// assert
expect(mockBaseController.isUrgentExceptionEnable, true);
expect(mockBaseController.isErrorViewStateEnable, false);
});

test('handleUrgentException should called when error is BadCredentialsException', () {
// arrange
const error = BadCredentialsException();
final stackTrace = StackTrace.current;

// act
mockBaseController.resetState();
mockBaseController.onError(error, stackTrace);

// assert
expect(mockBaseController.isUrgentExceptionEnable, true);
expect(mockBaseController.isErrorViewStateEnable, false);
});

test('handleUrgentException should called when error is ConnectionError', () {
// arrange
const error = ConnectionError();
final stackTrace = StackTrace.current;

// act
mockBaseController.resetState();
mockBaseController.onError(error, stackTrace);

// assert
expect(mockBaseController.isUrgentExceptionEnable, true);
expect(mockBaseController.isErrorViewStateEnable, false);
});

test('handleErrorViewState should called when error is SomeOtherException', () {
// arrange
final error = SomeOtherException();
final stackTrace = StackTrace.current;

// act
mockBaseController.resetState();
mockBaseController.onError(error, stackTrace);

// assert
expect(mockBaseController.isErrorViewStateEnable, true);
expect(mockBaseController.isUrgentExceptionEnable, false);
});
});
}

0 comments on commit 45e4cfa

Please sign in to comment.