diff --git a/lib/locator.dart b/lib/locator.dart index 495e8fad1..4885321ca 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -1,5 +1,6 @@ import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:get_it/get_it.dart'; +import 'package:http/http.dart' as http; import 'package:image_cropper/image_cropper.dart'; import 'package:image_picker/image_picker.dart'; import 'package:talawa/main.dart'; @@ -14,6 +15,7 @@ import 'package:talawa/services/org_service.dart'; import 'package:talawa/services/post_service.dart'; import 'package:talawa/services/session_manager.dart'; import 'package:talawa/services/size_config.dart'; +import 'package:talawa/services/third_party_service/connectivity_service.dart'; import 'package:talawa/services/third_party_service/multi_media_pick_service.dart'; import 'package:talawa/services/user_config.dart'; import 'package:talawa/utils/queries.dart'; @@ -68,6 +70,9 @@ final queries = locator(); ///GetIt for Connectivity. final connectivity = locator(); +///GetIt for ConnectivityService. +final connectivityService = locator(); + ///GetIt for OrganizationService. final organizationService = locator(); @@ -111,6 +116,8 @@ void setupLocator() { locator.registerLazySingleton(() => ImagePicker()); locator.registerLazySingleton(() => ImageCropper()); + locator.registerSingleton(ConnectivityService(client: http.Client())); + //graphql locator.registerSingleton(GraphqlConfig()); diff --git a/lib/services/third_party_service/connectivity_service.dart b/lib/services/third_party_service/connectivity_service.dart new file mode 100644 index 000000000..cec139a3e --- /dev/null +++ b/lib/services/third_party_service/connectivity_service.dart @@ -0,0 +1,175 @@ +import 'dart:async'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:http/http.dart' as http; +import 'package:talawa/locator.dart'; + +/// This class provides services related to network connectivity monitoring and handling. +/// +/// It includes methods for: +/// * Initializing the network service - [initConnectivity] +/// * Monitoring connectivity changes - [enableSubscription] +/// * Handling online and offline states - [_handleOnline], [_handleOffline] +/// * Checking reachability of a given URI - [isReachable] +/// * Handling the device's connectivity status - [handleConnection] +/// * Checking if the device has any type of network connection - [hasConnection] +class ConnectivityService { + /// This function is used to initialize the network service. + /// + /// **params**: + /// None + /// + /// **returns**: + /// None + ConnectivityService({required http.Client client}) { + _client = client; + _connectionStatusController = StreamController(); + initConnectivity(); + } + + /// Stream controller for network status changes + late StreamController _connectionStatusController; + + /// Getter for the stream of connection status changes. + Stream get connectionStream => + _connectionStatusController.stream; + + /// Client to access internet. + late final http.Client _client; + + /// This function initializes connectivity monitoring. + /// + /// **params**: + /// None + /// + /// **returns**: + /// None + Future initConnectivity() async { + /// Try getting initial connectivity status + checkInitialConnection(); + + /// Listen for future changes in connectivity + enableSubscription(); + } + + /// This function checks the initial connection status. + /// + /// **params**: + /// None + /// + /// **returns**: + /// None + Future checkInitialConnection() async { + try { + final result = await connectivity.checkConnectivity(); + print(result); + _connectionStatusController.add(result); + handleConnection(result); + } catch (e) { + // Handle other exceptions + print('Error checking connectivity: $e'); + _connectionStatusController + .add(ConnectivityResult.none); // Assume no connection on error + handleConnection(ConnectivityResult.none); + } + } + + /// This function enables the subscription to connectivity changes. + /// + /// **params**: + /// None + /// + /// **returns**: + /// None + Future enableSubscription() async { + connectivity.onConnectivityChanged.listen( + (ConnectivityResult result) { + print(result); + _connectionStatusController.add(result); + handleConnection(result); + }, + onError: (error) { + // Handle errors during listening for changes + print('Error listening for connectivity changes: $error'); + }, + ); + } + + /// This function handles the actions to be taken when the device is online. + /// + /// **params**: + /// None + /// + /// **returns**: + /// None + Future _handleOnline() async { + // To be implemented. + } + + /// This function handles the actions to be taken when the device is offline. + /// + /// **params**: + /// None + /// + /// **returns**: + /// None + Future _handleOffline() async { + // To be implemented. + } + + /// This function checks if a given URI is reachable within a specified timeout period. + /// + /// **params**: + /// * `client`: An instance of `http.Client` to make the HTTP request. + /// * `uriString`: An optional `String` specifying the URI to check. + /// Defaults to 'http://www.google.com' if not provided. + /// + /// **returns**: + /// * `Future`: indicates if the url is reachable. + Future isReachable({ + http.Client? client, + String? uriString, + }) async { + try { + client ??= _client; + await client + .get(Uri.parse(uriString ?? 'http://www.google.com')) + .timeout(const Duration(seconds: 5)); + return true; + } catch (e) { + print('Timeout while checking reachability: $e'); + return false; + } + } + + /// This function handles the device's connectivity status based on the provided `ConnectivityResult`. + /// + /// **params**: + /// * `result`: A `ConnectivityResult` indicating the current connectivity status. + /// + /// **returns**: + /// None + Future handleConnection(ConnectivityResult result) async { + if (await hasConnection() && await isReachable(client: _client)) { + _handleOnline(); + } else { + _handleOffline(); + } + } + + /// This function checks if the device currently has any type of network connection. + /// + /// **params**: + /// None + /// + /// **returns**: + /// * `Future`: indicating whether the device has a network connection. + Future hasConnection() async { + try { + final result = await connectivity.checkConnectivity(); + return result != ConnectivityResult.none; + } catch (e) { + return false; + } + } +} diff --git a/test/helpers/test_helpers.dart b/test/helpers/test_helpers.dart index dfdae1de6..13fa5a84a 100644 --- a/test/helpers/test_helpers.dart +++ b/test/helpers/test_helpers.dart @@ -27,6 +27,7 @@ import 'package:talawa/services/org_service.dart'; import 'package:talawa/services/post_service.dart'; import 'package:talawa/services/session_manager.dart'; import 'package:talawa/services/size_config.dart'; +import 'package:talawa/services/third_party_service/connectivity_service.dart'; import 'package:talawa/services/third_party_service/multi_media_pick_service.dart'; import 'package:talawa/services/user_config.dart'; import 'package:talawa/utils/event_queries.dart'; @@ -50,6 +51,7 @@ import 'package:talawa/view_model/widgets_view_models/like_button_view_model.dar import 'package:talawa/view_model/widgets_view_models/progress_dialog_view_model.dart'; import '../service_tests/image_service_test.dart'; +import '../service_tests/third_party_service_test.dart/connectivity_service_test.dart'; import '../service_tests/user_config_test.dart'; import '../views/main_screen_test.dart'; import 'test_helpers.mocks.dart'; @@ -68,7 +70,6 @@ import 'test_helpers.mocks.dart'; MockSpec(onMissingStub: OnMissingStub.returnDefault), MockSpec(onMissingStub: OnMissingStub.returnDefault), MockSpec(onMissingStub: OnMissingStub.returnDefault), - MockSpec(onMissingStub: OnMissingStub.returnDefault), MockSpec( onMissingStub: OnMissingStub.returnDefault, ), @@ -650,20 +651,35 @@ EventService getAndRegisterEventService() { return service; } -/// `getAndRegisterConnectivityService` returns a mock instance of the `Connectivity` class. +/// `getAndRegisterConnectivity` returns a mock instance of the `Connectivity` class. /// /// **params**: /// None /// /// **returns**: /// * `Connectivity`: A mock instance of the `Connectivity` class. -Connectivity getAndRegisterConnectivityService() { +Connectivity getAndRegisterConnectivity() { _removeRegistrationIfExists(); final service = MockConnectivity(); locator.registerSingleton(service); return service; } +/// `getAndRegisterConnectivityService` returns a mock instance of the `ConnectivityService` class. +/// +/// **params**: +/// None +/// +/// **returns**: +/// * `ConnectivityService`: A mock instance of the `ConnectivityService` class. +ConnectivityService getAndRegisterConnectivityService() { + _removeRegistrationIfExists(); + final service = MockConnectivityService(); + locator.registerSingleton(service); + // when(service.) + return service; +} + /// `getPostMockModel` returns a mock instance of the `Post` class. /// /// **params**: @@ -862,6 +878,7 @@ void registerServices() { getAndRegisterPostService(); getAndRegisterEventService(); getAndRegisterMultiMediaPickerService(); + getAndRegisterConnectivity(); getAndRegisterConnectivityService(); getAndRegisterDatabaseMutationFunctions(); getAndRegisterOrganizationService(); @@ -886,6 +903,7 @@ void unregisterServices() { locator.unregister(); locator.unregister(); locator.unregister(); + locator.unregister(); locator.unregister(); locator.unregister(); locator.unregister(); diff --git a/test/helpers/test_helpers.mocks.dart b/test/helpers/test_helpers.mocks.dart index 017b54648..15fb06f8f 100644 --- a/test/helpers/test_helpers.mocks.dart +++ b/test/helpers/test_helpers.mocks.dart @@ -7,20 +7,17 @@ import 'dart:async' as _i5; import 'dart:io' as _i19; import 'dart:ui' as _i10; -import 'package:connectivity_plus/connectivity_plus.dart' as _i27; -import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart' - as _i28; import 'package:flutter/material.dart' as _i1; import 'package:graphql_flutter/graphql_flutter.dart' as _i3; -import 'package:image_cropper/src/cropper.dart' as _i41; +import 'package:image_cropper/src/cropper.dart' as _i39; import 'package:image_cropper_platform_interface/image_cropper_platform_interface.dart' - as _i42; + as _i40; import 'package:image_picker/image_picker.dart' as _i13; import 'package:mockito/mockito.dart' as _i2; import 'package:mockito/src/dummies.dart' as _i25; -import 'package:qr_code_scanner/src/qr_code_scanner.dart' as _i34; -import 'package:qr_code_scanner/src/types/barcode.dart' as _i35; -import 'package:qr_code_scanner/src/types/camera.dart' as _i36; +import 'package:qr_code_scanner/src/qr_code_scanner.dart' as _i32; +import 'package:qr_code_scanner/src/types/barcode.dart' as _i33; +import 'package:qr_code_scanner/src/types/camera.dart' as _i34; import 'package:qr_code_scanner/src/types/features.dart' as _i12; import 'package:talawa/enums/enums.dart' as _i14; import 'package:talawa/models/chats/chat_list_tile_data_model.dart' as _i22; @@ -30,29 +27,29 @@ import 'package:talawa/models/organization/org_info.dart' as _i6; import 'package:talawa/models/post/post_model.dart' as _i17; import 'package:talawa/models/user/user_info.dart' as _i7; import 'package:talawa/services/chat_service.dart' as _i21; -import 'package:talawa/services/comment_service.dart' as _i37; +import 'package:talawa/services/comment_service.dart' as _i35; import 'package:talawa/services/database_mutation_functions.dart' as _i9; import 'package:talawa/services/event_service.dart' as _i11; import 'package:talawa/services/graphql_config.dart' as _i15; import 'package:talawa/services/navigation_service.dart' as _i8; -import 'package:talawa/services/org_service.dart' as _i30; +import 'package:talawa/services/org_service.dart' as _i28; import 'package:talawa/services/post_service.dart' as _i16; import 'package:talawa/services/third_party_service/multi_media_pick_service.dart' as _i18; import 'package:talawa/services/user_config.dart' as _i24; -import 'package:talawa/utils/validators.dart' as _i33; +import 'package:talawa/utils/validators.dart' as _i31; import 'package:talawa/view_model/after_auth_view_models/chat_view_models/direct_chat_view_model.dart' - as _i40; + as _i38; import 'package:talawa/view_model/after_auth_view_models/event_view_models/create_event_view_model.dart' - as _i39; + as _i37; import 'package:talawa/view_model/after_auth_view_models/event_view_models/explore_events_view_model.dart' - as _i31; + as _i29; import 'package:talawa/view_model/after_auth_view_models/feed_view_models/organization_feed_view_model.dart' - as _i32; + as _i30; import 'package:talawa/view_model/lang_view_model.dart' as _i26; import 'package:talawa/view_model/pre_auth_view_models/signup_details_view_model.dart' - as _i29; -import 'package:talawa/view_model/theme_view_model.dart' as _i38; + as _i27; +import 'package:talawa/view_model/theme_view_model.dart' as _i36; import 'package:talawa/widgets/custom_alert_dialog.dart' as _i4; // ignore_for_file: type=lint @@ -1736,37 +1733,11 @@ class MockAppLanguage extends _i2.Mock implements _i26.AppLanguage { ); } -/// A class which mocks [Connectivity]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockConnectivity extends _i2.Mock implements _i27.Connectivity { - @override - _i5.Stream<_i28.ConnectivityResult> get onConnectivityChanged => - (super.noSuchMethod( - Invocation.getter(#onConnectivityChanged), - returnValue: _i5.Stream<_i28.ConnectivityResult>.empty(), - returnValueForMissingStub: _i5.Stream<_i28.ConnectivityResult>.empty(), - ) as _i5.Stream<_i28.ConnectivityResult>); - - @override - _i5.Future<_i28.ConnectivityResult> checkConnectivity() => - (super.noSuchMethod( - Invocation.method( - #checkConnectivity, - [], - ), - returnValue: _i5.Future<_i28.ConnectivityResult>.value( - _i28.ConnectivityResult.bluetooth), - returnValueForMissingStub: _i5.Future<_i28.ConnectivityResult>.value( - _i28.ConnectivityResult.bluetooth), - ) as _i5.Future<_i28.ConnectivityResult>); -} - /// A class which mocks [SignupDetailsViewModel]. /// /// See the documentation for Mockito's code generation for more information. class MockSignupDetailsViewModel extends _i2.Mock - implements _i29.SignupDetailsViewModel { + implements _i27.SignupDetailsViewModel { @override _i1.GlobalKey<_i1.FormState> get formKey => (super.noSuchMethod( Invocation.getter(#formKey), @@ -2557,7 +2528,7 @@ class MockDataBaseMutationFunctions extends _i2.Mock /// /// See the documentation for Mockito's code generation for more information. class MockOrganizationService extends _i2.Mock - implements _i30.OrganizationService { + implements _i28.OrganizationService { @override _i5.Future> getOrgMembersList(String? orgId) => (super.noSuchMethod( @@ -2575,7 +2546,7 @@ class MockOrganizationService extends _i2.Mock /// /// See the documentation for Mockito's code generation for more information. class MockExploreEventsViewModel extends _i2.Mock - implements _i31.ExploreEventsViewModel { + implements _i29.ExploreEventsViewModel { @override bool get demoMode => (super.noSuchMethod( Invocation.getter(#demoMode), @@ -2779,7 +2750,7 @@ class MockExploreEventsViewModel extends _i2.Mock /// /// See the documentation for Mockito's code generation for more information. class MockOrganizationFeedViewModel extends _i2.Mock - implements _i32.OrganizationFeedViewModel { + implements _i30.OrganizationFeedViewModel { @override bool get istest => (super.noSuchMethod( Invocation.getter(#istest), @@ -3009,7 +2980,7 @@ class MockOrganizationFeedViewModel extends _i2.Mock /// A class which mocks [Validator]. /// /// See the documentation for Mockito's code generation for more information. -class MockValidator extends _i2.Mock implements _i33.Validator { +class MockValidator extends _i2.Mock implements _i31.Validator { @override _i5.Future validateUrlExistence(String? url) => (super.noSuchMethod( Invocation.method( @@ -3024,13 +2995,13 @@ class MockValidator extends _i2.Mock implements _i33.Validator { /// A class which mocks [QRViewController]. /// /// See the documentation for Mockito's code generation for more information. -class MockQRViewController extends _i2.Mock implements _i34.QRViewController { +class MockQRViewController extends _i2.Mock implements _i32.QRViewController { @override - _i5.Stream<_i35.Barcode> get scannedDataStream => (super.noSuchMethod( + _i5.Stream<_i33.Barcode> get scannedDataStream => (super.noSuchMethod( Invocation.getter(#scannedDataStream), - returnValue: _i5.Stream<_i35.Barcode>.empty(), - returnValueForMissingStub: _i5.Stream<_i35.Barcode>.empty(), - ) as _i5.Stream<_i35.Barcode>); + returnValue: _i5.Stream<_i33.Barcode>.empty(), + returnValueForMissingStub: _i5.Stream<_i33.Barcode>.empty(), + ) as _i5.Stream<_i33.Barcode>); @override bool get hasPermissions => (super.noSuchMethod( @@ -3040,28 +3011,28 @@ class MockQRViewController extends _i2.Mock implements _i34.QRViewController { ) as bool); @override - _i5.Future<_i36.CameraFacing> getCameraInfo() => (super.noSuchMethod( + _i5.Future<_i34.CameraFacing> getCameraInfo() => (super.noSuchMethod( Invocation.method( #getCameraInfo, [], ), returnValue: - _i5.Future<_i36.CameraFacing>.value(_i36.CameraFacing.back), + _i5.Future<_i34.CameraFacing>.value(_i34.CameraFacing.back), returnValueForMissingStub: - _i5.Future<_i36.CameraFacing>.value(_i36.CameraFacing.back), - ) as _i5.Future<_i36.CameraFacing>); + _i5.Future<_i34.CameraFacing>.value(_i34.CameraFacing.back), + ) as _i5.Future<_i34.CameraFacing>); @override - _i5.Future<_i36.CameraFacing> flipCamera() => (super.noSuchMethod( + _i5.Future<_i34.CameraFacing> flipCamera() => (super.noSuchMethod( Invocation.method( #flipCamera, [], ), returnValue: - _i5.Future<_i36.CameraFacing>.value(_i36.CameraFacing.back), + _i5.Future<_i34.CameraFacing>.value(_i34.CameraFacing.back), returnValueForMissingStub: - _i5.Future<_i36.CameraFacing>.value(_i36.CameraFacing.back), - ) as _i5.Future<_i36.CameraFacing>); + _i5.Future<_i34.CameraFacing>.value(_i34.CameraFacing.back), + ) as _i5.Future<_i34.CameraFacing>); @override _i5.Future getFlashStatus() => (super.noSuchMethod( @@ -3160,7 +3131,7 @@ class MockQRViewController extends _i2.Mock implements _i34.QRViewController { /// A class which mocks [CommentService]. /// /// See the documentation for Mockito's code generation for more information. -class MockCommentService extends _i2.Mock implements _i37.CommentService { +class MockCommentService extends _i2.Mock implements _i35.CommentService { @override _i5.Future createComments( String? postId, @@ -3193,7 +3164,7 @@ class MockCommentService extends _i2.Mock implements _i37.CommentService { /// A class which mocks [AppTheme]. /// /// See the documentation for Mockito's code generation for more information. -class MockAppTheme extends _i2.Mock implements _i38.AppTheme { +class MockAppTheme extends _i2.Mock implements _i36.AppTheme { @override String get key => (super.noSuchMethod( Invocation.getter(#key), @@ -3304,7 +3275,7 @@ class MockAppTheme extends _i2.Mock implements _i38.AppTheme { /// /// See the documentation for Mockito's code generation for more information. class MockCreateEventViewModel extends _i2.Mock - implements _i39.CreateEventViewModel { + implements _i37.CreateEventViewModel { @override _i1.TextEditingController get eventTitleTextController => (super.noSuchMethod( Invocation.getter(#eventTitleTextController), @@ -4025,7 +3996,7 @@ class MockCreateEventViewModel extends _i2.Mock /// /// See the documentation for Mockito's code generation for more information. class MockDirectChatViewModel extends _i2.Mock - implements _i40.DirectChatViewModel { + implements _i38.DirectChatViewModel { @override _i1.GlobalKey<_i1.AnimatedListState> get listKey => (super.noSuchMethod( Invocation.getter(#listKey), @@ -4204,24 +4175,24 @@ class MockDirectChatViewModel extends _i2.Mock /// A class which mocks [ImageCropper]. /// /// See the documentation for Mockito's code generation for more information. -class MockImageCropper extends _i2.Mock implements _i41.ImageCropper { +class MockImageCropper extends _i2.Mock implements _i39.ImageCropper { @override - _i5.Future<_i42.CroppedFile?> cropImage({ + _i5.Future<_i40.CroppedFile?> cropImage({ required String? sourcePath, int? maxWidth, int? maxHeight, - _i42.CropAspectRatio? aspectRatio, - List<_i42.CropAspectRatioPreset>? aspectRatioPresets = const [ - _i42.CropAspectRatioPreset.original, - _i42.CropAspectRatioPreset.square, - _i42.CropAspectRatioPreset.ratio3x2, - _i42.CropAspectRatioPreset.ratio4x3, - _i42.CropAspectRatioPreset.ratio16x9, + _i40.CropAspectRatio? aspectRatio, + List<_i40.CropAspectRatioPreset>? aspectRatioPresets = const [ + _i40.CropAspectRatioPreset.original, + _i40.CropAspectRatioPreset.square, + _i40.CropAspectRatioPreset.ratio3x2, + _i40.CropAspectRatioPreset.ratio4x3, + _i40.CropAspectRatioPreset.ratio16x9, ], - _i42.CropStyle? cropStyle = _i42.CropStyle.rectangle, - _i42.ImageCompressFormat? compressFormat = _i42.ImageCompressFormat.jpg, + _i40.CropStyle? cropStyle = _i40.CropStyle.rectangle, + _i40.ImageCompressFormat? compressFormat = _i40.ImageCompressFormat.jpg, int? compressQuality = 90, - List<_i42.PlatformUiSettings>? uiSettings, + List<_i40.PlatformUiSettings>? uiSettings, }) => (super.noSuchMethod( Invocation.method( @@ -4239,19 +4210,19 @@ class MockImageCropper extends _i2.Mock implements _i41.ImageCropper { #uiSettings: uiSettings, }, ), - returnValue: _i5.Future<_i42.CroppedFile?>.value(), - returnValueForMissingStub: _i5.Future<_i42.CroppedFile?>.value(), - ) as _i5.Future<_i42.CroppedFile?>); + returnValue: _i5.Future<_i40.CroppedFile?>.value(), + returnValueForMissingStub: _i5.Future<_i40.CroppedFile?>.value(), + ) as _i5.Future<_i40.CroppedFile?>); @override - _i5.Future<_i42.CroppedFile?> recoverImage() => (super.noSuchMethod( + _i5.Future<_i40.CroppedFile?> recoverImage() => (super.noSuchMethod( Invocation.method( #recoverImage, [], ), - returnValue: _i5.Future<_i42.CroppedFile?>.value(), - returnValueForMissingStub: _i5.Future<_i42.CroppedFile?>.value(), - ) as _i5.Future<_i42.CroppedFile?>); + returnValue: _i5.Future<_i40.CroppedFile?>.value(), + returnValueForMissingStub: _i5.Future<_i40.CroppedFile?>.value(), + ) as _i5.Future<_i40.CroppedFile?>); } /// A class which mocks [ImagePicker]. @@ -4289,8 +4260,8 @@ class MockImagePicker extends _i2.Mock implements _i13.ImagePicker { double? maxWidth, double? maxHeight, int? imageQuality, - bool? requestFullMetadata = true, int? limit, + bool? requestFullMetadata = true, }) => (super.noSuchMethod( Invocation.method( @@ -4300,8 +4271,8 @@ class MockImagePicker extends _i2.Mock implements _i13.ImagePicker { #maxWidth: maxWidth, #maxHeight: maxHeight, #imageQuality: imageQuality, - #requestFullMetadata: requestFullMetadata, #limit: limit, + #requestFullMetadata: requestFullMetadata, }, ), returnValue: _i5.Future>.value(<_i13.XFile>[]), @@ -4336,8 +4307,8 @@ class MockImagePicker extends _i2.Mock implements _i13.ImagePicker { double? maxWidth, double? maxHeight, int? imageQuality, - bool? requestFullMetadata = true, int? limit, + bool? requestFullMetadata = true, }) => (super.noSuchMethod( Invocation.method( @@ -4347,8 +4318,8 @@ class MockImagePicker extends _i2.Mock implements _i13.ImagePicker { #maxWidth: maxWidth, #maxHeight: maxHeight, #imageQuality: imageQuality, - #requestFullMetadata: requestFullMetadata, #limit: limit, + #requestFullMetadata: requestFullMetadata, }, ), returnValue: _i5.Future>.value(<_i13.XFile>[]), diff --git a/test/helpers/test_locator.dart b/test/helpers/test_locator.dart index 698696d44..198dcf12d 100644 --- a/test/helpers/test_locator.dart +++ b/test/helpers/test_locator.dart @@ -1,6 +1,7 @@ // ignore_for_file: talawa_api_doc // ignore_for_file: talawa_good_doc_comments +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:get_it/get_it.dart'; import 'package:image_cropper/image_cropper.dart'; import 'package:image_picker/image_picker.dart'; @@ -54,6 +55,7 @@ final multimediaPickerService = locator(); final organizationService = locator(); final eventService = locator(); final commentsService = locator(); +final connectivity = locator(); final postService = locator(); final mainScreenViewModel = locator(); final imageService = locator(); @@ -75,6 +77,7 @@ void testSetupLocator() { locator.registerLazySingleton(() => PostService()); locator.registerLazySingleton(() => EventService()); locator.registerLazySingleton(() => CommentService()); + locator.registerLazySingleton(() => Connectivity()); locator.registerLazySingleton(() => MultiMediaPickerService()); locator.registerLazySingleton(() => ImageService()); locator.registerLazySingleton(() => ImagePicker()); diff --git a/test/model_tests/app_tour_test.dart b/test/model_tests/app_tour_test.dart index f9009417a..f9985ee97 100644 --- a/test/model_tests/app_tour_test.dart +++ b/test/model_tests/app_tour_test.dart @@ -78,9 +78,10 @@ MaterialApp createMaterialApp({required Widget home}) { } void main() { - setupLocator(); - sizeConfig.test(); - // registerServices(); + setUpAll(() { + setupLocator(); + sizeConfig.test(); + }); group('Tests for FocusTarget', () { testWidgets('Test for first TargetContent builder in FocusTarget model.', diff --git a/test/model_tests/organization/org_info_test.dart b/test/model_tests/organization/org_info_test.dart index 9f2b25296..02f67c120 100644 --- a/test/model_tests/organization/org_info_test.dart +++ b/test/model_tests/organization/org_info_test.dart @@ -5,13 +5,12 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:talawa/locator.dart'; import 'package:talawa/models/organization/org_info.dart'; -import '../../helpers/test_helpers.dart'; - void main() { - setupLocator(); - sizeConfig.test(); - setUp(() { - registerServices(); + TestWidgetsFlutterBinding.ensureInitialized(); + + setUpAll(() { + setupLocator(); + sizeConfig.test(); }); group('Test OrgInfo model', () { diff --git a/test/router_test.dart b/test/router_test.dart index 748f8fa9f..8139d8b81 100644 --- a/test/router_test.dart +++ b/test/router_test.dart @@ -43,10 +43,15 @@ import 'package:talawa/views/pre_auth_screens/select_organization.dart'; import 'package:talawa/views/pre_auth_screens/set_url.dart'; import 'package:talawa/views/pre_auth_screens/waiting_screen.dart'; +import 'helpers/test_helpers.dart'; + class MockBuildContext extends Mock implements BuildContext {} void main() { - setupLocator(); + setUpAll(() { + setupLocator(); + getAndRegisterConnectivity(); + }); group('Tests for router', () { testWidgets('Test SplashScreen route', (WidgetTester tester) async { diff --git a/test/service_tests/session_manager_test.dart b/test/service_tests/session_manager_test.dart index 1834c561c..f5bace7a9 100644 --- a/test/service_tests/session_manager_test.dart +++ b/test/service_tests/session_manager_test.dart @@ -8,7 +8,12 @@ import 'package:talawa/services/session_manager.dart'; import '../helpers/test_helpers.dart'; void main() { - setupLocator(); + TestWidgetsFlutterBinding.ensureInitialized(); + + setUpAll(() { + setupLocator(); + }); + group('Test Session Manger', () { setUpAll(() { getAndRegisterDatabaseMutationFunctions(); diff --git a/test/service_tests/third_party_service_test.dart/connectivity_service_test.dart b/test/service_tests/third_party_service_test.dart/connectivity_service_test.dart new file mode 100644 index 000000000..1f6a71878 --- /dev/null +++ b/test/service_tests/third_party_service_test.dart/connectivity_service_test.dart @@ -0,0 +1,99 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:http/http.dart' as http; +import 'package:mockito/mockito.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +import 'package:talawa/locator.dart'; +import 'package:talawa/services/third_party_service/connectivity_service.dart'; + +import '../../helpers/test_helpers.dart'; +import '../../helpers/test_locator.dart' as testgetit; + +ConnectivityResult? connectivityStatus = ConnectivityResult.mobile; + +class MockConnectivityService extends Mock + with MockPlatformInterfaceMixin + implements ConnectivityService {} + +class MockConnectivity extends Mock implements Connectivity { + final controller = StreamController(); + + StreamController get connectivityController => controller; + + @override + Stream get onConnectivityChanged => controller.stream; + + @override + Future checkConnectivity() async { + // TODO: implement checkConnectivity + if (connectivityStatus == null) { + throw const SocketException('socket exception'); + } + return connectivityStatus!; + } +} + +class MockClient extends Mock implements http.Client { + @override + Future get(Uri url, {Map? headers}) async { + if (url.toString() == 'https://timeout.com') { + throw TimeoutException('site took too long to respond'); + } + return http.Response('{}', 200); + } +} + +void main() { + testgetit.testSetupLocator(); + final mockClient = MockClient(); + getAndRegisterConnectivity(); + connectivityStatus = ConnectivityResult.mobile; + final service = ConnectivityService(client: mockClient); + locator.registerSingleton(service); + + group('connectivity', () { + test('connectionStream getter', () async { + expect(connectivityService, isA()); + expect(service.connectionStream, isA>()); + }); + + test('check initialConneciton', () async { + connectivityStatus = null; + service.checkInitialConnection(); + }); + + test('listener', () async { + final mockConnectivity = testgetit.connectivity as MockConnectivity; + mockConnectivity.connectivityController.add(ConnectivityResult.mobile); + + mockConnectivity.connectivityController + .addError(Exception("Something went wrong!")); + }); + + test('check has connection', () async { + connectivityStatus = ConnectivityResult.none; + expect(await service.hasConnection(), false); + + connectivityStatus = ConnectivityResult.mobile; + expect(await service.hasConnection(), true); + }); + + test('isReachable', () async { + final reached = await service.isReachable(); + expect(reached, true); + }); + + test('isReachable throws TimeoutException on timeout', () async { + final isReachableResult = await service.isReachable( + client: mockClient, + uriString: 'https://timeout.com', + ); + + // Verify results (timeout should be thrown before verification) + expect(isReachableResult, false); + }); + }); +} diff --git a/test/view_model_tests/progress_dialog_view_model_test.dart b/test/view_model_tests/progress_dialog_view_model_test.dart index bb5de02fb..84dfa7340 100644 --- a/test/view_model_tests/progress_dialog_view_model_test.dart +++ b/test/view_model_tests/progress_dialog_view_model_test.dart @@ -7,20 +7,17 @@ import 'package:mockito/mockito.dart'; import 'package:talawa/view_model/widgets_view_models/progress_dialog_view_model.dart'; import '../helpers/test_helpers.dart'; +import '../service_tests/third_party_service_test.dart/connectivity_service_test.dart'; void main() { group('ProgressDialogViewModelTest -', () { group('initialise -', () { - final mockConnectivity = getAndRegisterConnectivityService(); + getAndRegisterConnectivity(); final model = ProgressDialogViewModel(); test( 'When called and connectivity is present, connectivityPresent must be set to true', () async { - when(mockConnectivity.checkConnectivity()).thenAnswer( - (_) async => ConnectivityResult.mobile, - ); - await model.initialise(); expect(model.connectivityPresent, true); @@ -31,8 +28,7 @@ void main() { () async { final mockNavigation = getAndRegisterNavigationService(); - when(mockConnectivity.checkConnectivity()) - .thenAnswer((_) async => ConnectivityResult.none); + connectivityStatus = ConnectivityResult.none; await model.initialise(); diff --git a/test/views/after_auth_screens/add_post_page_test.dart b/test/views/after_auth_screens/add_post_page_test.dart index 4f42e79f6..cfae2177d 100644 --- a/test/views/after_auth_screens/add_post_page_test.dart +++ b/test/views/after_auth_screens/add_post_page_test.dart @@ -116,14 +116,11 @@ final demoJson = { }; void main() { - // SizeConfig().test(); - setupLocator(); - // locator.registerSingleton(LikeButtonViewModel()); - sizeConfig.test(); - - setUp(() { + setUpAll(() { + setupLocator(); registerServices(); getAndRegisterImageService(); + sizeConfig.test(); }); group('createAddPostScreen Test', () { diff --git a/test/widget_tests/after_auth_screens/events/create_event_page_test.dart b/test/widget_tests/after_auth_screens/events/create_event_page_test.dart index c3a33cbf5..1fd243c16 100644 --- a/test/widget_tests/after_auth_screens/events/create_event_page_test.dart +++ b/test/widget_tests/after_auth_screens/events/create_event_page_test.dart @@ -48,9 +48,11 @@ Widget createEventScreen({ ); void main() { - SizeConfig().test(); - setupLocator(); - graphqlConfig.test(); + setUpAll(() { + SizeConfig().test(); + setupLocator(); + graphqlConfig.test(); + }); group("Create Event Screen Widget Test in dark mode", () { group('Check if the validator of the create_event_form is working', () { testWidgets("Testing if text field validator are working", diff --git a/test/widget_tests/after_auth_screens/events/edit_event_page_test.dart b/test/widget_tests/after_auth_screens/events/edit_event_page_test.dart index 821cad531..8172a1675 100644 --- a/test/widget_tests/after_auth_screens/events/edit_event_page_test.dart +++ b/test/widget_tests/after_auth_screens/events/edit_event_page_test.dart @@ -69,9 +69,11 @@ Widget editEventScreen({ ); void main() { - SizeConfig().test(); - setupLocator(); - graphqlConfig.test(); + setUpAll(() { + SizeConfig().test(); + setupLocator(); + graphqlConfig.test(); + }); group("Edit Event Screen Widget Test in dark mode", () { testWidgets("Testing if dark mode is applied", (tester) async { diff --git a/test/widget_tests/pre_auth_screens/set_url_page_test.dart b/test/widget_tests/pre_auth_screens/set_url_page_test.dart index fc9b6d16f..84a3ade0e 100644 --- a/test/widget_tests/pre_auth_screens/set_url_page_test.dart +++ b/test/widget_tests/pre_auth_screens/set_url_page_test.dart @@ -58,7 +58,6 @@ Widget createSetUrlScreen({ ); Future main() async { - TestWidgetsFlutterBinding.ensureInitialized(); const testMockStorage = 'test/fixtures/core'; Hive ..init(testMockStorage) @@ -69,10 +68,12 @@ Future main() async { // await Hive.openBox('currentOrg'); await Hive.openBox('url'); //setting up MVVM - setupLocator(); - //initializing test functions - locator().test(); - locator().test(); + setUpAll(() { + setupLocator(); + //initializing test functions + locator().test(); + locator().test(); + }); setUp(() async { registerServices(); }); diff --git a/test/widget_tests/pre_auth_screens/splash_screen_test.dart b/test/widget_tests/pre_auth_screens/splash_screen_test.dart index 855d49189..50f08eab4 100644 --- a/test/widget_tests/pre_auth_screens/splash_screen_test.dart +++ b/test/widget_tests/pre_auth_screens/splash_screen_test.dart @@ -64,8 +64,10 @@ Widget createSplashScreenDark({ThemeMode themeMode = ThemeMode.dark}) => ); Future main() async { - setupLocator(); - graphqlConfig.test(); + setUpAll(() { + setupLocator(); + graphqlConfig.test(); + }); group('Splash Screen Widget Test in light mode', () { testWidgets("Testing if Splash Screen shows up", (tester) async { diff --git a/test/widget_tests/widgets/custom_progress_dialog_test.dart b/test/widget_tests/widgets/custom_progress_dialog_test.dart index fe337fb3f..e9ba62364 100644 --- a/test/widget_tests/widgets/custom_progress_dialog_test.dart +++ b/test/widget_tests/widgets/custom_progress_dialog_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; import 'package:talawa/locator.dart'; import 'package:talawa/router.dart' as router; import 'package:talawa/services/navigation_service.dart'; @@ -15,6 +14,7 @@ import 'package:talawa/utils/app_localization.dart'; import 'package:talawa/widgets/custom_progress_dialog.dart'; import '../../helpers/test_helpers.dart'; +import '../../service_tests/third_party_service_test.dart/connectivity_service_test.dart'; Widget createCustomProgressDialog() { return MaterialApp( @@ -51,10 +51,6 @@ void main() { testWidgets( 'Check if CustomProgressDialog widget shows up when connection available', (tester) async { - // Setup connectivity for connection available - when(connectivity.checkConnectivity()) - .thenAnswer((_) async => ConnectivityResult.wifi); - // Build the widget await tester.pumpWidget(createCustomProgressDialog()); await tester.pump(); @@ -70,8 +66,7 @@ void main() { locator.registerSingleton(NavigationService()); // Setup connectivity for connection not available - when(connectivity.checkConnectivity()) - .thenAnswer((_) async => ConnectivityResult.none); + connectivityStatus = ConnectivityResult.none; // Build the widget await tester.pumpWidget(createCustomProgressDialog());