From 91051627a2e08ecbbad5e9fc6460846fa5f8910a Mon Sep 17 00:00:00 2001 From: Parag Gupta <103507835+Dante291@users.noreply.github.com> Date: Sun, 7 Jan 2024 01:05:12 +0530 Subject: [PATCH] Refactor: Decouple ViewModel by Moving UI Logic to View (#2306) * Refactor: Decouple ViewModel by Moving UI Logic to View * refactoring app_settings_view_model and app_seetings_page * writing test for missing lines --- .../app_setting_view_model.dart | 48 +----------- .../app_settings/app_settings_page.dart | 33 +++++++- .../app_setting_view_model_test.dart | 76 +------------------ .../app_settings/app_setting_page_test.dart | 22 +++++- 4 files changed, 56 insertions(+), 123 deletions(-) diff --git a/lib/view_model/after_auth_view_models/settings_view_models/app_setting_view_model.dart b/lib/view_model/after_auth_view_models/settings_view_models/app_setting_view_model.dart index 2438020590..2a63951eec 100644 --- a/lib/view_model/after_auth_view_models/settings_view_models/app_setting_view_model.dart +++ b/lib/view_model/after_auth_view_models/settings_view_models/app_setting_view_model.dart @@ -1,18 +1,11 @@ -import 'package:flutter/material.dart'; -import 'package:talawa/enums/enums.dart'; import 'package:talawa/locator.dart'; -import 'package:talawa/services/navigation_service.dart'; import 'package:talawa/view_model/base_view_model.dart'; -import 'package:talawa/widgets/custom_alert_dialog.dart'; -import 'package:talawa/widgets/talawa_error_dialog.dart'; import 'package:url_launcher/url_launcher_string.dart'; /// ViewModel for the App Settings functionality. /// /// This ViewModel handles the logic and data for the application settings. class AppSettingViewModel extends BaseModel { - // Services - final _navigationService = locator(); // final _appLanguageService = locator(); /// This method destroys the user's session or sign out the user from app, The function asks for the confimation in Custom Alert Dialog. @@ -22,9 +15,9 @@ class AppSettingViewModel extends BaseModel { /// /// **returns**: /// * `Future`: Resolves when user logout - Future logout(BuildContext context) async { + Future logout() async { // push custom alert dialog with the confirmation message. - _navigationService.pushDialog(logoutDialog()); + await userConfig.userLogOut(); } /// Launches a website using the provided URL. @@ -36,41 +29,4 @@ class AppSettingViewModel extends BaseModel { /// * `Future`: A [Future] that resolves to a [bool] value indicating /// whether the website launch was successful. Future launchWebsite(String url) async => await launchUrlString(url); - - /// Creates a custom alert dialog for the logout confirmation. - /// - /// This dialog prompts the user with a confirmation message for logout. - /// The dialog provides options to logout or cancel the operation. - /// - /// **params**: - /// None - /// - /// **returns**: - /// * `Widget`: A [Widget] representing the custom logout confirmation dialog. - Widget logoutDialog() { - return CustomAlertDialog( - reverse: true, - dialogSubTitle: 'Are you sure you want to logout?', - successText: 'Logout', - success: () async { - await userConfig.userLogOut(); - navigationService.pop(); - if (userConfig.loggedIn) { - navigationService.pushDialog( - const TalawaErrorDialog( - 'Unable to logout, please try again.', - key: Key('TalawaError'), - messageType: MessageType.error, - ), - ); - } else { - navigationService.removeAllAndPush( - '/selectLang', - '/', - arguments: '0', - ); - } - }, - ); - } } diff --git a/lib/views/after_auth_screens/app_settings/app_settings_page.dart b/lib/views/after_auth_screens/app_settings/app_settings_page.dart index 95f0294fc6..4fb2d30291 100644 --- a/lib/views/after_auth_screens/app_settings/app_settings_page.dart +++ b/lib/views/after_auth_screens/app_settings/app_settings_page.dart @@ -1,11 +1,14 @@ import 'package:flutter/material.dart'; import 'package:talawa/constants/routing_constants.dart'; +import 'package:talawa/enums/enums.dart'; import 'package:talawa/locator.dart'; import 'package:talawa/services/size_config.dart'; import 'package:talawa/utils/app_localization.dart'; import 'package:talawa/view_model/after_auth_view_models/settings_view_models/app_setting_view_model.dart'; import 'package:talawa/views/base_view.dart'; +import 'package:talawa/widgets/custom_alert_dialog.dart'; import 'package:talawa/widgets/lang_switch.dart'; +import 'package:talawa/widgets/talawa_error_dialog.dart'; import 'package:talawa/widgets/theme_switch.dart'; /// Widget representing the App Settings page. @@ -262,6 +265,7 @@ class AppSettingsPage extends StatelessWidget { children: [ customDivider(context: context), TextButton( + key: const Key('Logout'), child: Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, @@ -289,7 +293,34 @@ class AppSettingsPage extends StatelessWidget { ), onPressed: () { userConfig.loggedIn - ? model.logout(context) + ? showDialog( + context: context, + builder: (context) { + return CustomAlertDialog( + reverse: true, + dialogSubTitle: 'Are you sure you want to logout?', + successText: 'LogOut', + success: () async { + try { + await model.logout(); + navigationService.pop(); + navigationService.removeAllAndPush( + '/selectLang', + '/', + ); + } catch (e) { + navigationService.pushDialog( + const TalawaErrorDialog( + 'Unable to logout, please try again.', + key: Key('TalawaError'), + messageType: MessageType.error, + ), + ); + } + }, + ); + }, + ) : navigationService.pushScreen( Routes.setUrlScreen, arguments: '', diff --git a/test/view_model_tests/after_auth_view_model_tests/settings_view_models_test/app_setting_view_model_test.dart b/test/view_model_tests/after_auth_view_model_tests/settings_view_models_test/app_setting_view_model_test.dart index edcf1b768d..3827b490f7 100644 --- a/test/view_model_tests/after_auth_view_model_tests/settings_view_models_test/app_setting_view_model_test.dart +++ b/test/view_model_tests/after_auth_view_model_tests/settings_view_models_test/app_setting_view_model_test.dart @@ -3,24 +3,17 @@ import 'dart:io'; -import 'package:flutter/material.dart'; -import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:hive/hive.dart'; import 'package:mockito/mockito.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:talawa/models/organization/org_info.dart'; import 'package:talawa/models/user/user_info.dart'; -import 'package:talawa/router.dart' as router; import 'package:talawa/services/size_config.dart'; -import 'package:talawa/utils/app_localization.dart'; import 'package:talawa/view_model/after_auth_view_models/settings_view_models/app_setting_view_model.dart'; -import 'package:talawa/view_model/lang_view_model.dart'; -import 'package:talawa/views/base_view.dart'; import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; import '../../../helpers/test_helpers.dart'; import '../../../helpers/test_locator.dart'; -import '../../../router_test.dart'; class MockUrlLauncher extends Mock with MockPlatformInterfaceMixin @@ -64,74 +57,7 @@ void main() async { test('Test logout function.', () { final model = AppSettingViewModel(); - final context = MockBuildContext(); - model.logout(context); - }); - - testWidgets("Test logout dialog when logout successful.", (tester) async { - const userLoggedin = false; - when(userConfig.loggedIn).thenAnswer((_) => userLoggedin); - final model = AppSettingViewModel(); - - final widget = BaseView( - onModelReady: (model) => model.initialize(), - builder: (context, langModel, child) { - return MaterialApp( - locale: const Locale('en'), - localizationsDelegates: [ - const AppLocalizationsDelegate(isTest: true), - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ], - home: Scaffold( - body: model.logoutDialog(), - ), - navigatorKey: navigationService.navigatorKey, - onGenerateRoute: router.generateRoute, - ); - }, - ); - - await tester.pumpWidget(widget); - await tester.pumpAndSettle(); - - await tester.tap(find.textContaining('Logout')); - await tester.pumpAndSettle(); - - verify(navigationService.navigatorKey); - }); - - testWidgets("Test logout dialog when logout unsuccessful.", (tester) async { - final model = AppSettingViewModel(); - const userLoggedIn = true; - when(userConfig.loggedIn).thenAnswer((_) => userLoggedIn); - - final widget = BaseView( - onModelReady: (model) => model.initialize(), - builder: (context, langModel, child) { - return MaterialApp( - locale: const Locale('en'), - localizationsDelegates: [ - const AppLocalizationsDelegate(isTest: true), - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ], - home: Scaffold( - body: model.logoutDialog(), - ), - navigatorKey: navigationService.navigatorKey, - onGenerateRoute: router.generateRoute, - ); - }, - ); - - await tester.pumpWidget(widget); - await tester.pumpAndSettle(); - - await tester.tap(find.textContaining('Logout')); - await tester.pumpAndSettle(); - - verify(navigationService.navigatorKey); + model.logout(); }); test('test for launchWebsite method', () async { diff --git a/test/widget_tests/after_auth_screens/app_settings/app_setting_page_test.dart b/test/widget_tests/after_auth_screens/app_settings/app_setting_page_test.dart index 58742d74d7..2705a21811 100644 --- a/test/widget_tests/after_auth_screens/app_settings/app_setting_page_test.dart +++ b/test/widget_tests/after_auth_screens/app_settings/app_setting_page_test.dart @@ -14,6 +14,7 @@ import 'package:talawa/services/graphql_config.dart'; import 'package:talawa/services/navigation_service.dart'; import 'package:talawa/services/size_config.dart'; import 'package:talawa/utils/app_localization.dart'; +import 'package:talawa/view_model/after_auth_view_models/settings_view_models/app_setting_view_model.dart'; import 'package:talawa/view_model/lang_view_model.dart'; import 'package:talawa/view_model/theme_view_model.dart'; import 'package:talawa/views/after_auth_screens/app_settings/app_settings_page.dart'; @@ -271,7 +272,10 @@ Future main() async { await tester.pumpWidget(createChangePassScreenDark()); await tester.pumpAndSettle(); - final logoutButton = find.textContaining('Logout'); + await tester.tap(find.byKey(const Key('Logout'))); + await tester.pumpAndSettle(); + + final logoutButton = find.textContaining('LogOut'); await tester.tap(logoutButton); unregisterServices(); @@ -288,5 +292,21 @@ Future main() async { verify(navigationService.navigatorKey); }); + testWidgets('Test if Logout is unsuccessful.', (tester) async { + final model = AppSettingViewModel(); + when(model.logout()).thenThrow(Exception('Test error')); + + const userLoggedIn = true; + when(userConfig.loggedIn).thenAnswer((_) => userLoggedIn); + + await tester.pumpWidget(createChangePassScreenDark()); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key('Logout'))); + await tester.pumpAndSettle(); + + final logoutButton = find.textContaining('LogOut'); + await tester.tap(logoutButton); + }); }); }