Skip to content
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

TF-2889 Unit test possibilities of auto log out #2897

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
148 changes: 148 additions & 0 deletions test/features/base/base_controller_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
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:dartz/dartz.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:get/get.dart';
import 'package:mockito/mockito.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 '../email/presentation/controller/single_email_controller_test.mocks.dart';

class TestBaseController extends BaseController {
bool isLogoutCalled = false;

@override
void goToLogin() {
isLogoutCalled = true;
super.goToLogin();
}
}

class TestFeatureFailure extends FeatureFailure {
TestFeatureFailure({super.exception});
}

void main() {
TestWidgetsFlutterBinding.ensureInitialized();

// mock base controller Get dependencies
final cachingManager = MockCachingManager();
final languageCacheManager = MockLanguageCacheManager();
final authorizationInterceptors = MockAuthorizationInterceptors();
final dynamicUrlInterceptors = MockDynamicUrlInterceptors();
final deleteCredentialInteractor = MockDeleteCredentialInteractor();
final logoutOidcInteractor = MockLogoutOidcInteractor();
final deleteAuthorityOidcInteractor = MockDeleteAuthorityOidcInteractor();
final appToast = MockAppToast();
final imagePaths = MockImagePaths();
final responsiveUtils = MockResponsiveUtils();
final uuid = MockUuid();

late TestBaseController baseController;

setUp(() {
Get.put<CachingManager>(cachingManager);
Get.put<LanguageCacheManager>(languageCacheManager);
Get.put<AuthorizationInterceptors>(authorizationInterceptors);
Get.put<AuthorizationInterceptors>(
authorizationInterceptors,
tag: BindingTag.isolateTag,
);
Get.put<DynamicUrlInterceptors>(dynamicUrlInterceptors);
Get.put<DeleteCredentialInteractor>(deleteCredentialInteractor);
Get.put<LogoutOidcInteractor>(logoutOidcInteractor);
Get.put<DeleteAuthorityOidcInteractor>(deleteAuthorityOidcInteractor);
Get.put<AppToast>(appToast);
Get.put<ImagePaths>(imagePaths);
Get.put<ResponsiveUtils>(responsiveUtils);
Get.put<Uuid>(uuid);

baseController = TestBaseController();

Get.testMode = true;
});

group('base controller test:', () {
test(
'SHOULD log user out '
'WHEN any data received is failure '
'AND the exception is ConnectionError',
() async {
// arrange
when(authorizationInterceptors.isAppRunning).thenReturn(true);

// act
baseController.onData(Left(TestFeatureFailure(
exception: const ConnectionError())));
await Future.delayed(const Duration(milliseconds: 500));

// assert
expect(baseController.isLogoutCalled, true);
});

test(
'SHOULD log user out '
'WHEN any data received is failure '
'AND the exception is BadCredentialsException',
() async {
// arrange
when(authorizationInterceptors.isAppRunning).thenReturn(true);

// act
baseController.onData(Left(TestFeatureFailure(
exception: const BadCredentialsException())));
await Future.delayed(const Duration(milliseconds: 500));

// assert
expect(baseController.isLogoutCalled, true);
});

test(
'SHOULD log user out '
'WHEN the stream consumed throw an exception '
'AND the exception is ConnectionError',
() async {
// arrange
when(authorizationInterceptors.isAppRunning).thenReturn(true);

// act
baseController.onError(
const ConnectionError(),
StackTrace.empty);
await Future.delayed(const Duration(milliseconds: 500));

// assert
expect(baseController.isLogoutCalled, true);
});

test(
'SHOULD log user out '
'WHEN the stream consumed throw an exception '
'AND the exception is BadCredentialsException',
() async {
// arrange
when(authorizationInterceptors.isAppRunning).thenReturn(true);

// act
baseController.onError(
const BadCredentialsException(),
StackTrace.empty);
await Future.delayed(const Duration(milliseconds: 500));

// assert
expect(baseController.isLogoutCalled, true);
});
});
}
57 changes: 57 additions & 0 deletions test/features/home/presentation/home_controller_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,22 @@ import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:model/account/authentication_type.dart';
import 'package:model/account/password.dart';
import 'package:model/account/personal_account.dart';
import 'package:tmail_ui_user/features/caching/caching_manager.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_email_cache_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_url_cache_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_username_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_search_cache_interactor.dart';
import 'package:tmail_ui_user/features/home/domain/state/get_session_state.dart';
import 'package:tmail_ui_user/features/home/domain/usecases/get_session_interactor.dart';
import 'package:tmail_ui_user/features/home/presentation/home_controller.dart';
import 'package:tmail_ui_user/features/login/data/network/interceptors/authorization_interceptors.dart';
import 'package:tmail_ui_user/features/login/domain/state/get_credential_state.dart';
import 'package:tmail_ui_user/features/login/domain/state/get_stored_token_oidc_state.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';
Expand All @@ -32,6 +37,23 @@ import '../../email/presentation/controller/single_email_controller_test.mocks.d
import '../../mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.mocks.dart';
import 'home_controller_test.mocks.dart';

class TestHomeController extends HomeController {
TestHomeController(
super.cleanupEmailCacheInteractor,
super.emailReceiveManager,
super.cleanupRecentSearchCacheInteractor,
super.cleanupRecentLoginUrlCacheInteractor,
super.cleanupRecentLoginUsernameCacheInteractor);

bool goToLoginCalled = false;

@override
void goToLogin() {
goToLoginCalled = true;
super.goToLogin();
}
}

@GenerateNiceMocks([
MockSpec<CleanupEmailCacheInteractor>(),
MockSpec<CleanupRecentSearchCacheInteractor>(),
Expand Down Expand Up @@ -135,4 +157,39 @@ void main() {
verifyNever(mockAppToast.showToastErrorMessage(any, any));
});
});

group("HomeController: Auto log out feature test:", () {
test(
'SHOULD log user out '
'WHEN user logged in with basic auth '
'AND user reloads TwakeMail '
'AND the app fails to get user session',
() async {
// arrange
when(mockGetAuthenticatedAccountInteractor.execute(stateChange: anyNamed('stateChange')))
.thenAnswer((_) => Stream.value(Right(GetCredentialViewState(
Uri.parse('https://test.com'),
UserName('value'),
Password('value'),
PersonalAccount(
'abc123',
AuthenticationType.basic,
isSelected: true)))));
when(mockGetSessionInteractor.execute(stateChange: anyNamed('stateChange')))
.thenAnswer((_) => Stream.value(Left(GetSessionFailure(Exception()))));
final homeController = TestHomeController(
cleanupEmailCacheInteractor,
emailReceiveManager,
cleanupRecentSearchCacheInteractor,
cleanupRecentLoginUrlCacheInteractor,
cleanupRecentLoginUsernameCacheInteractor);

// act
homeController.onReady();
await Future.delayed(const Duration(microseconds: 500));

// assert
expect(homeController.goToLoginCalled, true);
});
});
}
Loading
Loading