From 7d74da929f129d49d786cb6e49091a027750dd92 Mon Sep 17 00:00:00 2001 From: Parag Gupta <103507835+Dante291@users.noreply.github.com> Date: Wed, 20 Dec 2023 00:08:12 +0530 Subject: [PATCH 1/7] Test for join_organisation_after_auth.dart (#2260) * Test for join_organisation_after_auth.dart * modify * adding more tests for complete coverage --- .../join_organisation_after_auth_test.dart | 115 ++++++++++++++++-- 1 file changed, 103 insertions(+), 12 deletions(-) diff --git a/test/views/after_auth_screens/join_organisation_after_auth_test.dart b/test/views/after_auth_screens/join_organisation_after_auth_test.dart index 53d67e89d..1fdcef83b 100644 --- a/test/views/after_auth_screens/join_organisation_after_auth_test.dart +++ b/test/views/after_auth_screens/join_organisation_after_auth_test.dart @@ -4,26 +4,31 @@ 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:qr_code_scanner/qr_code_scanner.dart'; import 'package:talawa/enums/enums.dart'; import 'package:talawa/models/organization/org_info.dart'; import 'package:talawa/models/user/user_info.dart'; import 'package:talawa/services/graphql_config.dart'; import 'package:talawa/services/size_config.dart'; import 'package:talawa/utils/app_localization.dart'; -import 'package:talawa/view_model/lang_view_model.dart'; import 'package:talawa/view_model/pre_auth_view_models/select_organization_view_model.dart'; import 'package:talawa/views/after_auth_screens/join_org_after_auth/join_organisation_after_auth.dart'; import 'package:talawa/views/base_view.dart'; import 'package:talawa/widgets/organization_search_list.dart'; import '../../helpers/test_helpers.dart'; +import '../../helpers/test_helpers.mocks.dart'; import '../../helpers/test_locator.dart'; -Widget createJoinOrgAfterAuth({String orgId = "fake_id"}) { - return BaseView( - onModelReady: (model) => model.initialize(), - builder: (context, langModel, child) { +Widget createJoinOrgAfterAuth({ + String orgId = "fake_id", +}) { + return BaseView( + onModelReady: (model) => model.initialise(orgId), + builder: (context, model, child) { return MaterialApp( + navigatorKey: navigationService.navigatorKey, locale: const Locale('en'), localizationsDelegates: const [ AppLocalizationsDelegate(isTest: true), @@ -53,6 +58,99 @@ void main() { }); group("Tests for JoinOrganizationAfterAuth - widgets", () { + testWidgets('QR Scan Test', (WidgetTester tester) async { + final controller = MockQRViewController(); + when(controller.scannedDataStream).thenAnswer((_) async* { + yield Barcode( + ' ' + '?orgid=6737904485008f171cf29924', + BarcodeFormat.qrcode, + null, + ); + }); + when(controller.stopCamera()) + .thenAnswer((realInvocation) => Future.value()); + + await tester.pumpWidget( + createJoinOrgAfterAuth(), + ); + + await tester.pumpAndSettle(const Duration(seconds: 6)); + + await tester.tap(find.byIcon(Icons.qr_code_scanner)); + await tester.pumpAndSettle(); + + expect( + find.byWidgetPredicate( + (widget) => + widget is ClipRRect && + widget.child is Container && + (widget.child! as Container).child is Column, + ), + findsOneWidget, + ); + (tester.widget(find.byType(QRView)) as QRView) + .onQRViewCreated(controller); + }); + testWidgets('QR Scan Test when url != GraphqlConfig.orgURI', + (WidgetTester tester) async { + final controller = MockQRViewController(); + when(controller.scannedDataStream).thenAnswer((_) async* { + yield Barcode( + '1' + '?orgid=6737904485008f171cf29924', + BarcodeFormat.qrcode, + null, + ); + }); + when(controller.stopCamera()) + .thenAnswer((realInvocation) => Future.value()); + + await tester.pumpWidget( + createJoinOrgAfterAuth(), + ); + + await tester.pumpAndSettle(const Duration(seconds: 6)); + + await tester.tap(find.byIcon(Icons.qr_code_scanner)); + await tester.pumpAndSettle(); + + expect( + find.byWidgetPredicate( + (widget) => + widget is ClipRRect && + widget.child is Container && + (widget.child! as Container).child is Column, + ), + findsOneWidget, + ); + (tester.widget(find.byType(QRView)) as QRView) + .onQRViewCreated(controller); + }); + testWidgets('Test _onQRViewCreated when throwing exception', + (WidgetTester tester) async { + final controller = MockQRViewController(); + when(controller.scannedDataStream).thenAnswer((_) async* { + yield Barcode( + ' ' + '?orgid=6737904485008f171cf29924', + BarcodeFormat.qrcode, + null, + ); + }); + when(controller.stopCamera()) + .thenAnswer((realInvocation) => Future.value()); + + await tester.pumpWidget( + createJoinOrgAfterAuth(), + ); + when(controller.stopCamera()).thenThrow(Exception("exception")); + + await tester.pumpAndSettle(const Duration(seconds: 6)); + + await tester.tap(find.byIcon(Icons.qr_code_scanner)); + await tester.pumpAndSettle(); + + (tester.widget(find.byType(QRView)) as QRView) + .onQRViewCreated(controller); + }); testWidgets( "Check if JoinOrganizationsAfterAuth shows up", (tester) async { @@ -132,13 +230,6 @@ void main() { /// Search is No-Longer is a feature, if it gets implemented in future use this test /// Really good test to learn from so not deleting testWidgets("Check if model related functions work", (tester) async { - // Registers a singleton, which means that every instance of - // SelectOrganizationViewModel will be the same. - locator.unregister(); - locator.registerSingleton( - SelectOrganizationViewModel(), - ); - final orgOne = OrgInfo( name: "org_one", creatorInfo: User( From a12294f8cb573946ac0e9be6d65f89e6ad2e870e Mon Sep 17 00:00:00 2001 From: Nidhin V Ninan <131900819+nidhin29@users.noreply.github.com> Date: Wed, 20 Dec 2023 23:53:54 +0530 Subject: [PATCH 2/7] Unittest for custom_view_modal.dart (#2250) * modified * modified * modified * modified * modified * modified * modified * modified * modified * modified * modified * modified * modified * modified * modified --- .../custom_drawer_view_model.dart | 3 +- .../custom_drawer_view_model_test.dart | 252 ++++++++++++++---- 2 files changed, 204 insertions(+), 51 deletions(-) diff --git a/lib/view_model/widgets_view_models/custom_drawer_view_model.dart b/lib/view_model/widgets_view_models/custom_drawer_view_model.dart index 0abcb0742..1daab37b2 100644 --- a/lib/view_model/widgets_view_models/custom_drawer_view_model.dart +++ b/lib/view_model/widgets_view_models/custom_drawer_view_model.dart @@ -75,7 +75,8 @@ class CustomDrawerViewModel extends BaseModel { /// None void switchOrg(OrgInfo switchToOrg) { // if `selectedOrg` is equal to `switchOrg` and `switchToOrg` present or not. - if (selectedOrg == switchToOrg && isPresentinSwitchableOrg(switchToOrg)) { + if ((selectedOrg == switchToOrg) && + (isPresentinSwitchableOrg(switchToOrg))) { // _navigationService.pop(); navigationService.showTalawaErrorSnackBar( '${switchToOrg.name} already selected', diff --git a/test/view_model_tests/custom_drawer_view_model_test.dart b/test/view_model_tests/custom_drawer_view_model_test.dart index cb4b695f7..ee24e31ff 100644 --- a/test/view_model_tests/custom_drawer_view_model_test.dart +++ b/test/view_model_tests/custom_drawer_view_model_test.dart @@ -1,25 +1,38 @@ -// ignore_for_file: talawa_api_doc -// ignore_for_file: talawa_good_doc_comments - import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; +import 'package:talawa/enums/enums.dart'; import 'package:talawa/models/organization/org_info.dart'; import 'package:talawa/models/user/user_info.dart'; import 'package:talawa/services/graphql_config.dart'; +import 'package:talawa/services/navigation_service.dart'; import 'package:talawa/services/size_config.dart'; import 'package:talawa/view_model/main_screen_view_model.dart'; import 'package:talawa/view_model/widgets_view_models/custom_drawer_view_model.dart'; +import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; + import '../helpers/test_helpers.dart'; import '../helpers/test_locator.dart'; +/// Mocked context. +/// +/// more_info_if_required class MockBuildContext extends Mock implements BuildContext {} +/// Main. +/// +/// more_info_if_required +/// +/// **params**: +/// None +/// +/// **returns**: +/// None void main() { - int testCount = 0; testSetupLocator(); locator().test(); locator().test(); + locator(); setUp(() { registerServices(); @@ -29,21 +42,103 @@ void main() { tearDown(() { unregisterServices(); }); + group('CustomDrawerViewModel Tests', () { + test('switchAbleOrg should correctly get and set value', () { + final model = CustomDrawerViewModel(); + final orgList = [ + OrgInfo(name: 'Test Org 1'), + OrgInfo(name: 'Test Org 2'), + ]; + + model.switchAbleOrg = orgList; + + expect(model.switchAbleOrg, equals(orgList)); + }); + test("initialize should setup the model with user's joined organizations", + () { + final homeModel = MainScreenViewModel(); + final MockBuildContext mockContext = MockBuildContext(); + final model = CustomDrawerViewModel(); + final user = User(joinedOrganizations: [OrgInfo(name: 'Test Org')]); + + when(userConfig.currentOrgInfoStream) + .thenAnswer((_) => Stream.value(OrgInfo())); + when(userConfig.currentUser).thenReturn(user); + when(userConfig.currentOrg).thenReturn(OrgInfo()); + + model.initialize(homeModel, mockContext); + + expect(model.switchAbleOrg, equals(user.joinedOrganizations)); + }); + + test('switchOrg should show info message if different organization', () { + final model = CustomDrawerViewModel(); + final orgInfo = OrgInfo(name: 'Test Org'); + + when(userConfig.currentOrg).thenReturn(OrgInfo(name: 'Current Org')); + model.switchAbleOrg = [orgInfo]; + + model.switchOrg(orgInfo); + + verify( + navigationService.showTalawaErrorSnackBar( + 'Switched to ${orgInfo.name}', + MessageType.info, + ), + ); + }); + + test('switchOrg should pop navigation after switching or showing error', + () { + final model = CustomDrawerViewModel(); + final orgInfo = OrgInfo(name: 'Test Org'); + + when(userConfig.currentOrg).thenReturn(OrgInfo(name: 'Current Org')); + model.switchAbleOrg = [orgInfo]; + + model.switchOrg(orgInfo); + + verify(navigationService.pop()); + }); + + test('initialize should setup the model with userConfig values', () { + final homeModel = MainScreenViewModel(); + final MockBuildContext mockContext = MockBuildContext(); + final model = CustomDrawerViewModel(); + final user = User(joinedOrganizations: [OrgInfo(name: 'Test Org')]); + + when(userConfig.currentOrgInfoStream) + .thenAnswer((_) => Stream.value(OrgInfo())); + when(userConfig.currentUser).thenReturn(user); + when(userConfig.currentOrg).thenReturn(OrgInfo()); + + model.initialize(homeModel, mockContext); + + expect(model.switchAbleOrg, equals(user.joinedOrganizations)); + expect(model.selectedOrg, equals(userConfig.currentOrg)); + }); + test( + 'switchOrg should save new organization in userConfig if different organization', + () { + final model = CustomDrawerViewModel(); + final orgInfo = OrgInfo(name: 'Test Org'); - group('Custom Drawer Model testing -', () { - //final mockConnectivity = getAndRegisterConnectivityService(); - final mainscreenModel = MainScreenViewModel(); - final model = CustomDrawerViewModel(); - final MockBuildContext mockBuildContext = MockBuildContext(); - //final UserConfig mockus - tearDown(() { - if (testCount == 5) { - model.dispose(); - } + when(userConfig.currentOrg).thenReturn(OrgInfo(name: 'Current Org')); + model.switchAbleOrg = [orgInfo]; + + model.switchOrg(orgInfo); + + verify(userConfig.saveCurrentOrgInHive(orgInfo)); + verify( + navigationService.showTalawaErrorSnackBar( + 'Switched to ${orgInfo.name}', + MessageType.info, + ), + ); }); test('check if switchOrg is working with zero switchable orgs', () { - print("1"); + final model = CustomDrawerViewModel(); model.setSelectedOrganizationName(userConfig.currentOrg); //No switchable org are present in the model @@ -55,12 +150,11 @@ void main() { //check if selected org is mocked joined org .Expectation-false. expect(model.selectedOrg, isNot(mockJoinedOrg)); - testCount++; }); test('check if switchOrg is working with wrong switchable org being passed', () { - print("2"); + final model = CustomDrawerViewModel(); model.setSelectedOrganizationName(userConfig.currentOrg); //Mock switchable org are present in the model @@ -83,13 +177,14 @@ void main() { expect(isPresent, false); //check if selected org is changed or not. Expected-Not changing expect(model.selectedOrg, isNot(fakeOrg)); - testCount++; }); test('check if switchOrg is working with mock joined orgs', () async { - print("3"); + final model = CustomDrawerViewModel(); + final homeModel = MainScreenViewModel(); + final MockBuildContext mockContext = MockBuildContext(); //Intializing a mock model with mockBuildContext - model.initialize(mainscreenModel, mockBuildContext); + model.initialize(homeModel, mockContext); //Storing the first switchable org in mockOrgInfo final OrgInfo mockChangeOrgTo = model.switchAbleOrg.first; @@ -98,35 +193,92 @@ void main() { //expecting the selected org will be equal to the mockChangeOrgto returns true expect(model.selectedOrg, mockChangeOrgTo); - testCount++; - }); - - // test('check if switchOrg is working with already joined mock orgs', - // () async { - // print("4"); - // //Intializing a mock model with mockBuildContext - // // model.initialize(mainscreenModel, mockBuildContext); - // //Storing the first switchable org in mockOrgInfo - // final OrgInfo mockChangeOrgTo = model.switchAbleOrg.first; - // //Calling the switchOrg function - // model.switchOrg(mockChangeOrgTo); - // model.switchOrg(mockChangeOrgTo); - - // //expecting the selected org will be equal to the mockChangeOrgto returns true - // expect(model.selectedOrg, mockChangeOrgTo); - // testCount++; - // }); - - // test('check if switchOrg is working with switching joined mock orgs', - // () async { - // print("5"); - // // model.initialize(mainscreenModel, mockBuildContext); - // final OrgInfo mockChangeOrgTo = model.switchAbleOrg.first; - // final OrgInfo mockChangeOrgToLast = model.switchAbleOrg.last; - // model.switchOrg(mockChangeOrgTo); - // model.switchOrg(mockChangeOrgToLast); - // expect(model.selectedOrg, mockChangeOrgToLast); - // testCount++; - // }); + }); + + test('setSelectedOrganizationName should update selectedOrg if different', + () { + final model = CustomDrawerViewModel(); + final orgInfo = OrgInfo(name: 'Test Org'); + + model.setSelectedOrganizationName(orgInfo); + + expect(model.selectedOrg, equals(orgInfo)); + }); + + test('Check if OrgInfo is present in switchAbleOrg', () { + final model = CustomDrawerViewModel(); + model.switchAbleOrg = [ + OrgInfo(id: '1'), + OrgInfo(id: '2'), + OrgInfo(id: '3'), + ]; + final switchToOrg = OrgInfo(id: '2'); + + final result = model.isPresentinSwitchableOrg(switchToOrg); + + expect(result, true); + }); + + test('Check if OrgInfo is not present in switchAbleOrg', () { + final model = CustomDrawerViewModel(); + model.switchAbleOrg = [ + OrgInfo(id: '1'), + OrgInfo(id: '2'), + OrgInfo(id: '3'), + ]; + final switchToOrg = OrgInfo(id: '4'); + + final result = model.isPresentinSwitchableOrg(switchToOrg); + + expect(result, false); + }); + + test( + 'setSelectedOrganizationName should show error snackbar if org is same as selected', + () { + final homeModel = MainScreenViewModel(); + final MockBuildContext mockContext = MockBuildContext(); + final model = CustomDrawerViewModel(); + final user = + User(joinedOrganizations: [OrgInfo(id: '1', name: 'Test Org1')]); + + when(userConfig.currentOrgInfoStream) + .thenAnswer((_) => Stream.value(OrgInfo(id: '1', name: 'Test Org1'))); + when(userConfig.currentUser).thenReturn(user); + when(userConfig.currentOrg) + .thenReturn(OrgInfo(id: '1', name: 'Test Org1')); + model.initialize(homeModel, mockContext); + final switchToOrg = OrgInfo(id: '1', name: 'Test Org1'); + model.setSelectedOrganizationName(switchToOrg); + final result1 = model.isPresentinSwitchableOrg(switchToOrg); + + expect(result1, true); + // expect(model.selectedOrg, equals(userConfig.currentOrg)); + model.switchOrg(switchToOrg); + final result = model.isPresentinSwitchableOrg(switchToOrg); + + expect(result, true); + expect(model.selectedOrg, equals(switchToOrg)); + verify( + navigationService.showTalawaErrorSnackBar( + '${switchToOrg.name} already selected', + MessageType.warning, + ), + ).called(1); + }); + test('controller should return ScrollController instance', () { + final model = CustomDrawerViewModel(); + expect(model.controller, isA()); + }); + + test('targets should return List instance', () { + final model = CustomDrawerViewModel(); + expect(model.targets, isA>()); + }); + + test('selectedOrg should be initially null', () { + final model = CustomDrawerViewModel(); + expect(model.selectedOrg, isNull); + }); }); } From 3ecd3fc3389a692ba1da01635db2b8fd2500264c Mon Sep 17 00:00:00 2001 From: Shaik Azad <120930148+Azad99-9@users.noreply.github.com> Date: Sat, 23 Dec 2023 20:45:03 +0530 Subject: [PATCH 3/7] Test user config (#2258) * resolved conflicts * fetchmore result typecast * user_config.dart made 100% code coverage. --- lib/services/user_config.dart | 2 + test/helpers/test_helpers.dart | 2 + test/service_tests/user_config_test.dart | 113 +++++++++++++++++++++-- 3 files changed, 111 insertions(+), 6 deletions(-) diff --git a/lib/services/user_config.dart b/lib/services/user_config.dart index 73fcfa739..62683ad02 100644 --- a/lib/services/user_config.dart +++ b/lib/services/user_config.dart @@ -84,6 +84,7 @@ class UserConfig { _currentOrgInfoController.add(_currentOrg!); _currentUser = boxUser.get('user'); + // if there is not currentUser then returns false. if (_currentUser == null) { _currentUser = User(id: 'null', authToken: 'null'); @@ -108,6 +109,7 @@ class UserConfig { _currentOrgInfoController.add(_currentOrg!); saveUserInHive(); + return true; } on Exception catch (e) { print(e); diff --git a/test/helpers/test_helpers.dart b/test/helpers/test_helpers.dart index 6bafa6645..4fca02942 100644 --- a/test/helpers/test_helpers.dart +++ b/test/helpers/test_helpers.dart @@ -243,6 +243,8 @@ GraphqlConfig getAndRegisterGraphqlConfig() { ); }); + when(service.getToken()).thenAnswer((_) async => "sample_token"); + locator.registerSingleton(service); return service; } diff --git a/test/service_tests/user_config_test.dart b/test/service_tests/user_config_test.dart index 8f842156d..ef0bd9d78 100644 --- a/test/service_tests/user_config_test.dart +++ b/test/service_tests/user_config_test.dart @@ -1,6 +1,7 @@ // ignore_for_file: talawa_api_doc // ignore_for_file: talawa_good_doc_comments +import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; @@ -78,7 +79,81 @@ void main() async { setUpAll(() { registerServices(); }); - test('Test for User log out.', () async { + + test('Test for getters & setters.', () { + final model = UserConfig(); + + // model.currentOrgInfoController + expect(model.currentOrgInfoController, isA>()); + + // model.currentOrgName + expect(model.currentOrgName, isA()); + + // model.currenOrg (setter) + model.currentOrg = OrgInfo(name: 'org'); + + // print(model.currentOrgInfoController); + }); + + test('Test for userLoggedIn method.', () async { + final model = UserConfig(); + model.currentUser.id = 'fake_id'; + + userBox.put('user', User(id: 'fake', firstName: 'first')); + + final Map data = { + 'users': [ + { + '_id': '1234567890', + 'firstName': 'John', + 'lastName': 'Doe', + 'email': 'johndoe@example.com', + 'image': 'https://example.com/profile.jpg', + 'accessToken': 'exampleAccessToken', + 'refreshToken': 'exampleRefreshToken', + } + ], + }; + + when( + databaseFunctions.gqlAuthQuery( + queries.fetchUserInfo, + variables: anyNamed('variables'), + ), + ).thenAnswer((_) async { + return QueryResult( + source: QueryResultSource.network, + data: data, + options: QueryOptions(document: gql(queries.fetchUserInfo)), + ); + }); + + // if there is _currentUser. + bool loggedIn = await model.userLoggedIn(); + expect(loggedIn, true); + + userBox.delete('user'); + + // if there is no _currentUser. + loggedIn = await model.userLoggedIn(); + expect(loggedIn, false); + + when( + databaseFunctions.gqlAuthQuery( + queries.fetchUserInfo, + variables: anyNamed('variables'), + ), + ).thenAnswer((_) async { + throw Exception('Simulated Exception.'); + }); + + // show couldn't update errorsnackbar. + loggedIn = await model.userLoggedIn(); + expect(loggedIn, true); + // print(model.currentUser); + }); + + test('Test for User log out method.', () async { databaseFunctions.init(); when(databaseFunctions.gqlAuthMutation(queries.logout())) @@ -120,7 +195,7 @@ void main() async { expect(loggedOut, false); }); - test('Test for updateUserJoinedOrg', () async { + test('Test for updateUserJoinedOrg method', () async { final model = UserConfig(); model.currentUser = mockUser; @@ -129,7 +204,7 @@ void main() async { expect(mockUser.joinedOrganizations, mockOrgDetails); }); - test('Test for updateUserCreatedOrg', () async { + test('Test for updateUserCreatedOrg method', () async { final model = UserConfig(); model.currentUser = mockUser; @@ -138,7 +213,7 @@ void main() async { expect(mockUser.createdOrganizations, mockOrgDetails); }); - test('Test for updateUserMemberRequestOrg', () async { + test('Test for updateUserMemberRequestOrg method', () async { final model = UserConfig(); model.currentUser = mockUser; final expected = [...mockUser.membershipRequests!, ...mockOrgDetails]; @@ -147,7 +222,7 @@ void main() async { expect(mockUser.membershipRequests, expected); }); - test('Test for updateUserAdminOrg', () async { + test('Test for updateUserAdminOrg method', () async { final model = UserConfig(); model.currentUser = mockUser; @@ -156,7 +231,7 @@ void main() async { expect(mockUser.adminFor, mockOrgDetails); }); - test('Test for updateAccessToken', () async { + test('Test for updateAccessToken method.', () async { final model = UserConfig(); model.currentUser = mockUser; const newAuthToken = 'newAccessToken'; @@ -170,5 +245,31 @@ void main() async { expect(mockUser.authToken, newAuthToken); expect(mockUser.refreshToken, newRefreshToken); }); + + test('Test for saveCurrentOrgInHive method.', () async { + final model = UserConfig(); + model.currentUser = mockUser; + + // To test the box.get('org') != null condition. + orgBox.put('org', OrgInfo(id: 'fakeId', name: 'org')); + model.saveCurrentOrgInHive(mockOrgDetails[0]); + + // To test the box.get('org') == null condition. + orgBox.delete('org'); + model.saveCurrentOrgInHive(mockOrgDetails[0]); + }); + + test('Test for updateUser method.', () async { + final model = UserConfig(); + + when(databaseFunctions.init()).thenAnswer((_) { + throw Exception('simulated exception.'); + }); + + final updated = await model.updateUser(User(id: 'sampleId')); + + // user updation failed. + expect(!updated, true); + }); }); } From 1401b74178a2d2abdcd4fd171bbd57517503802c Mon Sep 17 00:00:00 2001 From: Vaidic Dodwani <59657947+vaidic-dodwani@users.noreply.github.com> Date: Sat, 23 Dec 2023 20:50:51 +0530 Subject: [PATCH 4/7] =?UTF-8?q?Edit:=20Made=20changes=20to=20follow=20the?= =?UTF-8?q?=20custom=20lints=20patter=20and=20updates=20the=20=E2=80=A6=20?= =?UTF-8?q?(#2118)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Edit: Made changes to follow the custom lints patter and updates the package * Removed unused function in the edit_profile_view_model * added tests for convertToBase64 function --- .../edit_profile_view_model.dart | 21 ---------------- pubspec.lock | 24 +++++++++---------- .../widgets/lang_switch_test.dart | 2 +- 3 files changed, 13 insertions(+), 34 deletions(-) diff --git a/lib/view_model/after_auth_view_models/profile_view_models/edit_profile_view_model.dart b/lib/view_model/after_auth_view_models/profile_view_models/edit_profile_view_model.dart index be1a52fdb..b65a25832 100644 --- a/lib/view_model/after_auth_view_models/profile_view_models/edit_profile_view_model.dart +++ b/lib/view_model/after_auth_view_models/profile_view_models/edit_profile_view_model.dart @@ -1,6 +1,4 @@ -import 'dart:convert'; import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:talawa/locator.dart'; import 'package:talawa/services/third_party_service/multi_media_pick_service.dart'; @@ -63,25 +61,6 @@ class EditProfilePageViewModel extends BaseModel { } } - /// This function is used to convert the image into Base64 format. - /// - /// **params**: - /// * `file`: Takes the image in format of file. - /// - /// **returns**: - /// * `Future`: image in string format - Future convertToBase64(File file) async { - try { - final List bytes = await file.readAsBytes(); - final String base64String = base64Encode(bytes); - print(base64String); - imageFile = base64String as File?; - return base64String; - } catch (error) { - return ''; - } - } - /// This function remove the selected image. /// /// **params**: diff --git a/pubspec.lock b/pubspec.lock index 8cebab539..b878a957d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -213,10 +213,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.2" connectivity_plus: dependency: "direct main" description: @@ -1049,10 +1049,10 @@ packages: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.9.1" mime: dependency: transitive description: @@ -1518,18 +1518,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" stream_transform: dependency: transitive description: @@ -1597,10 +1597,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.6.0" timelines: dependency: "direct main" description: @@ -1781,10 +1781,10 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.1.4-beta" web_socket_channel: dependency: transitive description: diff --git a/test/widget_tests/widgets/lang_switch_test.dart b/test/widget_tests/widgets/lang_switch_test.dart index 9c920cbbd..02b6be38f 100644 --- a/test/widget_tests/widgets/lang_switch_test.dart +++ b/test/widget_tests/widgets/lang_switch_test.dart @@ -16,7 +16,7 @@ import '../../helpers/test_locator.dart'; Widget createLanguageTile() { return BaseView( - onModelReady: (model) => model.initialize(), + onModelReady: (appLanguageModel) => appLanguageModel.initialize(), builder: (_, __, ___) => MaterialApp( localizationsDelegates: [ const AppLocalizationsDelegate(isTest: true), From f292741731794dbc14ab858cd2caaa90076c85a4 Mon Sep 17 00:00:00 2001 From: Shivam Gupta Date: Sun, 24 Dec 2023 01:13:28 +0530 Subject: [PATCH 5/7] News feed comment fix (#2248) * Updated the code * Updated * Updated * Updated * Updated * Updated * Updated * Updated * Fixed View Model Test * Updated * Updated * Updated * Update pubspec.lock * fixed order * Updated --- lib/services/comment_service.dart | 47 ++-- lib/utils/post_queries.dart | 46 ++++ lib/view_model/access_request_view_model.dart | 2 - .../comments_view_model.dart | 66 +++-- test/helpers/test_helpers.mocks.dart | 27 +- test/service_tests/comment_service_test.dart | 249 ++++++++++++++---- 6 files changed, 342 insertions(+), 95 deletions(-) diff --git a/lib/services/comment_service.dart b/lib/services/comment_service.dart index 655a2b476..dc457e504 100644 --- a/lib/services/comment_service.dart +++ b/lib/services/comment_service.dart @@ -1,9 +1,8 @@ -// ignore_for_file: talawa_api_doc, avoid_dynamic_calls -// ignore_for_file: talawa_good_doc_comments - +import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:talawa/locator.dart'; import 'package:talawa/services/database_mutation_functions.dart'; import 'package:talawa/utils/comment_queries.dart'; +import 'package:talawa/utils/post_queries.dart'; /// CommentService class have different member functions which provides service in the context of commenting. /// @@ -18,11 +17,14 @@ class CommentService { /// This function is used to add comment on the post. /// - /// parameters: - /// * [postId] - Post id where comment need to be added. - /// * [text] - content of the comment. + /// To verify things are working, check out the native platform logs. + /// **params**: + /// * `postId`: The post id on which comment is to be added. + /// * `text`: The comment text. + /// + /// **returns**: + /// * `Future`: promise that will be fulfilled message background activities are successful. Future createComments(String postId, String text) async { - print("comment service called"); final String createCommentQuery = CommentQueries().createComment(); final result = await _dbFunctions.gqlAuthMutation( createCommentQuery, @@ -31,21 +33,30 @@ class CommentService { 'text': text, }, ); - print("comment added"); - print(result); return result; } - /// This function is used to fetch all comments on the post. + /// This function is used to get all comments on the post. + /// + /// To verify things are working, check out the native platform logs. + /// **params**: + /// * `postId`: The post id for which comments are to be fetched. + /// + /// **returns**: + /// * `Future>`: promise that will be fulfilled with list of comments. /// - /// parameters: - /// * [postId] - Post id for which comments need to be fetched. - Future getCommentsForPost(String postId) async { - final String getCommmentQuery = CommentQueries().getPostsComments(postId); - final result = await _dbFunctions.gqlAuthMutation(getCommmentQuery); - if (result.data != null) { - return result.data["commentsByPost"] as List; + Future> getCommentsForPost(String postId) async { + final String getCommmentQuery = PostQueries().getPostById(postId); + + final dynamic result = await _dbFunctions.gqlAuthMutation(getCommmentQuery); + + if (result == null) { + return []; } - return []; + final resultData = (result as QueryResult).data; + + final resultDataPostComments = (resultData?['post'] + as Map)['comments'] as List; + return resultDataPostComments; } } diff --git a/lib/utils/post_queries.dart b/lib/utils/post_queries.dart index c5b73d922..40cff4d0d 100644 --- a/lib/utils/post_queries.dart +++ b/lib/utils/post_queries.dart @@ -40,6 +40,52 @@ class PostQueries { """; } + /// Getting Post by Post Id. + /// + /// **params**: + /// * `postId`: The post id + /// + /// **returns**: + /// * `String`: The query related to gettingPostsbyId + String getPostById(String postId) { + return """ + query { + post(id: "$postId") + { + _id + text + createdAt + imageUrl + videoUrl + title + commentCount + likeCount + creator{ + _id + firstName + lastName + image + } + organization{ + _id + } + likedBy{ + _id + } + comments{ + _id, + text, + createdAt + creator{ + firstName + lastName + } + } + } + } +"""; + } + /// Add Like to a post. /// /// **params**: diff --git a/lib/view_model/access_request_view_model.dart b/lib/view_model/access_request_view_model.dart index a2e8648ab..1d539c065 100644 --- a/lib/view_model/access_request_view_model.dart +++ b/lib/view_model/access_request_view_model.dart @@ -1,4 +1,3 @@ -// ignore_for_file: talawa_api_doc import 'package:flutter/cupertino.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:talawa/constants/routing_constants.dart'; @@ -23,7 +22,6 @@ class AccessScreenViewModel extends BaseModel { /// initialization function. /// - /// /// **params**: /// * `org`: Org to send request to. /// diff --git a/lib/view_model/widgets_view_models/comments_view_model.dart b/lib/view_model/widgets_view_models/comments_view_model.dart index f189e528a..4bc9b31ef 100644 --- a/lib/view_model/widgets_view_models/comments_view_model.dart +++ b/lib/view_model/widgets_view_models/comments_view_model.dart @@ -1,6 +1,3 @@ -// ignore_for_file: talawa_api_doc -// ignore_for_file: talawa_good_doc_comments - import 'package:talawa/enums/enums.dart'; import 'package:talawa/locator.dart'; import 'package:talawa/models/comment/comment_model.dart'; @@ -9,25 +6,41 @@ import 'package:talawa/services/post_service.dart'; import 'package:talawa/services/user_config.dart'; import 'package:talawa/view_model/base_view_model.dart'; -/// CommentsViewModel class helps to serve the data from model -/// and to react to user's input for Comment Widget. +/// CommentsViewModel class helps to serve the data from model and to react to user's input for Comment Widget. /// /// Methods include: /// * `getComments` : to get all comments on the post. /// * `createComment` : to add comment on the post. class CommentsViewModel extends BaseModel { + /// Constructor late CommentService _commentService; + + /// PostService instance. late PostService _postService; + + /// Post id on which comments are to be fetched. late String _postID; + + /// List of comments on the post. late List _commentlist; + + /// UserConfig instance. late UserConfig _userConfig; // Getters List get commentList => _commentlist; String get postId => _postID; - // initialiser. - Future initialise(String postID) async { + /// This function is used to initialise the CommentViewModel. + /// + /// To verify things are working, check out the native platform logs. + /// **params**: + /// * `postID`: The post id for which comments are to be fetched. + /// + /// **returns**: + /// * `Future`: promise that will be fulfilled message background activities are successful. + /// + Future initialise(String postID) async { _commentlist = []; _postID = postID; _commentService = locator(); @@ -37,12 +50,18 @@ class CommentsViewModel extends BaseModel { await getComments(); } - /// This methods fetch all comments on the post. - /// The function uses `getCommentsForPost` method by Comment Service. - Future getComments() async { + /// This function is used to get all comments on the post. + /// + /// To verify things are working, check out the native platform logs. + /// **params**: + /// None + /// + /// **returns**: + /// * `Future`: promise that will be fulfilled when comments are fetched. + /// + Future getComments() async { setState(ViewState.busy); - final List commentsJSON = - await _commentService.getCommentsForPost(_postID) as List; + final List commentsJSON = await _commentService.getCommentsForPost(_postID); print(commentsJSON); commentsJSON.forEach((commentJson) { _commentlist.add(Comment.fromJson(commentJson as Map)); @@ -50,18 +69,27 @@ class CommentsViewModel extends BaseModel { setState(ViewState.idle); } - /// This function add comment on the post. - /// The function uses `createComments` method provided by Comment Service. + /// This function add comment on the post. The function uses `createComments` method provided by Comment Service. + /// + /// **params**: + /// * `msg`: The comment text. /// - /// params: - /// * `msg` : text of the comment to add. - Future createComment(String msg) async { + /// **returns**: + /// * `Future`: promise that will be fulfilled when comment is added. + /// + Future createComment(String msg) async { print("comment viewModel called"); await _commentService.createComments(_postID, msg); addCommentLocally(msg); } - // This function add comment locally. + /// This function add comment locally. + /// + /// **params**: + /// * `msg`: BuildContext, contain parent info + /// + /// **returns**: + /// None void addCommentLocally(String msg) { _postService.addCommentLocally(_postID); final creator = _userConfig.currentUser; @@ -70,7 +98,7 @@ class CommentsViewModel extends BaseModel { createdAt: DateTime.now().toString(), creator: creator, ); - _commentlist.insert(0, localComment); + _commentlist.add(localComment); notifyListeners(); } } diff --git a/test/helpers/test_helpers.mocks.dart b/test/helpers/test_helpers.mocks.dart index a5557bb59..4f51950a6 100644 --- a/test/helpers/test_helpers.mocks.dart +++ b/test/helpers/test_helpers.mocks.dart @@ -2822,14 +2822,25 @@ class MockCommentService extends _i2.Mock implements _i35.CommentService { ) as _i4.Future); @override - _i4.Future getCommentsForPost(String? postId) => (super.noSuchMethod( - Invocation.method( - #getCommentsForPost, - [postId], - ), - returnValue: _i4.Future.value(), - returnValueForMissingStub: _i4.Future.value(), - ) as _i4.Future); + _i4.Future> getCommentsForPost(String? postId) { + final result = super.noSuchMethod( + Invocation.method( + #getCommentsForPost, + [postId], + ), + returnValue: _i4.Future>.value( + []), // Provide an empty list as a default value + returnValueForMissingStub: _i4.Future>.value([]), + ); + + // Check if the result is null, and return an empty list if it is + if (result == null) { + return _i4.Future>.value([]); + } + + // Otherwise, cast the result to List + return result as _i4.Future>; + } } /// A class which mocks [AppTheme]. diff --git a/test/service_tests/comment_service_test.dart b/test/service_tests/comment_service_test.dart index 0fa40c43f..0792b6b93 100644 --- a/test/service_tests/comment_service_test.dart +++ b/test/service_tests/comment_service_test.dart @@ -1,6 +1,3 @@ -// ignore_for_file: talawa_api_doc -// ignore_for_file: talawa_good_doc_comments - import 'package:flutter_test/flutter_test.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:mockito/mockito.dart'; @@ -8,7 +5,7 @@ import 'package:talawa/locator.dart'; import 'package:talawa/services/comment_service.dart'; import 'package:talawa/services/database_mutation_functions.dart'; import 'package:talawa/utils/comment_queries.dart'; - +import 'package:talawa/utils/post_queries.dart'; import '../helpers/test_helpers.dart'; void main() { @@ -48,63 +45,63 @@ void main() { }); test('test for getCommentsForPost', () async { final dataBaseMutationFunctions = locator(); - final String getCommmentQuery = - CommentQueries().getPostsComments('Ayush s postid'); + PostQueries().getPostById('Ayush s postid'); + when( dataBaseMutationFunctions.gqlAuthMutation(getCommmentQuery), ).thenAnswer( (_) async => QueryResult( options: QueryOptions(document: gql(getCommmentQuery)), data: { - 'commentsByPost': [ - { - 'creator': { - '_id': '123', - 'firstName': 'John', - 'lastName': 'Doe', - 'email': 'test@test.com', - }, - 'createdAt': '123456', - 'text': 'test text', - 'post': 'test post', - 'likeCount': 'test count', - }, - { - 'creator': { - '_id': '123', - 'firstName': 'Ayush', - 'lastName': 'Doe', - 'email': 'test@test.com', + 'post': { + 'comments': [ + { + 'creator': { + '_id': '123', + 'firstName': 'John', + 'lastName': 'Doe', + 'email': 'test@test.com', + }, + 'createdAt': '123456', + 'text': 'test text', + 'post': 'test post', + 'likeCount': 'test count', }, - 'createdAt': '123456', - 'text': 'test text', - 'post': 'test post', - 'likeCount': 'test count', - }, - { - 'creator': { - '_id': '123', - 'firstName': 'john', - 'lastName': 'chauhdary', - 'email': 'test@test.com', + { + 'creator': { + '_id': '123', + 'firstName': 'Ayush', + 'lastName': 'Doe', + 'email': 'test@test.com', + }, + 'createdAt': '123456', + 'text': 'test text', + 'post': 'test post', + 'likeCount': 'test count', }, - 'createdAt': '123456', - 'text': 'test text', - 'post': 'test post', - 'likeCount': 'test count', - } - ], + { + 'creator': { + '_id': '123', + 'firstName': 'john', + 'lastName': 'chauhdary', + 'email': 'test@test.com', + }, + 'createdAt': '123456', + 'text': 'test text', + 'post': 'test post', + 'likeCount': 'test count', + } + ], + }, }, source: QueryResultSource.network, ), ); final service = CommentService(); - final result = await service.getCommentsForPost('Ayush s postid'); - print(result); if (result.toString().contains('[{creator: ' '{' '_id: 123, ' @@ -141,22 +138,178 @@ void main() { final dataBaseMutationFunctions = locator(); final String getCommmentQuery = - CommentQueries().getPostsComments('Ayush'); + PostQueries().getPostById('Ayush s postid'); when( dataBaseMutationFunctions.gqlAuthMutation(getCommmentQuery), ).thenAnswer( (_) async => QueryResult( options: QueryOptions(document: gql(getCommmentQuery)), - data: null, + data: { + 'post': { + 'comments': [], + }, + }, + source: QueryResultSource.network, + ), + ); + + final service = CommentService(); + final result = await service.getCommentsForPost('Ayush postid'); + + if (result.toString().contains('[{creator: ' + '{' + '_id: 123, ' + 'firstName: John, ' + 'lastName: Doe, ' + 'email: test@test.com},' + ' createdAt: 123456, ' + 'text: test text, ' + 'post: test post, ' + 'likeCount: test count}, ' + '{creator: ' + '{_id: 123, ' + 'firstName: Ayush, ' + 'lastName: Doe, ' + 'email: test@test.com}, ' + 'createdAt: 123456, ' + 'text: test text, ' + 'post: test post, ' + 'likeCount: test count}, ' + '{creator: {_id: 123,' + ' firstName: john, ' + 'lastName: chauhdary, ' + 'email: test@test.com}, ' + 'createdAt: 123456, ' + 'text: test text, ' + 'post: test post, ' + 'likeCount: test count}]')) { + fail('the result is not maatching'); + } + expect(result, isEmpty); + }); + + test('test for zero comments on post', () async { + final dataBaseMutationFunctions = locator(); + + final String getCommmentQuery = + PostQueries().getPostById('Ayush s postid'); + when( + dataBaseMutationFunctions.gqlAuthMutation(getCommmentQuery), + ).thenAnswer( + (_) async => QueryResult( + options: QueryOptions(document: gql(getCommmentQuery)), + data: { + 'post': {'comments': []}, + }, source: QueryResultSource.network, ), ); final service = CommentService(); + final result = await service.getCommentsForPost('Ayush postid'); - final result = await service.getCommentsForPost('Ayush'); + if (result.toString().contains('[{creator: ' + '{' + '_id: 123, ' + 'firstName: John, ' + 'lastName: Doe, ' + 'email: test@test.com},' + ' createdAt: 123456, ' + 'text: test text, ' + 'post: test post, ' + 'likeCount: test count}, ' + '{creator: ' + '{_id: 123, ' + 'firstName: Ayush, ' + 'lastName: Doe, ' + 'email: test@test.com}, ' + 'createdAt: 123456, ' + 'text: test text, ' + 'post: test post, ' + 'likeCount: test count}, ' + '{creator: {_id: 123,' + ' firstName: john, ' + 'lastName: chauhdary, ' + 'email: test@test.com}, ' + 'createdAt: 123456, ' + 'text: test text, ' + 'post: test post, ' + 'likeCount: test count}]')) { + fail('the result is not maatching'); + } + expect(result, isEmpty); + }); + + test('test when post is null', () async { + final dataBaseMutationFunctions = locator(); + + final String getCommmentQuery = + PostQueries().getPostById('Ayush s postid'); + when( + dataBaseMutationFunctions.gqlAuthMutation(getCommmentQuery), + ).thenAnswer( + (_) async => QueryResult( + options: QueryOptions(document: gql(getCommmentQuery)), + data: { + 'post': null, + }, + source: QueryResultSource.network, + ), + ); + + final service = CommentService(); + final result = await service.getCommentsForPost('Ayush postid'); + + if (result.toString().contains('[{creator: ' + '{' + '_id: 123, ' + 'firstName: John, ' + 'lastName: Doe, ' + 'email: test@test.com},' + ' createdAt: 123456, ' + 'text: test text, ' + 'post: test post, ' + 'likeCount: test count}, ' + '{creator: ' + '{_id: 123, ' + 'firstName: Ayush, ' + 'lastName: Doe, ' + 'email: test@test.com}, ' + 'createdAt: 123456, ' + 'text: test text, ' + 'post: test post, ' + 'likeCount: test count}, ' + '{creator: {_id: 123,' + ' firstName: john, ' + 'lastName: chauhdary, ' + 'email: test@test.com}, ' + 'createdAt: 123456, ' + 'text: test text, ' + 'post: test post, ' + 'likeCount: test count}]')) { + fail('the result is not maatching'); + } + expect(result, isEmpty); + }); + + test('test when result is null', () async { + final dataBaseMutationFunctions = locator(); + + final String getCommmentQuery = + PostQueries().getPostById('Ayush s postid'); + when( + dataBaseMutationFunctions.gqlAuthMutation(getCommmentQuery), + ).thenAnswer( + (_) async => QueryResult( + options: QueryOptions(document: gql(getCommmentQuery)), + data: null, + source: QueryResultSource.network, + ), + ); + + final service = CommentService(); + final result = await service.getCommentsForPost('Ayush postid'); - print(result); if (result.toString().contains('[{creator: ' '{' '_id: 123, ' From bc36dac9cb677c5c32d0840995c76f9a97019fe2 Mon Sep 17 00:00:00 2001 From: Shivam Gupta Date: Sun, 24 Dec 2023 01:15:00 +0530 Subject: [PATCH 6/7] Node files not commit to project (#2267) * Fixed node file upload * Fixed node file upload --- .gitignore | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index d0cd2ee33..b14badeec 100644 --- a/.gitignore +++ b/.gitignore @@ -244,3 +244,12 @@ test/fixtures/core # Ignoring file that are generated during talawa testing and firebase initialization genhtml.perl test_img.png + + +# Ignoring Node files that are generated if user uses any node command which is not required for the project +node_modules/ +package.json +package-lock.json +yarn.lock +npm-debug.log +yarn-error.log \ No newline at end of file From c902baaf1467b985b5301a6b30a06d92516e4956 Mon Sep 17 00:00:00 2001 From: Peter Harrison <16875803+palisadoes@users.noreply.github.com> Date: Sat, 23 Dec 2023 13:12:48 -0800 Subject: [PATCH 7/7] Update pull-request.yml - 88% coverage --- .github/workflows/pull-request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 2099d2e9a..6762757ce 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -123,7 +123,7 @@ jobs: uses: VeryGoodOpenSource/very_good_coverage@v2 with: path: './coverage/lcov.info' - min_coverage: 87.0 + min_coverage: 88.0 Android-Build: name: Testing build for android