diff --git a/lib/main.dart b/lib/main.dart index be5f73998..24f3de8d7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -26,7 +26,7 @@ void main() { * Use the "environments.local.json" for running against your local web-api * For IOS users: change the SERVER_HOST in the environment.local file to "http://localhost:5000" */ - environment.setFile('assets/environments.dev.json').whenComplete(() { + environment.setFile('assets/environments.local.json').whenComplete(() { _runApp(); }); } @@ -51,9 +51,9 @@ void _runApp() { lastState = snapshot.data; //To make sure we only listen to the stream once we take advantage // of firstTimeLogin bool value - if(firstTimeLogIn== true){ + if (firstTimeLogIn == true) { _api.connectivity.connectivityStream.listen((dynamic event) { - if(event == false){ + if (event == false) { lostConnectionDialog(context); } }); @@ -63,11 +63,10 @@ void _runApp() { // Show screen dependent on logged in role switch (_authBloc.loggedInUser.role) { case Role.Citizen: - return WeekplanSelectorScreen( - DisplayNameModel( - displayName: _authBloc.loggedInUser.displayName, - role: describeEnum(_authBloc.loggedInUser.role), - id: _authBloc.loggedInUser.id)); + return WeekplanSelectorScreen(DisplayNameModel( + displayName: _authBloc.loggedInUser.displayName, + role: describeEnum(_authBloc.loggedInUser.role), + id: _authBloc.loggedInUser.id)); default: return ChooseCitizenScreen(); } diff --git a/lib/widgets/pictogram_text.dart b/lib/widgets/pictogram_text.dart index 46e9bf83a..a3ceff55b 100644 --- a/lib/widgets/pictogram_text.dart +++ b/lib/widgets/pictogram_text.dart @@ -89,14 +89,14 @@ class PictogramText extends StatelessWidget { /// accounted for double textWidth(String text, BuildContext context) { return (TextPainter( - text: TextSpan( - text: text, - style: - const TextStyle(fontWeight: FontWeight.bold, fontSize: 120)), - maxLines: 1, - textScaleFactor: MediaQuery.of(context).textScaleFactor, - textDirection: TextDirection.ltr) - ..layout()) + text: TextSpan( + text: text, + style: + const TextStyle(fontWeight: FontWeight.bold, fontSize: 120)), + maxLines: 1, + textScaleFactor: MediaQuery.of(context).textScaleFactor, + textDirection: TextDirection.ltr) + ..layout()) .size .width; } diff --git a/test/blocs/activity_bloc_test.dart b/test/blocs/activity_bloc_test.dart index e32033043..60e353814 100644 --- a/test/blocs/activity_bloc_test.dart +++ b/test/blocs/activity_bloc_test.dart @@ -24,7 +24,7 @@ void main() { MockActivityApi activityApi; final DisplayNameModel mockUser = - DisplayNameModel(id: '50', displayName: 'testUser202', role: null); + DisplayNameModel(id: '50', displayName: 'testUser202', role: null); final ActivityModel mockActivity = ActivityModel( id: 1, @@ -52,11 +52,10 @@ void main() { void setupApiCalls() { when(weekApi.update(mockUser.id, mockWeekModel.weekYear, mockWeekModel.weekNumber, mockWeekModel)) - .thenAnswer((_) => rx_dart.BehaviorSubject - .seeded(mockWeekModel)); - when(activityApi.update(mockActivity, mockUser.id)) - .thenAnswer((_) => rx_dart.BehaviorSubject - .seeded(mockActivity)); + .thenAnswer( + (_) => rx_dart.BehaviorSubject.seeded(mockWeekModel)); + when(activityApi.update(mockActivity, mockUser.id)).thenAnswer( + (_) => rx_dart.BehaviorSubject.seeded(mockActivity)); } setUp(() { diff --git a/test/blocs/auth_bloc.test.dart b/test/blocs/auth_bloc.test.dart index 2de4285cb..e8016e7c2 100644 --- a/test/blocs/auth_bloc.test.dart +++ b/test/blocs/auth_bloc.test.dart @@ -82,9 +82,16 @@ void main() { }) ); + + + ///setup at the top to reflect logins of different user roles const String username = 'Graatand'; const String password = 'password'; - test('Should check that authenticate works', async((DoneFn done) { + ///TODO: test fails with error message below + ///NoSuchMethodError: The method 'listen' was called on null. + /// Receiver: null + /// Tried calling: listen(Closure: (GirafUserModel) => Null) + test('Should check that authenticate works guardian', async((DoneFn done) { authBloc.mode.skip(1).listen((WeekplanMode mode) { expect(mode, WeekplanMode.guardian); done(); @@ -92,8 +99,13 @@ void main() { authBloc.authenticate(username, password); })); + ///setup at the top to reflect logins of different user roles const String username2 = 'Chris'; - test('Should check that authenticate works', async((DoneFn done) { + ///TODO: test fails with error message below + ///NoSuchMethodError: The method 'listen' was called on null. + /// Receiver: null + /// Tried calling: listen(Closure: (GirafUserModel) => Null) + test('Should check that authenticate works (trustee)', async((DoneFn done) { authBloc.mode.skip(1).listen((WeekplanMode mode) { expect(mode, WeekplanMode.trustee); done(); @@ -101,8 +113,13 @@ void main() { authBloc.authenticate(username2, password); })); + ///setup at the top to reflect logins of different user roles const String username3 = 'Janne'; - test('Should check that authenticate works', async((DoneFn done) { + ///TODO: test fails with error message below + ///NoSuchMethodError: The method 'listen' was called on null. + /// Receiver: null + /// Tried calling: listen(Closure: (GirafUserModel) => Null) + test('Should check that authenticate works (citizen)', async((DoneFn done) { authBloc.mode.skip(1).listen((WeekplanMode mode) { expect(mode, WeekplanMode.citizen); done(); diff --git a/test/blocs/choose_citizen_bloc_test.dart b/test/blocs/choose_citizen_bloc_test.dart index 9e2d2254b..0d32ec29b 100644 --- a/test/blocs/choose_citizen_bloc_test.dart +++ b/test/blocs/choose_citizen_bloc_test.dart @@ -8,6 +8,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:weekplanner/blocs/choose_citizen_bloc.dart'; +//Creates a mock for the test class MockUserApi extends Mock implements UserApi { @override Stream me() { @@ -30,6 +31,7 @@ class MockUserApi extends Mock implements UserApi { } void main() { + //Setting up the environment ChooseCitizenBloc bloc; Api api; setUp(() { @@ -40,11 +42,16 @@ void main() { test('Should be able to get UsernameModel from API', async((DoneFn done) { int _count = 0; + //Set up citizen listener bloc.citizen.listen((List response) { + //When "_count" is zero it expects length to be 0, and iterates "_count" if (_count == 0) { expect(response.length, 0); _count++; - } else { + } + //Otherwise it expects the length to be 1, + //and checks if the data matches with the mock made above. + else { expect(response.length, 1); final DisplayNameModel rsp = response[0]; expect(rsp.displayName, 'test1'); diff --git a/test/blocs/edit_weekplan_bloc_test.dart b/test/blocs/edit_weekplan_bloc_test.dart index 8823be5ae..389e41029 100644 --- a/test/blocs/edit_weekplan_bloc_test.dart +++ b/test/blocs/edit_weekplan_bloc_test.dart @@ -14,10 +14,12 @@ import 'package:weekplanner/di.dart'; class MockWeekApi extends Mock implements WeekApi {} +//test functionality for editing a weekplan bloc void main() { EditWeekplanBloc bloc; WeekplansBloc mockWeekplanSelector; Api api; + //Create mockup pictogram final PictogramModel mockThumbnail = PictogramModel( id: 1, lastEdit: null, @@ -26,7 +28,7 @@ void main() { imageUrl: 'http://any.tld', imageHash: null); final DisplayNameModel mockUser = - DisplayNameModel(displayName: 'User', id: '1', role: null); + DisplayNameModel(displayName: 'User', id: '1', role: null); final WeekModel mockWeek = WeekModel( thumbnail: mockThumbnail, days: null, @@ -34,6 +36,7 @@ void main() { weekNumber: 1, weekYear: DateTime.now().year + 1); +//set up test, defines what values to return on api calls setUp(() { api = Api('any'); api.week = MockWeekApi(); diff --git a/test/blocs/new_citizen_bloc_test.dart b/test/blocs/new_citizen_bloc_test.dart index e9d08e60d..ca6882963 100644 --- a/test/blocs/new_citizen_bloc_test.dart +++ b/test/blocs/new_citizen_bloc_test.dart @@ -8,6 +8,9 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:weekplanner/blocs/new_citizen_bloc.dart'; +//tests that features relevant to creating a citizen are functional + +//creates an example user class MockUserApi extends Mock implements UserApi { @override Stream me() { @@ -20,13 +23,15 @@ class MockUserApi extends Mock implements UserApi { username: 'kb7913')); } } + class MockAccountApi extends Mock implements AccountApi {} void main() { NewCitizenBloc bloc; Api api; - final GirafUserModel user = GirafUserModel(id: '1', + final GirafUserModel user = GirafUserModel( + id: '1', department: 1, role: Role.Citizen, roleName: 'Citizen', @@ -40,15 +45,12 @@ void main() { bloc = NewCitizenBloc(api); bloc.initialize(); - - when(api.account.register( - any, any, any, any, - departmentId: anyNamed('departmentId'), role: anyNamed('role'))) +//sets api calls to return correct user data + when(api.account.register(any, any, any, any, + departmentId: anyNamed('departmentId'), role: anyNamed('role'))) .thenAnswer((_) { return Stream.value(user); }); - - }); test('Should save a new citizen', async((DoneFn done) { @@ -339,102 +341,95 @@ void main() { test('PasswordVerification is null, but password is missing', async((DoneFn done) { - bloc.onPasswordChange.add(''); - bloc.onPasswordVerifyChange.add(null); - bloc.validPasswordVerificationStream.listen((bool isValid) { - expect(isValid, isNotNull); - expect(isValid, false); - done(); - }); - })); + bloc.onPasswordChange.add(''); + bloc.onPasswordVerifyChange.add(null); + bloc.validPasswordVerificationStream.listen((bool isValid) { + expect(isValid, isNotNull); + expect(isValid, false); + done(); + }); + })); test('PasswordVerification is filled, but password is missing', async((DoneFn done) { - bloc.onPasswordVerifyChange.add('abcd'); - bloc.validPasswordVerificationStream.listen((bool isValid) { - expect(isValid, isNotNull); - expect(isValid, false); - done(); - }); - })); + bloc.onPasswordVerifyChange.add('abcd'); + bloc.validPasswordVerificationStream.listen((bool isValid) { + expect(isValid, isNotNull); + expect(isValid, false); + done(); + }); + })); test('PasswordVerification is filled, but does not match password', async((DoneFn done) { - bloc.onPasswordChange.add('4321'); - bloc.onPasswordVerifyChange.add('1234'); - bloc.validPasswordVerificationStream.listen((bool isValid) { - expect(isValid, isNotNull); - expect(isValid, false); - done(); - }); - })); + bloc.onPasswordChange.add('4321'); + bloc.onPasswordVerifyChange.add('1234'); + bloc.validPasswordVerificationStream.listen((bool isValid) { + expect(isValid, isNotNull); + expect(isValid, false); + done(); + }); + })); test('PasswordVerification is filled, but password is empty', async((DoneFn done) { - bloc.onPasswordChange.add(''); - bloc.onPasswordVerifyChange.add('1234'); - bloc.validPasswordVerificationStream.listen((bool isValid) { - expect(isValid, isNotNull); - expect(isValid, false); - done(); - }); - })); + bloc.onPasswordChange.add(''); + bloc.onPasswordVerifyChange.add('1234'); + bloc.validPasswordVerificationStream.listen((bool isValid) { + expect(isValid, isNotNull); + expect(isValid, false); + done(); + }); + })); test('PasswordVerification is filled, but password is null', async((DoneFn done) { - bloc.onPasswordChange.add(null); - bloc.onPasswordVerifyChange.add('1234'); - bloc.validPasswordVerificationStream.listen((bool isValid) { - expect(isValid, isNotNull); - expect(isValid, false); - done(); - }); - })); - - test('PasswordVerification and password match 1', - async((DoneFn done) { - bloc.onPasswordChange.add('1234'); - bloc.onPasswordVerifyChange.add('1234'); - bloc.validPasswordVerificationStream.listen((bool isValid) { - expect(isValid, isNotNull); - expect(isValid, true); - done(); - }); - })); - - test('PasswordVerification and password match 2', - async((DoneFn done) { - bloc.onPasswordChange.add('abc123'); - bloc.onPasswordVerifyChange.add('abc123'); - bloc.validPasswordVerificationStream.listen((bool isValid) { - expect(isValid, isNotNull); - expect(isValid, true); - done(); - }); - })); - - test('PasswordVerification and password match 3', - async((DoneFn done) { - bloc.onPasswordChange.add(null); - bloc.onPasswordVerifyChange.add(null); - bloc.validPasswordVerificationStream.listen((bool isValid) { - expect(isValid, isNotNull); - expect(isValid, true); - done(); - }); - })); - - test('PasswordVerification and password match 4', - async((DoneFn done) { - bloc.onPasswordChange.add(''); - bloc.onPasswordVerifyChange.add(''); - bloc.validPasswordVerificationStream.listen((bool isValid) { - expect(isValid, isNotNull); - expect(isValid, true); - done(); - }); - })); + bloc.onPasswordChange.add(null); + bloc.onPasswordVerifyChange.add('1234'); + bloc.validPasswordVerificationStream.listen((bool isValid) { + expect(isValid, isNotNull); + expect(isValid, false); + done(); + }); + })); + test('PasswordVerification and password match 1', async((DoneFn done) { + bloc.onPasswordChange.add('1234'); + bloc.onPasswordVerifyChange.add('1234'); + bloc.validPasswordVerificationStream.listen((bool isValid) { + expect(isValid, isNotNull); + expect(isValid, true); + done(); + }); + })); + + test('PasswordVerification and password match 2', async((DoneFn done) { + bloc.onPasswordChange.add('abc123'); + bloc.onPasswordVerifyChange.add('abc123'); + bloc.validPasswordVerificationStream.listen((bool isValid) { + expect(isValid, isNotNull); + expect(isValid, true); + done(); + }); + })); + test('PasswordVerification and password match 3', async((DoneFn done) { + bloc.onPasswordChange.add(null); + bloc.onPasswordVerifyChange.add(null); + bloc.validPasswordVerificationStream.listen((bool isValid) { + expect(isValid, isNotNull); + expect(isValid, true); + done(); + }); + })); -} \ No newline at end of file + test('PasswordVerification and password match 4', async((DoneFn done) { + bloc.onPasswordChange.add(''); + bloc.onPasswordVerifyChange.add(''); + bloc.validPasswordVerificationStream.listen((bool isValid) { + expect(isValid, isNotNull); + expect(isValid, true); + done(); + }); + })); +} diff --git a/test/blocs/new_pictogram_password_bloc_test.dart b/test/blocs/new_pictogram_password_bloc_test.dart index 262169035..a882b867d 100644 --- a/test/blocs/new_pictogram_password_bloc_test.dart +++ b/test/blocs/new_pictogram_password_bloc_test.dart @@ -9,6 +9,8 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:weekplanner/blocs/new_pictogram_password_bloc.dart'; +//tests if a new pictogram password can be properly created + class MockUserApi extends Mock implements UserApi { @override Stream me() { diff --git a/test/blocs/new_weekplan_bloc_test.dart b/test/blocs/new_weekplan_bloc_test.dart index 836ef7f85..904cf8645 100644 --- a/test/blocs/new_weekplan_bloc_test.dart +++ b/test/blocs/new_weekplan_bloc_test.dart @@ -13,9 +13,11 @@ import 'package:weekplanner/di.dart'; class MockWeekApi extends Mock implements WeekApi {} +//tests for various functions related to creating new weekplans void main() { NewWeekplanBloc bloc; Api api; + //create a mock week for use in the tests final PictogramModel mockThumbnail = PictogramModel( id: 1, lastEdit: null, @@ -24,7 +26,7 @@ void main() { imageUrl: 'http://any.tld', imageHash: null); final DisplayNameModel mockUser = - DisplayNameModel(displayName: 'User', id: '1', role: null); + DisplayNameModel(displayName: 'User', id: '1', role: null); final WeekModel mockWeek = WeekModel( thumbnail: mockThumbnail, days: null, @@ -37,7 +39,7 @@ void main() { setUp(() { api = Api('any'); api.week = MockWeekApi(); - + //setup api listeners to return the correct values from the mock week created earlier when(api.week.update(any, any, any, any)).thenAnswer((_) { return Stream.value(mockWeek); }); diff --git a/test/blocs/pictogram_bloc_test.dart b/test/blocs/pictogram_bloc_test.dart index d421ed48b..c9cf7488b 100644 --- a/test/blocs/pictogram_bloc_test.dart +++ b/test/blocs/pictogram_bloc_test.dart @@ -65,8 +65,12 @@ void main() { bloc.search(query); })); - - // TODO: Is this even a valid test? + /*Closes streams for the pictogram bloc + test does not return anything on its own (see lack of expect function) + but the dispose function should throw an error if something goes wrong within + itself. It may however still be relevant to keep this test as it ensures the + streams are actually closed at the end of the test file. + */ test('Should dispose stream', async((DoneFn done) { bloc.pictograms.listen((_) {}, onDone: done); bloc.dispose(); diff --git a/test/blocs/settings_bloc_test.dart b/test/blocs/settings_bloc_test.dart index c19453bf1..95f541363 100644 --- a/test/blocs/settings_bloc_test.dart +++ b/test/blocs/settings_bloc_test.dart @@ -85,17 +85,23 @@ void main() { }); test('Can load settings from username model', async((DoneFn done) { + // Creates listener, fires then SettingsModel is loaded + //Checks that the response is not null, that the response is equal to the + // current setting and verifies that the getSettings method is used. settingsBloc.settings.listen((SettingsModel response) { expect(response, isNotNull); expect(response.toJson(), equals(settings.toJson())); verify(api.user.getSettings(any)); done(); }); - + //Loads the setting for user settingsBloc.loadSettings(user); })); test('Can update settings', async((DoneFn done) { + // Creates listener for SettingModel, fires when a setting is loaded. + //Checks that the loaded setting is not null, and equal to the + // updatedSettings settingsBloc.settings.listen((SettingsModel loadedSettings) { expect(loadedSettings, isNotNull); expect(loadedSettings.toJson(), equals(updatedSettings.toJson())); @@ -107,7 +113,9 @@ void main() { })); test('Should dispose stream', async((DoneFn done) { + //Creates listener for settings, uses done when fired settingsBloc.settings.listen((_) {}, onDone: done); + //Disposes the settingsBloc and triggers the listener settingsBloc.dispose(); })); } diff --git a/test/blocs/toolbar_bloc_test.dart b/test/blocs/toolbar_bloc_test.dart index 414da4f47..cbf148390 100644 --- a/test/blocs/toolbar_bloc_test.dart +++ b/test/blocs/toolbar_bloc_test.dart @@ -22,37 +22,45 @@ void main() { test('Should insert log out icon when none are defined', async((DoneFn done) { + // Creates listener for visibleButtons, using a list of IconButtons + //When fired, it expects that the list contains one element bloc.visibleButtons.skip(1).listen((List response) { expect(response.length, 1); done(); }); + //Updates the icons on bloc with null and null. bloc.updateIcons(null, null); })); test('Defined icon is added to stream', async((DoneFn done) { + // Creates a map method Icon setting AppBarIcon.undo to null. final Map icons = { AppBarIcon.undo: null }; - + // Creates listener for visibleButtons to a list of IconButton + //When fired, the response is expected to have one element. bloc.visibleButtons.skip(1).listen((List response) { expect(response.length, 1); done(); }); - + //Updates bloc with updateIcons and fires the listener. bloc.updateIcons(icons, null); })); test('Defined icons are added to stream', async((DoneFn done) { + // Creates map method called icons, setting AppBarIcon.undo and .search + // to null final Map icons = { AppBarIcon.undo: null, AppBarIcon.search: null }; - + // Creates Listener on visibleButtons to a list of IconButtons + // Expects the response be to have two elements bloc.visibleButtons.skip(1).listen((List response) { expect(response.length, 2); done(); }); - + //Updates the bloc with updateIcons carrying the icon, firing the listener bloc.updateIcons(icons, null); })); } diff --git a/test/blocs/weekplan_bloc_test.dart b/test/blocs/weekplan_bloc_test.dart index 62e4e90b6..1ade26b5c 100644 --- a/test/blocs/weekplan_bloc_test.dart +++ b/test/blocs/weekplan_bloc_test.dart @@ -196,7 +196,6 @@ void main() { //Creates an markedactivity and addes it to a list with a listener. //The listener fires the expect function, expecting the lenght = 0. //Uses the clearMarkedactivities() function to remove activities. - // TODO actually add the activity to the list, including more than one act weekplanBloc.addMarkedActivity(ActivityModel( pictograms: [ PictogramModel( @@ -212,6 +211,7 @@ void main() { order: null, state: null)); + weekplanBloc.markedActivities .skip(1) .listen((List markedActivitiesList) { diff --git a/test/blocs/weekplans_bloc_test.dart b/test/blocs/weekplans_bloc_test.dart index 4fe6ddb7b..ce978c431 100644 --- a/test/blocs/weekplans_bloc_test.dart +++ b/test/blocs/weekplans_bloc_test.dart @@ -234,6 +234,7 @@ void main() { bloc.toggleMarkedWeekModel(weekModel1); expect(bloc.getNumberOfMarkedWeekModels(), 1); + bloc.toggleMarkedWeekModel(WeekModel(name: 'testWeekModel')); expect(bloc.getNumberOfMarkedWeekModels(), 2); @@ -280,12 +281,14 @@ void main() { } }); + done(); })); test('check deletion of new weekplan without oldWeekPlan', async((DoneFn done) { // Creates a list of weekNameModels with one weekNameModel + final List weekNameModelList = [ weekNameModel6 ]; @@ -299,6 +302,7 @@ void main() { // seeded weekNameModelList when(weekApi.getNames(mockUser.id)).thenAnswer((_) => rx_dart.BehaviorSubject>.seeded(weekNameModelList)); + //loads the mockUser, toggles weekModel6 and checks how many // weekModels are marked bloc.load(mockUser); @@ -513,6 +517,7 @@ void main() { textDelimiter: '"', textEndDelimiter: '"', eol: ';'); + //Converts the csv to a list called datesAndWeeks final List> datesAndWeeks = converter.convert(csv); // Foreach element in the datesAndWeeks, parse the current element to a diff --git a/test/widgets/citizen_avatar_widget_test.dart b/test/widgets/citizen_avatar_widget_test.dart index 1611c311e..b8c1a795e 100644 --- a/test/widgets/citizen_avatar_widget_test.dart +++ b/test/widgets/citizen_avatar_widget_test.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:weekplanner/widgets/citizen_avatar_widget.dart'; +//Creates a mock for the test class MockScreen extends StatelessWidget { MockScreen({@required this.callback}); @@ -24,44 +25,57 @@ class MockScreen extends StatelessWidget { } void main() { + //Setting up the environment int i = 0; const Key widgetAvatar = Key('WidgetAvatar'); const Key widgetText = Key('WidgetText'); final MockScreen mockScreen = MockScreen(callback: () => ++i); testWidgets('Test if citizen text appears', (WidgetTester tester) async { + //Pumps the mockScreen until there are no more frames scheduled await tester.pumpWidget(MaterialApp(home: mockScreen)); await tester.pumpAndSettle(); + //Checks if it can find the text (widgetText) expect(find.byKey(widgetText), findsOneWidget); }); testWidgets('Test if citizen avatar appears', (WidgetTester tester) async { + //Pumps the mockScreen until there are no more frames scheduled await tester.pumpWidget(MaterialApp(home: mockScreen)); await tester.pumpAndSettle(); + //Checks if it can find the citizen avatar (widgetAvatar) expect(find.byKey(widgetAvatar), findsOneWidget); }); testWidgets('Test if text is the username', (WidgetTester tester) async { + //Pumps the mockScreen until there are no more frames scheduled await tester.pumpWidget(MaterialApp(home: mockScreen)); await tester.pumpAndSettle(); + //Checks if "Testname" is the username expect(find.text('Testname'), findsOneWidget); }); testWidgets('Test if callback is working on avatar', (WidgetTester tester) async { i = 0; + //Pumps the mockScreen until there are no more frames scheduled await tester.pumpWidget(MaterialApp(home: mockScreen)); await tester.pumpAndSettle(); + //Uses tester.tap to check if callback works when clicking on an avatar await tester.tap(find.byKey(widgetAvatar)); + //If it works "i" would have been iterated to 1 and the assert will be true expect(i, 1); }); testWidgets('Test if callback is working on text', (WidgetTester tester) async { i = 0; + //Pumps the mockScreen until there are no more frames scheduled await tester.pumpWidget(MaterialApp(home: mockScreen)); await tester.pumpAndSettle(); + //Uses tester.tap to check if callback works when clicking on an avatar await tester.tap(find.byKey(widgetText)); + //If it works "i" would have been iterated to 1 and the assert will be true expect(i, 1); }); } diff --git a/test/widgets/giraf_3button_dialog_test.dart b/test/widgets/giraf_3button_dialog_test.dart index 7b7d8b734..661bcb970 100644 --- a/test/widgets/giraf_3button_dialog_test.dart +++ b/test/widgets/giraf_3button_dialog_test.dart @@ -45,45 +45,67 @@ class MockScreen extends StatelessWidget { void main() { testWidgets('Test if 3 button Dialog is shown', (WidgetTester tester) async { + //Pumps the MockScreen widget (calls the runApp on the widget) and finds the + // button with the key FirsButton and triggers that frame + // await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('FirstButton'))); await tester.pump(); + //Checks that the widget (Giraf3ButtonDialog) can be found expect(find.byType(Giraf3ButtonDialog), findsOneWidget); }); testWidgets('Test if 3 button Dialog is closed when tapping Cancel button', (WidgetTester tester) async { - await tester.pumpWidget(MaterialApp(home: MockScreen())); - await tester.tap(find.byKey(const Key('FirstButton'))); - await tester.pump(); - expect(find.byType(Giraf3ButtonDialog), findsOneWidget); - await tester.tap(find.byKey(const Key('ConfirmDialogCancelButton'))); - await tester.pump(); - expect(find.byType(Giraf3ButtonDialog), findsNothing); - }); + //Pumps the MockScreen widget (calls the runApp on the widget) and finds the + // button with the key FirsButton and triggers that frame + await tester.pumpWidget(MaterialApp(home: MockScreen())); + await tester.tap(find.byKey(const Key('FirstButton'))); + await tester.pump(); + //Checks that the widget (Giraf3ButtonDialog) can be found + expect(find.byType(Giraf3ButtonDialog), findsOneWidget); + // Finds the confirmDialogCancelButton and triggers it + // Pumps the frame stack (To make sure that the frame activating the + // confirmDialogCancelButton has been run) + await tester.tap(find.byKey(const Key('ConfirmDialogCancelButton'))); + await tester.pump(); + // Checks that 3 button dialog has been closed after activating the + // cancel button + expect(find.byType(Giraf3ButtonDialog), findsNothing); + }); //In this case, the confirmed action is closing the widget testWidgets( 'Test if action 1 is performed when pressing option1', (WidgetTester tester) async { + //Activates the widget MockScreen and finds the first button await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('FirstButton'))); + //Makes sure that the frame has been run await tester.pump(); + // Checks that the Griaf3ButtonDialog exists once. expect(find.byType(Giraf3ButtonDialog), findsOneWidget); + // Clicks the Option1Button and run the frame await tester.tap(find.byKey(const Key('Option1Button'))); await tester.pump(); + // Checks that the Griaf3ButtonDialog has been removed expect(find.byType(Giraf3ButtonDialog), findsNothing); }); testWidgets( 'Test if action 2 is performed when pressing option2', (WidgetTester tester) async { + // Activates the MockScreen and clicks the FirstButton. + // Also run the frame await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('FirstButton'))); await tester.pump(); + // Expects Girfat3ButtonDialog to exist only once expect(find.byType(Giraf3ButtonDialog), findsOneWidget); + // Clicks the option2Button and runs the frame await tester.tap(find.byKey(const Key('Option2Button'))); await tester.pump(); + //Checks that the Giraf3ButtonDialog has been closed expect(find.byType(Giraf3ButtonDialog), findsNothing); }); } \ No newline at end of file diff --git a/test/widgets/giraf_activity_time_picker_dialog_test.dart b/test/widgets/giraf_activity_time_picker_dialog_test.dart index 3424cd886..b9c32b437 100644 --- a/test/widgets/giraf_activity_time_picker_dialog_test.dart +++ b/test/widgets/giraf_activity_time_picker_dialog_test.dart @@ -81,17 +81,26 @@ class MockTimerBloc extends Mock implements TimerBloc { void main() { testWidgets('Test if Time Picker Dialog is shown', (WidgetTester tester) async { + // Activates the MockScreen widget and click the TimePickerOpenButton widget await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('TimePickerOpenButton'))); + //Run the next frame await tester.pump(); + //Checks that GirafActivityTimerPickerDialog exists in only once. expect(find.byType(GirafActivityTimerPickerDialog), findsOneWidget); }); testWidgets('Tests if all textfields are rendered', (WidgetTester tester) async { + // Activates the MockScreen widget and click the TimePickerOpenButton widget await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('TimePickerOpenButton'))); + // Run the next frame await tester.pump(); + //Checks that GirafActivityTimerPickerDialog exists in only once, the + // sekunderTextFildKey exists in only once, + // the MinutterTextFieldKey exists in only once and + // that TimerTextFieldKey exsits only once. expect(find.byType(GirafActivityTimerPickerDialog), findsOneWidget); expect(find.byKey(const Key('SekunderTextFieldKey')), findsOneWidget); expect(find.byKey(const Key('MinutterTextFieldKey')), findsOneWidget); @@ -100,9 +109,14 @@ void main() { testWidgets('Tests if both buttons are rendered', (WidgetTester tester) async { + // Activates the MockScreen widget and click the TimePickerOpenButton widget await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('TimePickerOpenButton'))); + // Run the next frame await tester.pump(); + //Checks that GirafActivityTimerPickerDialog exists in only once, the + // TimePickerDialogCancelButton key exists in only once, + // the TimePickerDialogAcceptButton key exists in only once and expect(find.byType(GirafActivityTimerPickerDialog), findsOneWidget); expect( find.byKey(const Key('TimePickerDialogCancelButton')), findsOneWidget); @@ -112,24 +126,35 @@ void main() { testWidgets('Test if Confirm Dialog is closed when tapping X button', (WidgetTester tester) async { + // Activates the MockScreen widget and click the TimePickerOpenButton widget await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('TimePickerOpenButton'))); + // Runs the next frame await tester.pump(); + // Clicks the widget with key TimePickerDialogCancelButton await tester.tap(find.byKey(const Key('TimePickerDialogCancelButton'))); + // Runs the next frame await tester.pump(); + //Checks that the GirafActivityTimerPickerDIalog does not exists expect(find.byType(GirafActivityTimerPickerDialog), findsNothing); }); testWidgets( 'Test if Time Picker Dialog no longer is shown after pressing accept', (WidgetTester tester) async { + // Activates the MockScreen widget and click the TimePickerOpenButton widget await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('TimePickerOpenButton'))); + // Runs the next frame await tester.pump(); + // enters the textfield with key 'sekunderTextFieldKey' and types '1' await tester.enterText(find.byKey(const Key('SekunderTextFieldKey')), '1'); + // Runs the next frame and clicks the + // widget with key TimePickerDialogAcceptButton and runs the next frame await tester.pump(); await tester.tap(find.byKey(const Key('TimePickerDialogAcceptButton'))); await tester.pump(); + // Checks that the GirafActivityTimerPickerDialog does not exist expect(find.byType(GirafActivityTimerPickerDialog), findsNothing); }); @@ -138,9 +163,12 @@ void main() { const int hours = 1; const int minutes = 2; const int seconds = 3; + // Activates the MockScreen widget and click the TimePickerOpenButton widget await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('TimePickerOpenButton'))); + // Runs next frame await tester.pump(); + // Enters the hours, minutes and seconds into their textfields await tester.enterText( find.byKey(const Key('TimerTextFieldKey')), hours.toString()); await tester.pump(); @@ -149,12 +177,16 @@ void main() { await tester.pump(); await tester.enterText( find.byKey(const Key('SekunderTextFieldKey')), seconds.toString()); + // Runs next frame and clicks widget the with key + // TimePickerDialogAcceptButton and runs the next frame await tester.pump(); await tester.tap(find.byKey(const Key('TimePickerDialogAcceptButton'))); await tester.pump(); + //Checks that the timer is instantiated with a listener _mockTimerBloc.timerIsInstantiated.listen((bool b) { expect(b, true); }); + // Checks that the timer and expected duration is equal in milliseconds. expect( _activityModel.timer.fullLength, const Duration(hours: hours, minutes: minutes, seconds: seconds) @@ -164,18 +196,26 @@ void main() { testWidgets( 'Test that wrong 0 time input on textfields prompts a notify dialog' 'with correct message', (WidgetTester tester) async { + // Activates the MockScreen widget and click the TimePickerOpenButton widget await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('TimePickerOpenButton'))); + // Runs next frame and enters the textfield with key TimerTextFieldKey and + // types 0 await tester.pump(); await tester.enterText(find.byKey(const Key('TimerTextFieldKey')), '0'); + // Runs next frame and enters 0 in min and 0 sec into their textFields await tester.pump(); await tester.enterText( find.byKey(const Key('MinutterTextFieldKey')), '0'); await tester.pump(); await tester.enterText( find.byKey(const Key('SekunderTextFieldKey')), '0'); + // Runs the next frame and clicks widget with + // TimePickerDialogAcceptButton key await tester.pump(); await tester.tap(find.byKey(const Key('TimePickerDialogAcceptButton'))); + // Runs next frame and checks that the text + // 'Den valgte tid må ikke være 0' is found once await tester.pump(); expect(find.text('Den valgte tid må ikke være 0'), findsOneWidget); }); @@ -183,10 +223,14 @@ void main() { testWidgets( 'Test that no input on textfields prompts a notify dialog' 'with correct message', (WidgetTester tester) async { + // Activates the MockScreen widget and click the TimePickerOpenButton widget await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('TimePickerOpenButton'))); + // Runs next frame and click widget with key TimePickerDialogAcceptButton await tester.pump(); await tester.tap(find.byKey(const Key('TimePickerDialogAcceptButton'))); + // Runs next frame and checks that the text + // 'Den valgte tid må ikke være 0' is found once await tester.pump(); expect(find.text('Den valgte tid må ikke være 0'), findsOneWidget); }); diff --git a/test/widgets/giraf_button_widget_test.dart b/test/widgets/giraf_button_widget_test.dart index f3377fb4b..3199c0232 100644 --- a/test/widgets/giraf_button_widget_test.dart +++ b/test/widgets/giraf_button_widget_test.dart @@ -36,33 +36,42 @@ class MockScreen extends StatelessWidget { void main() { testWidgets('Test if GirafButton is shown', (WidgetTester tester) async { + // Opens the MockScreen widget await tester.pumpWidget(MaterialApp(home: MockScreen())); + // Checks that the GirafButton exists on the MockScreen expect(find.byType(GirafButton), findsOneWidget); }); testWidgets('GirafButton has a title', (WidgetTester tester) async { + // Opens the MockScreen widget await tester.pumpWidget(MaterialApp(home: MockScreen())); - + // Checks that the text PressButton exists on the MockScreen expect(find.text('PressButton'), findsOneWidget); }); testWidgets('GirafButton has an icon', (WidgetTester tester) async { + // Opens the MockScreen widget await tester.pumpWidget(MaterialApp(home: MockScreen())); - + // Checks that the acceptIcon widget exists on the MockScreen expect(find.byWidget(acceptIcon), findsOneWidget); }); testWidgets( 'GirafButton is pressed and' ' works when enabled', (WidgetTester tester) async { + // TODO; Skal revuderes, mange af disse ting er nok unødvendige final Completer done = Completer(); final MockScreen screen = MockScreen(); + // Opens the MockScreen widget and enables the GirafButton await tester.pumpWidget(MaterialApp(home: screen)); screen.btnEnabled.add(true); + // Runs all stacked frames and finds widget with Button key await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('Button'))); + //Runs next frame and creates listener for isPressed await tester.pump(); screen.isPressed.listen((bool status) { + // Checks that the status of the button is true expect(status, isTrue); done.complete(); }); @@ -72,13 +81,18 @@ void main() { testWidgets( 'GirafButton is pressed and' ' does not work when disabled', (WidgetTester tester) async { + // TODO; Skal revuderes, mange af disse ting er nok unødvendige final Completer done = Completer(); final MockScreen screen = MockScreen(); + // Opens the MockScreen widget and enables the GirafButton await tester.pumpWidget(MaterialApp(home: screen)); await tester.pump(); + // Finds the widget with key Button and runs next frame await tester.tap(find.byKey(const Key('Button'))); + //Runs next frame and creates listener for isPressed await tester.pump(); screen.isPressed.listen((bool status) { + // Checks that the status of the button is false expect(status, isFalse); done.complete(); }); diff --git a/test/widgets/giraf_confirm_dialog_test.dart b/test/widgets/giraf_confirm_dialog_test.dart index 84d74aa6a..96d4496a6 100644 --- a/test/widgets/giraf_confirm_dialog_test.dart +++ b/test/widgets/giraf_confirm_dialog_test.dart @@ -40,20 +40,26 @@ class MockScreen extends StatelessWidget { void main() { testWidgets('Test if Confirm Dialog is shown', (WidgetTester tester) async { + // Activates mockScreen and clicks widget with key FistButton await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('FirstButton'))); + //Runs next frame and checks that GirafConfirmDialog exists once await tester.pump(); expect(find.byType(GirafConfirmDialog), findsOneWidget); }); testWidgets('Test if Confirm Dialog is closed when tapping Cancel button', (WidgetTester tester) async { + // Activates mockScreen and clicks widget with key FistButton await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('FirstButton'))); + //Runs next frame and checks that GirafConfirmDialog exists once await tester.pump(); expect(find.byType(GirafConfirmDialog), findsOneWidget); + // Clicks the widget with key ConfirmDialogCancelButton and runs next frame await tester.tap(find.byKey(const Key('ConfirmDialogCancelButton'))); await tester.pump(); + // Checks that GirafConfirmDialog has been closed. expect(find.byType(GirafConfirmDialog), findsNothing); }); @@ -61,12 +67,16 @@ void main() { testWidgets( 'Test if confirmed action is performed when tapping Confirm button', (WidgetTester tester) async { + // Activates mockScreen and clicks widget with key FistButton await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('FirstButton'))); + //Runs next frame and checks that GirafConfirmDialog exists once await tester.pump(); expect(find.byType(GirafConfirmDialog), findsOneWidget); + // Clicks the widget with key ConfirmDialogConfirmButton and runs next frame await tester.tap(find.byKey(const Key('ConfirmDialogConfirmButton'))); await tester.pump(); + // Checks that GirafConfirmDialog has been closed. expect(find.byType(GirafConfirmDialog), findsNothing); }); } diff --git a/test/widgets/giraf_title_header_test.dart b/test/widgets/giraf_title_header_test.dart index b7314f14f..139410667 100644 --- a/test/widgets/giraf_title_header_test.dart +++ b/test/widgets/giraf_title_header_test.dart @@ -5,21 +5,25 @@ import 'package:weekplanner/widgets/giraf_title_header.dart'; void main() { testWidgets('Test that a null title is replaced with empty', (WidgetTester tester) async { + //Pumps a widget containing a GirafTitleHeader with the title "TitleHeader" await tester.pumpWidget(const MaterialApp( home: Scaffold( body: GirafTitleHeader(title: 'TitleHeader'), ))); await tester.pump(); + //Checks if the text is "TitleHeader" expect(find.text('TitleHeader'), findsOneWidget); }); testWidgets('Test that a null title is replaced with empty', (WidgetTester tester) async { + //Pumps a widget containing a GirafTitleHeader with no title assigned" await tester.pumpWidget(const MaterialApp( home: Scaffold( body: GirafTitleHeader(), ))); await tester.pump(); + //Checks if the text is empty expect(find.text(''), findsOneWidget); }); } diff --git a/test/widgets/loading_spinner_widget_test.dart b/test/widgets/loading_spinner_widget_test.dart index 9b2bf96ce..8d7fbbc12 100644 --- a/test/widgets/loading_spinner_widget_test.dart +++ b/test/widgets/loading_spinner_widget_test.dart @@ -3,6 +3,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:weekplanner/routes.dart'; import 'package:weekplanner/widgets/loading_spinner_widget.dart'; +//Creates a mock for the test class MockScreen extends StatelessWidget { @override Widget build(BuildContext context) { @@ -27,6 +28,7 @@ class MockScreen extends StatelessWidget { ); } + //Function for showing the loading spinner void loadingSpinner(BuildContext context) { showLoadingSpinner(context, true); } @@ -34,22 +36,28 @@ class MockScreen extends StatelessWidget { void main() { testWidgets('Test if Loading Spinner is shown', (WidgetTester tester) async { + //Pumps the MockScreen and tries to find the "FirstButton" with tester.tap await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('FirstButton'))); await tester.pump(); + //As the "FirstButton" is set to toggle the loading spinner (can be seen in the mock above), + //It is now expected that the loading spinner is being shown expect(find.byType(CircularProgressIndicator), findsOneWidget); }); testWidgets('Test if Loading Spinner is removed again', (WidgetTester tester) async { + //Line 51-54 is the same as above, toggling the loading spinner on await tester.pumpWidget(MaterialApp(home: MockScreen())); await tester.tap(find.byKey(const Key('FirstButton'))); await tester.pump(); expect(find.byType(CircularProgressIndicator), findsOneWidget); await tester.pump(); + //Finds the "SecondButton" which toggles the loading spinner off again await tester.tap(find.byKey(const Key('SecondButton')), warnIfMissed: false); await tester.pump(); + //Checks to see if the loading spinner is removed expect(find.byType(CircularProgressIndicator), findsNothing); }); } diff --git a/test/widgets/pictogram_image_test.dart b/test/widgets/pictogram_image_test.dart index 3de910c7d..497de9d31 100644 --- a/test/widgets/pictogram_image_test.dart +++ b/test/widgets/pictogram_image_test.dart @@ -67,40 +67,53 @@ void main() { onPressed: () {}, )); + // Finder that gets all widgets that are PictogramImages. final Finder f = find.byWidgetPredicate((Widget widget) { return widget is PictogramImage; }); + // Verify that only one PictogramImage is found. + // The test fails if there there is not exactly one PictogramImage. expect(f, findsOneWidget); final Completer waiter = Completer(); + + // Listen for updates on the image stream. + // The function inside is called every time bloc.image is updated. bloc.image.listen(expectAsync1((Image image) async { + // Update the frame. await tester.pump(); + + // Expect that there is one and only one Image widget. + // The test fails if there is not exactly one Image widget. expect(find.byType(Image), findsOneWidget); waiter.complete(); })); + await waiter.future; }); - testWidgets('triggers callback on tap', (WidgetTester tester) async { - final Completer done = Completer(); + testWidgets('Widget triggers callback on tap', (WidgetTester tester) async { + bool onPressedCallbackTriggered = false; + //sets up the widget. await tester.pumpWidget(PictogramImage( + key: Key('pictogram_image_key'), pictogram: pictogramModel, onPressed: () { - done.complete(true); + onPressedCallbackTriggered = true; }, )); - final Finder f = find.byWidgetPredicate((Widget widget) { - return widget is StreamBuilder; - }); + // Finder that gets the PictogramImage widget by key. + final Finder f = find.byKey(Key('pictogram_image_key')); - bloc.image.listen(expectAsync1((Image image) async { - await tester.pump(); - await tester.tap(f); - })); - await done.future; + // Tap the PictogramImage widget. + await tester.tap(f); + await tester.pump(); + + // Expect that the onPressed callback was triggered. + expect(onPressedCallbackTriggered, true); }); testWidgets('shows spinner on loading', (WidgetTester tester) async { @@ -109,13 +122,20 @@ void main() { onPressed: () {}, )); + // Finder that gets all widgets that are CircularProgressIndicators. final Finder f = find.byWidgetPredicate((Widget widget) { return widget is CircularProgressIndicator; }); + // Verify that only one CircularProgressIndicator is found. + // The test fails if there there is not exactly one + // CircularProgressIndicator. expect(f, findsOneWidget); final Completer waiter = Completer(); + + // Listen for updates on the image stream. + // The function inside is called every time bloc.image is updated. bloc.image.listen(expectAsync1((Image image) async { await tester.pump(); expect(f, findsNothing); @@ -131,24 +151,37 @@ void main() { onPressed: () {}, haveRights: true, )); + expect(find.byType(GirafButton), findsOneWidget); }); testWidgets('show delete button when comparing ids', (WidgetTester tester) async { String id; + final Completer done = Completer(); + + // Listen for updates on the currently authenticated user. + // The function inside is called every time the given authenticaded user's + // Information is changed. api.user.me().listen((GirafUserModel model) { id = model.id; done.complete(); }); + // Wait for the new user to be authenticated, + // which is done when the stream is updated. await done.future; + + // Create a new PictogramImage where the authenticated user's rights are + // determined by pictogramModel.userId. await tester.pumpWidget(PictogramImage( pictogram: pictogramModel, onPressed: () {}, haveRights: pictogramModel.userId == id, )); + + // Expect that there is one and only one GirafButton. expect(find.byType(GirafButton), findsOneWidget); }); @@ -159,6 +192,8 @@ void main() { onPressed: () {}, haveRights: false, )); + + // Expect that there is no GirafButton when the user does not have rights. expect(find.byType(GirafButton), findsNothing); }); } diff --git a/test/widgets/pictogram_text_test.dart b/test/widgets/pictogram_text_test.dart index 9ec546b79..5d4f72ac2 100644 --- a/test/widgets/pictogram_text_test.dart +++ b/test/widgets/pictogram_text_test.dart @@ -21,6 +21,7 @@ import 'package:weekplanner/widgets/pictogram_text.dart'; SettingsModel mockSettings; +//tests for pictogram text being rendered as expected class MockUserApi extends Mock implements UserApi { @override Stream me() { @@ -39,7 +40,7 @@ void main() { SettingsBloc settingsBloc; ActivityBloc activityBloc; AuthBloc authBloc; - + //create data for use in the tests, such as users, pictograms, and activites final DisplayNameModel user = DisplayNameModel( displayName: 'Anders And', id: '101', role: Role.Guardian.toString());