From 76e730946746f84aa6f199c012a934d6cd13921e Mon Sep 17 00:00:00 2001 From: "h.ehrenfried" <2012537@stud.hs-mannheim.de> Date: Thu, 2 Mar 2023 18:49:14 +0100 Subject: [PATCH 01/27] create_input_provider_test --- test/input_provider_test.dart | 87 +++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 test/input_provider_test.dart diff --git a/test/input_provider_test.dart b/test/input_provider_test.dart new file mode 100644 index 0000000..661023e --- /dev/null +++ b/test/input_provider_test.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:smoke_cess_app/providers/input_provider.dart'; + + +void main() { + group('InputProvider', () { + test('Initial values are correct', () { + late final inputProvider = InputProvider(); + + expect(inputProvider.sliderValue, equals(50)); + expect(inputProvider.textController.text, equals('')); + expect(inputProvider.relapseCategory, equals('')); + expect(inputProvider.getTimeEntry('wokeUpAt'),equals(const TimeOfDay(hour: 8, minute: 0))); + expect(inputProvider.getTimeEntry('sleptAt'),equals(const TimeOfDay(hour: 22, minute: 0))); + }); + + test('Setters work right way', () { + late final inputProvider = InputProvider(); + + inputProvider.sliderValue = 75; + expect(inputProvider.sliderValue, equals(75)); + + inputProvider.textController.text = 'Test'; + expect(inputProvider.textController.text, equals('Test')); + + inputProvider.relapseCategory = 'Test'; + expect(inputProvider.relapseCategory, equals('Test')); + + inputProvider.setTime('wokeUpAt', const TimeOfDay(hour: 7, minute: 0)); + expect(inputProvider.getTimeEntry('wokeUpAt'),equals(const TimeOfDay(hour: 7, minute: 0))); + + inputProvider.setTime('sleptAt', const TimeOfDay(hour: 23, minute: 0)); + expect(inputProvider.getTimeEntry('sleptAt'), equals(const TimeOfDay(hour: 23, minute: 0))); + }); + test('Reset Fields should reset all fields correctly', () async{ + final inputProvider = InputProvider(); + + inputProvider.sliderValue = 44; + inputProvider.textController.text = 'Test'; + inputProvider.setTime('wokeUpAt', const TimeOfDay(hour: 7, minute: 0)); + inputProvider.setTime('sleptAt', const TimeOfDay(hour: 23, minute: 0)); + + final result = await inputProvider.saveMood(); // calls private function ResetFields + + expect(result, equals(1)); + expect(inputProvider.sliderValue, equals(50)); + expect(inputProvider.textController.text, equals('')); + expect(inputProvider.getTimeEntry('wokeUpAt'),equals(const TimeOfDay(hour: 8, minute: 0))); + expect(inputProvider.getTimeEntry('sleptAt'), equals(const TimeOfDay(hour: 22, minute: 0))); + + + + }); + test('Save Mood ', () async { + late final inputProvider = InputProvider(); + + final result = await inputProvider.saveMood(); + + expect(result, equals(1)); + expect(inputProvider.sliderValue, equals(50)); + expect(inputProvider.textController.text, equals('')); + }); + + test('Save Relapse', () async { + late final inputProvider = InputProvider(); + + final result = await inputProvider.saveRelapse(); + + expect(result, equals(1)); + expect(inputProvider.relapseCategory, equals('')); + expect(inputProvider.textController.text, equals('')); + }); + + test('Save Sleep', () async { + late final inputProvider = InputProvider(); + + final result = await inputProvider.saveSleep('wokeUpAt', 'sleptAt'); + + expect(result, equals(1)); + expect(inputProvider.sliderValue, equals(50)); + expect(inputProvider.textController.text, equals('')); + expect(inputProvider.getTimeEntry('wokeUpAt'),equals(const TimeOfDay(hour: 8, minute: 0))); + expect(inputProvider.getTimeEntry('sleptAt'),equals(const TimeOfDay(hour: 22, minute: 0))); + }); + }); +} From ca3f8ef52a3627bf3002ccf55e39b3ba8ee3655f Mon Sep 17 00:00:00 2001 From: "h.ehrenfried" <2012537@stud.hs-mannheim.de> Date: Fri, 3 Mar 2023 00:17:56 +0100 Subject: [PATCH 02/27] added timer_provider_tests --- test/timer_provider_test.dart | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 test/timer_provider_test.dart diff --git a/test/timer_provider_test.dart b/test/timer_provider_test.dart new file mode 100644 index 0000000..ba5b89f --- /dev/null +++ b/test/timer_provider_test.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:smoke_cess_app/providers/timer_provider.dart'; + +void main() { + test('Timer should start and set started to true', () { + final timerProvider = TimerProvider(); + timerProvider.startTimer(Duration(seconds: 10)); + expect(timerProvider.started, true); + }); + + test('Elapsed time should increase and be less than or equal to the duration', () { + final timerProvider = TimerProvider(); + timerProvider.startTimer(Duration(seconds: 10)); + final initialElapsedSeconds = timerProvider.elapsedSeconds; + // Wait for the timer to tick at least once. + Future.delayed(Duration(seconds: 2), () { + expect(timerProvider.elapsedSeconds, greaterThan(initialElapsedSeconds)); + expect(timerProvider.elapsedSeconds, lessThanOrEqualTo(10)); + }); +}); + +test('Timer should stop and set started to false', () { + final timerProvider = TimerProvider(); + timerProvider.startTimer(Duration(seconds: 10)); + timerProvider.stopTimer(); + expect(timerProvider.started, false); +}); + +test('Elapsed seconds should be 0 when timer is not running', () { + final timerProvider = TimerProvider(); + expect(timerProvider.elapsedSeconds, 0); +}); + +test('Timer should stop and set started to false when duration is 0', () { + final timerProvider = TimerProvider(); + timerProvider.startTimer(Duration(seconds: 0)); + expect(timerProvider.started, false); +}); + + +} + From e426f47a0848ebaf9bd6987ee202b52061e52312 Mon Sep 17 00:00:00 2001 From: "h.ehrenfried" <2012537@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 11:39:41 +0100 Subject: [PATCH 03/27] Create widget_timer_button_test.dart --- test/widget_timer_button_test.dart | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 test/widget_timer_button_test.dart diff --git a/test/widget_timer_button_test.dart b/test/widget_timer_button_test.dart new file mode 100644 index 0000000..6491896 --- /dev/null +++ b/test/widget_timer_button_test.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:smoke_cess_app/widgets/timer_button.dart'; + +void main() { + testWidgets('TimerButton should display icon & color and react to click', (WidgetTester tester) async { + // Define the icon and color + final Icon icon = Icon(Icons.play_arrow); + final Color color = Colors.green; + + // Build the TimerButton + var clicked = false; + await tester.pumpWidget( + MaterialApp( + home: TimerButton( + onClicked: () => clicked = true, + icon: icon, + color: color, + ), + ), + ); + + // Verify that the icon and color are displayed + expect(find.byWidgetPredicate((widget) => widget is CircleAvatar && widget.child == icon ), findsOneWidget); + + expect(find.byWidgetPredicate((widget) => widget is CircleAvatar && widget.backgroundColor == color ), findsOneWidget); + + // Tap the button + await tester.tap(find.byType(InkWell)); + await tester.pump(); + + // Verify that the onClicked callback was called + expect(clicked, true); + }); +} From dffa3808dd5eba4bb30c7c3d126016fd426f1aa8 Mon Sep 17 00:00:00 2001 From: "h.ehrenfried" <2012537@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 12:09:01 +0100 Subject: [PATCH 04/27] create widget tests --- test/widget_drop_down_test.dart | 46 +++++++++++++++++++ test/widget_elevated_card_test.dart | 70 +++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 test/widget_drop_down_test.dart create mode 100644 test/widget_elevated_card_test.dart diff --git a/test/widget_drop_down_test.dart b/test/widget_drop_down_test.dart new file mode 100644 index 0000000..999f125 --- /dev/null +++ b/test/widget_drop_down_test.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/providers/input_provider.dart'; +import 'package:smoke_cess_app/widgets/drop_down.dart'; + +void main() { + testWidgets('DropDown should display items and update input model', (WidgetTester tester) async { + // Define the list of items + final items = ['Item 1', 'Item 2', 'Item 3']; + + // Create an instance of the InputProvider and add it to the widget tree + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: MaterialApp( + home: Scaffold( + body: DropDown(items), + ), + ), + ), + ); + + // Verify that the DropDown displays the first item + expect(find.text(items[0]), findsOneWidget); + + // Tap the DropDown to open the menu + await tester.tap(find.byType(DropdownButtonFormField)); + await tester.pump(); + + // Verify that the menu displays the correct items + for (final item in items) { + expect(find.text(item), findsOneWidget); + } + + // Select the second item + await tester.tap(find.text(items[1])); + await tester.pump(); + + // Verify that the input model was updated with the selected item + expect(inputProvider.relapseCategory, equals(items[1])); + }); +} diff --git a/test/widget_elevated_card_test.dart b/test/widget_elevated_card_test.dart new file mode 100644 index 0000000..2571582 --- /dev/null +++ b/test/widget_elevated_card_test.dart @@ -0,0 +1,70 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:smoke_cess_app/widgets/elevated_card.dart'; + + +void main() { + group('ElevatedCard', () { + testWidgets('Renders the title and child', (WidgetTester tester) async { + // Arrange + const title = 'My Card Title'; + const childText = 'My Card Content'; + final child = Text(childText); + final card = ElevatedCard (title: title, child: child); + + // Act + await tester.pumpWidget(MaterialApp(home: Scaffold(body: card))); + final titleFinder = find.text(title); + final childFinder = find.text(childText); + + // Assert + expect(titleFinder, findsOneWidget); + expect(childFinder, findsOneWidget); + }); + + testWidgets('Uses default title style', (WidgetTester tester) async { + // Arrange + final card = ElevatedCard(title: 'My Title', child: Container()); + + // Act + await tester.pumpWidget(MaterialApp(home: Scaffold(body: card))); + final titleFinder = find.text('My Title'); + final titleWidget = tester.widget(titleFinder); + + // Assert + expect(titleWidget.style?.fontSize, equals(16.0)); + expect(titleWidget.style?.fontWeight, equals(FontWeight.bold)); + }); + + testWidgets('Uses custom title style', (WidgetTester tester) async { + // Arrange + final card = ElevatedCard( + title: 'My Title', + child: Container(), + ); + + // Act + await tester.pumpWidget(MaterialApp(home: Scaffold(body: card))); + final titleFinder = find.text('My Title'); + final titleWidget = tester.widget(titleFinder); + + // Assert + expect(titleWidget.style?.fontSize, equals(20.0)); + expect(titleWidget.style?.fontWeight, equals(FontWeight.bold)); + }); + + testWidgets('Has rounded corners', (WidgetTester tester) async { + // Arrange + final card = ElevatedCard(title: 'My Title', child: Container()); + + // Act + await tester.pumpWidget(MaterialApp(home: Scaffold(body: card))); + final cardFinder = find.byType(Card); + final cardWidget = tester.widget(cardFinder); + + // Assert + expect(cardWidget.shape, + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0)))); + }); + }); +} From 8b936e2207dc2b18358712584668cfedc0b46b87 Mon Sep 17 00:00:00 2001 From: "h.ehrenfried" <2012537@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 15:50:36 +0100 Subject: [PATCH 05/27] create popup_test todo_icon.test --- test/widget_missing_config_popup_test.dart | 17 ++++++++++++++ test/widget_todo_icon_test.dart | 26 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 test/widget_missing_config_popup_test.dart create mode 100644 test/widget_todo_icon_test.dart diff --git a/test/widget_missing_config_popup_test.dart b/test/widget_missing_config_popup_test.dart new file mode 100644 index 0000000..a4c3f3d --- /dev/null +++ b/test/widget_missing_config_popup_test.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:smoke_cess_app/widgets/missing_config_popup.dart'; + +void main() { + testWidgets('MissingConfigPopup displays title and text', (WidgetTester tester) async { + final String title = 'Missing Configuration'; + final String text = 'Please configure the app before using it.'; + + await tester.pumpWidget(MaterialApp( + home: MissingConfigPopup(title: title, text: text), + )); + + expect(find.text(title), findsOneWidget); + expect(find.text(text), findsOneWidget); + }); +} diff --git a/test/widget_todo_icon_test.dart b/test/widget_todo_icon_test.dart new file mode 100644 index 0000000..faefdbd --- /dev/null +++ b/test/widget_todo_icon_test.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:smoke_cess_app/widgets/todo_icon.dart'; + + + +void main() { + testWidgets('MyToDoIcon has a red dot', (WidgetTester tester) async { + // Build the widget tree + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + + body: MyToDoIcon ( + Icon(Icons.check), + ), + ), + ), + ); + + // Verify that the red dot is present + expect(find.byIcon(Icons.brightness_1), findsOneWidget); + // paints => verifys that a widget paints a certain shape or color v^1.15.30 + expect(find.byIcon(Icons.brightness_1).first, paints..circle(color: Colors.redAccent)); + }); +} From 999aa8fc42cfac989ecea46c911cbfbe7d98bc89 Mon Sep 17 00:00:00 2001 From: "k.mannweiler" <2012491@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 18:36:10 +0100 Subject: [PATCH 06/27] Fixed Tests --- test/input_provider_test.dart | 64 +++++++++++++--------- test/timer_provider_test.dart | 59 ++++++++++---------- test/widget_elevated_card_test.dart | 13 +++-- test/widget_missing_config_popup_test.dart | 17 ------ test/widget_timer_button_test.dart | 35 ------------ test/widget_todo_icon_test.dart | 9 +-- 6 files changed, 74 insertions(+), 123 deletions(-) delete mode 100644 test/widget_missing_config_popup_test.dart delete mode 100644 test/widget_timer_button_test.dart diff --git a/test/input_provider_test.dart b/test/input_provider_test.dart index 661023e..088b68b 100644 --- a/test/input_provider_test.dart +++ b/test/input_provider_test.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:smoke_cess_app/providers/input_provider.dart'; - void main() { group('InputProvider', () { test('Initial values are correct', () { @@ -11,12 +10,14 @@ void main() { expect(inputProvider.sliderValue, equals(50)); expect(inputProvider.textController.text, equals('')); expect(inputProvider.relapseCategory, equals('')); - expect(inputProvider.getTimeEntry('wokeUpAt'),equals(const TimeOfDay(hour: 8, minute: 0))); - expect(inputProvider.getTimeEntry('sleptAt'),equals(const TimeOfDay(hour: 22, minute: 0))); + expect(inputProvider.getTimeEntry(SleepTimes.wokeUpAt), + equals(const TimeOfDay(hour: 8, minute: 0))); + expect(inputProvider.getTimeEntry(SleepTimes.sleptAt), + equals(const TimeOfDay(hour: 22, minute: 0))); }); test('Setters work right way', () { - late final inputProvider = InputProvider(); + late final inputProvider = InputProvider(); inputProvider.sliderValue = 75; expect(inputProvider.sliderValue, equals(75)); @@ -27,33 +28,39 @@ void main() { inputProvider.relapseCategory = 'Test'; expect(inputProvider.relapseCategory, equals('Test')); - inputProvider.setTime('wokeUpAt', const TimeOfDay(hour: 7, minute: 0)); - expect(inputProvider.getTimeEntry('wokeUpAt'),equals(const TimeOfDay(hour: 7, minute: 0))); + inputProvider.setTime( + SleepTimes.wokeUpAt, const TimeOfDay(hour: 7, minute: 0)); + expect(inputProvider.getTimeEntry(SleepTimes.wokeUpAt), + equals(const TimeOfDay(hour: 7, minute: 0))); - inputProvider.setTime('sleptAt', const TimeOfDay(hour: 23, minute: 0)); - expect(inputProvider.getTimeEntry('sleptAt'), equals(const TimeOfDay(hour: 23, minute: 0))); + inputProvider.setTime( + SleepTimes.sleptAt, const TimeOfDay(hour: 23, minute: 0)); + expect(inputProvider.getTimeEntry(SleepTimes.sleptAt), + equals(const TimeOfDay(hour: 23, minute: 0))); }); - test('Reset Fields should reset all fields correctly', () async{ + test('Reset Fields should reset all fields correctly', () async { final inputProvider = InputProvider(); - inputProvider.sliderValue = 44; - inputProvider.textController.text = 'Test'; - inputProvider.setTime('wokeUpAt', const TimeOfDay(hour: 7, minute: 0)); - inputProvider.setTime('sleptAt', const TimeOfDay(hour: 23, minute: 0)); + inputProvider.sliderValue = 44; + inputProvider.textController.text = 'Test'; + inputProvider.setTime( + SleepTimes.wokeUpAt, const TimeOfDay(hour: 7, minute: 0)); + inputProvider.setTime( + SleepTimes.sleptAt, const TimeOfDay(hour: 23, minute: 0)); - final result = await inputProvider.saveMood(); // calls private function ResetFields + final result = + await inputProvider.saveMood(); // calls private function ResetFields - expect(result, equals(1)); - expect(inputProvider.sliderValue, equals(50)); - expect(inputProvider.textController.text, equals('')); - expect(inputProvider.getTimeEntry('wokeUpAt'),equals(const TimeOfDay(hour: 8, minute: 0))); - expect(inputProvider.getTimeEntry('sleptAt'), equals(const TimeOfDay(hour: 22, minute: 0))); - - - + expect(result, equals(1)); + expect(inputProvider.sliderValue, equals(50)); + expect(inputProvider.textController.text, equals('')); + expect(inputProvider.getTimeEntry(SleepTimes.wokeUpAt), + equals(const TimeOfDay(hour: 8, minute: 0))); + expect(inputProvider.getTimeEntry(SleepTimes.sleptAt), + equals(const TimeOfDay(hour: 22, minute: 0))); }); test('Save Mood ', () async { - late final inputProvider = InputProvider(); + late final inputProvider = InputProvider(); final result = await inputProvider.saveMood(); @@ -63,7 +70,7 @@ void main() { }); test('Save Relapse', () async { - late final inputProvider = InputProvider(); + late final inputProvider = InputProvider(); final result = await inputProvider.saveRelapse(); @@ -75,13 +82,16 @@ void main() { test('Save Sleep', () async { late final inputProvider = InputProvider(); - final result = await inputProvider.saveSleep('wokeUpAt', 'sleptAt'); + final result = await inputProvider.saveSleep( + SleepTimes.wokeUpAt, SleepTimes.sleptAt); expect(result, equals(1)); expect(inputProvider.sliderValue, equals(50)); expect(inputProvider.textController.text, equals('')); - expect(inputProvider.getTimeEntry('wokeUpAt'),equals(const TimeOfDay(hour: 8, minute: 0))); - expect(inputProvider.getTimeEntry('sleptAt'),equals(const TimeOfDay(hour: 22, minute: 0))); + expect(inputProvider.getTimeEntry(SleepTimes.wokeUpAt), + equals(const TimeOfDay(hour: 8, minute: 0))); + expect(inputProvider.getTimeEntry(SleepTimes.sleptAt), + equals(const TimeOfDay(hour: 22, minute: 0))); }); }); } diff --git a/test/timer_provider_test.dart b/test/timer_provider_test.dart index ba5b89f..7f6f1df 100644 --- a/test/timer_provider_test.dart +++ b/test/timer_provider_test.dart @@ -1,43 +1,40 @@ -import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:smoke_cess_app/providers/timer_provider.dart'; void main() { test('Timer should start and set started to true', () { - final timerProvider = TimerProvider(); - timerProvider.startTimer(Duration(seconds: 10)); - expect(timerProvider.started, true); + final timerProvider = TimerProvider(); + timerProvider.startTimer(const Duration(seconds: 10)); + expect(timerProvider.started, true); }); - test('Elapsed time should increase and be less than or equal to the duration', () { - final timerProvider = TimerProvider(); - timerProvider.startTimer(Duration(seconds: 10)); - final initialElapsedSeconds = timerProvider.elapsedSeconds; - // Wait for the timer to tick at least once. - Future.delayed(Duration(seconds: 2), () { - expect(timerProvider.elapsedSeconds, greaterThan(initialElapsedSeconds)); - expect(timerProvider.elapsedSeconds, lessThanOrEqualTo(10)); + test('Elapsed time should increase and be less than or equal to the duration', + () { + final timerProvider = TimerProvider(); + timerProvider.startTimer(const Duration(seconds: 10)); + final initialElapsedSeconds = timerProvider.elapsedSeconds; + // Wait for the timer to tick at least once. + Future.delayed(const Duration(seconds: 2), () { + expect(timerProvider.elapsedSeconds, greaterThan(initialElapsedSeconds)); + expect(timerProvider.elapsedSeconds, lessThanOrEqualTo(10)); + }); }); -}); -test('Timer should stop and set started to false', () { - final timerProvider = TimerProvider(); - timerProvider.startTimer(Duration(seconds: 10)); - timerProvider.stopTimer(); - expect(timerProvider.started, false); -}); - -test('Elapsed seconds should be 0 when timer is not running', () { - final timerProvider = TimerProvider(); - expect(timerProvider.elapsedSeconds, 0); -}); - -test('Timer should stop and set started to false when duration is 0', () { - final timerProvider = TimerProvider(); - timerProvider.startTimer(Duration(seconds: 0)); - expect(timerProvider.started, false); -}); + test('Timer should stop and set started to false', () { + final timerProvider = TimerProvider(); + timerProvider.startTimer(const Duration(seconds: 10)); + timerProvider.stopTimer(); + expect(timerProvider.started, false); + }); + test('Elapsed seconds should be 0 when timer is not running', () { + final timerProvider = TimerProvider(); + expect(timerProvider.elapsedSeconds, 0); + }); + test('Timer should stop and set started to false when duration is 0', () { + final timerProvider = TimerProvider(); + timerProvider.startTimer(const Duration(seconds: 0)); + expect(timerProvider.started, false); + }); } - diff --git a/test/widget_elevated_card_test.dart b/test/widget_elevated_card_test.dart index 2571582..f5359fa 100644 --- a/test/widget_elevated_card_test.dart +++ b/test/widget_elevated_card_test.dart @@ -2,18 +2,17 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:smoke_cess_app/widgets/elevated_card.dart'; - void main() { group('ElevatedCard', () { testWidgets('Renders the title and child', (WidgetTester tester) async { // Arrange const title = 'My Card Title'; const childText = 'My Card Content'; - final child = Text(childText); - final card = ElevatedCard (title: title, child: child); + const child = Text(childText); + const card = ElevatedCard(title: title, child: child); // Act - await tester.pumpWidget(MaterialApp(home: Scaffold(body: card))); + await tester.pumpWidget(const MaterialApp(home: Scaffold(body: card))); final titleFinder = find.text(title); final childFinder = find.text(childText); @@ -63,8 +62,10 @@ void main() { final cardWidget = tester.widget(cardFinder); // Assert - expect(cardWidget.shape, - const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0)))); + expect( + cardWidget.shape, + const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)))); }); }); } diff --git a/test/widget_missing_config_popup_test.dart b/test/widget_missing_config_popup_test.dart deleted file mode 100644 index a4c3f3d..0000000 --- a/test/widget_missing_config_popup_test.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:smoke_cess_app/widgets/missing_config_popup.dart'; - -void main() { - testWidgets('MissingConfigPopup displays title and text', (WidgetTester tester) async { - final String title = 'Missing Configuration'; - final String text = 'Please configure the app before using it.'; - - await tester.pumpWidget(MaterialApp( - home: MissingConfigPopup(title: title, text: text), - )); - - expect(find.text(title), findsOneWidget); - expect(find.text(text), findsOneWidget); - }); -} diff --git a/test/widget_timer_button_test.dart b/test/widget_timer_button_test.dart deleted file mode 100644 index 6491896..0000000 --- a/test/widget_timer_button_test.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:smoke_cess_app/widgets/timer_button.dart'; - -void main() { - testWidgets('TimerButton should display icon & color and react to click', (WidgetTester tester) async { - // Define the icon and color - final Icon icon = Icon(Icons.play_arrow); - final Color color = Colors.green; - - // Build the TimerButton - var clicked = false; - await tester.pumpWidget( - MaterialApp( - home: TimerButton( - onClicked: () => clicked = true, - icon: icon, - color: color, - ), - ), - ); - - // Verify that the icon and color are displayed - expect(find.byWidgetPredicate((widget) => widget is CircleAvatar && widget.child == icon ), findsOneWidget); - - expect(find.byWidgetPredicate((widget) => widget is CircleAvatar && widget.backgroundColor == color ), findsOneWidget); - - // Tap the button - await tester.tap(find.byType(InkWell)); - await tester.pump(); - - // Verify that the onClicked callback was called - expect(clicked, true); - }); -} diff --git a/test/widget_todo_icon_test.dart b/test/widget_todo_icon_test.dart index faefdbd..077308f 100644 --- a/test/widget_todo_icon_test.dart +++ b/test/widget_todo_icon_test.dart @@ -2,16 +2,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:smoke_cess_app/widgets/todo_icon.dart'; - - void main() { testWidgets('MyToDoIcon has a red dot', (WidgetTester tester) async { // Build the widget tree await tester.pumpWidget( - MaterialApp( + const MaterialApp( home: Scaffold( - - body: MyToDoIcon ( + body: MyToDoIcon( Icon(Icons.check), ), ), @@ -20,7 +17,5 @@ void main() { // Verify that the red dot is present expect(find.byIcon(Icons.brightness_1), findsOneWidget); - // paints => verifys that a widget paints a certain shape or color v^1.15.30 - expect(find.byIcon(Icons.brightness_1).first, paints..circle(color: Colors.redAccent)); }); } From fb287fdb23200a5e744f743f60624ddf3609ef98 Mon Sep 17 00:00:00 2001 From: "k.mannweiler" <2012491@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 19:12:31 +0100 Subject: [PATCH 07/27] Ordner Struktur --- test/{ => provider}/input_provider_test.dart | 0 test/{ => provider}/timer_provider_test.dart | 0 test/widget_test.dart | 30 ------------------- test/{ => widgets}/widget_drop_down_test.dart | 9 +++--- .../widget_elevated_card_test.dart | 2 +- test/{ => widgets}/widget_todo_icon_test.dart | 0 6 files changed, 6 insertions(+), 35 deletions(-) rename test/{ => provider}/input_provider_test.dart (100%) rename test/{ => provider}/timer_provider_test.dart (100%) delete mode 100644 test/widget_test.dart rename test/{ => widgets}/widget_drop_down_test.dart (87%) rename test/{ => widgets}/widget_elevated_card_test.dart (97%) rename test/{ => widgets}/widget_todo_icon_test.dart (100%) diff --git a/test/input_provider_test.dart b/test/provider/input_provider_test.dart similarity index 100% rename from test/input_provider_test.dart rename to test/provider/input_provider_test.dart diff --git a/test/timer_provider_test.dart b/test/provider/timer_provider_test.dart similarity index 100% rename from test/timer_provider_test.dart rename to test/provider/timer_provider_test.dart diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index ecf9aaf..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:smoke_cess_app/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/test/widget_drop_down_test.dart b/test/widgets/widget_drop_down_test.dart similarity index 87% rename from test/widget_drop_down_test.dart rename to test/widgets/widget_drop_down_test.dart index 999f125..a7f5f9f 100644 --- a/test/widget_drop_down_test.dart +++ b/test/widgets/widget_drop_down_test.dart @@ -5,7 +5,8 @@ import 'package:smoke_cess_app/providers/input_provider.dart'; import 'package:smoke_cess_app/widgets/drop_down.dart'; void main() { - testWidgets('DropDown should display items and update input model', (WidgetTester tester) async { + testWidgets('DropDown should display items and update input model', + (WidgetTester tester) async { // Define the list of items final items = ['Item 1', 'Item 2', 'Item 3']; @@ -28,16 +29,16 @@ void main() { expect(find.text(items[0]), findsOneWidget); // Tap the DropDown to open the menu - await tester.tap(find.byType(DropdownButtonFormField)); + await tester.tap(find.byType(DropDown)); await tester.pump(); // Verify that the menu displays the correct items for (final item in items) { - expect(find.text(item), findsOneWidget); + expect(find.text(item).first, findsOneWidget); } // Select the second item - await tester.tap(find.text(items[1])); + await tester.tap(find.text(items[1]).last); await tester.pump(); // Verify that the input model was updated with the selected item diff --git a/test/widget_elevated_card_test.dart b/test/widgets/widget_elevated_card_test.dart similarity index 97% rename from test/widget_elevated_card_test.dart rename to test/widgets/widget_elevated_card_test.dart index f5359fa..51e6242 100644 --- a/test/widget_elevated_card_test.dart +++ b/test/widgets/widget_elevated_card_test.dart @@ -48,7 +48,7 @@ void main() { final titleWidget = tester.widget(titleFinder); // Assert - expect(titleWidget.style?.fontSize, equals(20.0)); + expect(titleWidget.style?.fontSize, equals(16.0)); expect(titleWidget.style?.fontWeight, equals(FontWeight.bold)); }); diff --git a/test/widget_todo_icon_test.dart b/test/widgets/widget_todo_icon_test.dart similarity index 100% rename from test/widget_todo_icon_test.dart rename to test/widgets/widget_todo_icon_test.dart From bf749fdeb53f229f730c154a622286406fb9d910 Mon Sep 17 00:00:00 2001 From: "k.mannweiler" <2012491@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 19:13:39 +0100 Subject: [PATCH 08/27] Ordnerstruktur --- test/{provider => unit_tests}/input_provider_test.dart | 0 test/{provider => unit_tests}/timer_provider_test.dart | 0 test/{widgets => widget_tests}/widget_drop_down_test.dart | 0 test/{widgets => widget_tests}/widget_elevated_card_test.dart | 0 test/{widgets => widget_tests}/widget_todo_icon_test.dart | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename test/{provider => unit_tests}/input_provider_test.dart (100%) rename test/{provider => unit_tests}/timer_provider_test.dart (100%) rename test/{widgets => widget_tests}/widget_drop_down_test.dart (100%) rename test/{widgets => widget_tests}/widget_elevated_card_test.dart (100%) rename test/{widgets => widget_tests}/widget_todo_icon_test.dart (100%) diff --git a/test/provider/input_provider_test.dart b/test/unit_tests/input_provider_test.dart similarity index 100% rename from test/provider/input_provider_test.dart rename to test/unit_tests/input_provider_test.dart diff --git a/test/provider/timer_provider_test.dart b/test/unit_tests/timer_provider_test.dart similarity index 100% rename from test/provider/timer_provider_test.dart rename to test/unit_tests/timer_provider_test.dart diff --git a/test/widgets/widget_drop_down_test.dart b/test/widget_tests/widget_drop_down_test.dart similarity index 100% rename from test/widgets/widget_drop_down_test.dart rename to test/widget_tests/widget_drop_down_test.dart diff --git a/test/widgets/widget_elevated_card_test.dart b/test/widget_tests/widget_elevated_card_test.dart similarity index 100% rename from test/widgets/widget_elevated_card_test.dart rename to test/widget_tests/widget_elevated_card_test.dart diff --git a/test/widgets/widget_todo_icon_test.dart b/test/widget_tests/widget_todo_icon_test.dart similarity index 100% rename from test/widgets/widget_todo_icon_test.dart rename to test/widget_tests/widget_todo_icon_test.dart From bb833f4bfe8d38c2d0a88a4fea5494449667ae04 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 19:30:37 +0100 Subject: [PATCH 09/27] test EntryDetailTitle --- .../widget_entry_detail_test.dart | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 test/widget_tests/widget_entry_detail_test.dart diff --git a/test/widget_tests/widget_entry_detail_test.dart b/test/widget_tests/widget_entry_detail_test.dart new file mode 100644 index 0000000..a741ab5 --- /dev/null +++ b/test/widget_tests/widget_entry_detail_test.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:intl/intl.dart'; +import 'package:intl/date_symbol_data_local.dart'; + +import 'package:smoke_cess_app/widgets/entry_detail_title.dart'; + +void main() { + group('EntryDetailTitle', () { + DateTime date = DateTime.now(); + String entryData = "TestEntryData"; + initializeDateFormatting('de'); + + testWidgets('EntryDetailTitle has formatted date and entrydata', + (widgetTester) async { + await widgetTester.pumpWidget(MaterialApp( + home: EntryDetailTitle(date: date, entryData: entryData))); + final formattedDateFinder = find.text(DateFormat.MMMd('de').format(date)); + final entryDataFinder = find.text(entryData); + expect(formattedDateFinder, findsOneWidget); + expect(entryDataFinder, findsOneWidget); + }); + }); +} From a9480cc5080279811c6dc0f5a4bd6f7f33506406 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 19:31:37 +0100 Subject: [PATCH 10/27] add tests to pipeline --- .gitlab-ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4bb6e7e..52497a7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,6 +2,7 @@ image: cirrusci/flutter:3.7.5 stages: - analyze + - test before_script: - flutter pub get @@ -13,3 +14,10 @@ analyze: - flutter analyze only: - merge_requests + +test: + stage: test + script: + - flutter test + only: + - merge_requests From d6a45e8974bd8d96d271850de6252ef204524272 Mon Sep 17 00:00:00 2001 From: "h.ehrenfried" <2012537@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 20:38:53 +0100 Subject: [PATCH 11/27] create workout & settings Provider and date service tests --- test/unit_tests/date_service_test.dart | 118 ++++++++++++++++++++ test/unit_tests/settings_provider_test.dart | 28 +++++ test/unit_tests/workout_provider_test.dart | 75 +++++++++++++ 3 files changed, 221 insertions(+) create mode 100644 test/unit_tests/date_service_test.dart create mode 100644 test/unit_tests/settings_provider_test.dart create mode 100644 test/unit_tests/workout_provider_test.dart diff --git a/test/unit_tests/date_service_test.dart b/test/unit_tests/date_service_test.dart new file mode 100644 index 0000000..13bf03b --- /dev/null +++ b/test/unit_tests/date_service_test.dart @@ -0,0 +1,118 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:smoke_cess_app/services/date_service.dart'; +import 'package:smoke_cess_app/services/pages_service.dart'; +import 'package:timezone/data/latest.dart' as tz; +import 'package:timezone/timezone.dart'; + +void main() { + group('Helpers', () { + group('isSameDay', () { + test('returns true when dates are the same day', () { + DateTime dateA = DateTime.now(); + DateTime dateB = DateTime(dateA.year, dateA.month, dateA.day, 10, 0); + expect(isSameDay(dateA, dateB), true); + }); + + test('returns false when dates are different days', () { + DateTime dateA = DateTime.now(); + DateTime dateB = DateTime(dateA.year, dateA.month, dateA.day + 1, 10, 0); + expect(isSameDay(dateA, dateB), false); + }); + + test('returns false when one date is null', () { + DateTime? dateA = DateTime.now(); + DateTime? dateB; + expect(isSameDay(dateA, dateB), false); + }); + }); + + group('createTZDateTimes', () { + test('returns empty list when selectedDays is null', () { + List tzDateTimes = + createTZDateTimes(null, 10, 0); + expect(tzDateTimes, []); + }); + + test('returns empty list when selectedHours is null', () { + List tzDateTimes = + createTZDateTimes(['Montag'], null, 0); + expect(tzDateTimes, []); + }); + + test('returns empty list when selectedMinutes is null', () { + List tzDateTimes = + createTZDateTimes(['Montag'], 10, null); + expect(tzDateTimes, []); + }); + + test('returns empty list when no valid dates are found', () { + List tzDateTimes = + createTZDateTimes(['Montag'], 10, 0); + expect(tzDateTimes, []); + }); + + test('returns list of valid dates', () { + List tzDateTimes = + createTZDateTimes(['Montag'], 10, 0); + expect(tzDateTimes.length, greaterThan(0)); + }); + }); + + group('getTimeTill', () { + test('returns time till next mood', () async { + Duration duration = await getTimeTill(Pages.mood); + expect(duration, isNotNull); + }); + + test('returns time till next sleep', () async { + Duration duration = await getTimeTill(Pages.sleep); + expect(duration, isNotNull); + }); + //? + test('returns time till next workout', () async { + Duration duration = await getTimeTill(Pages.relapse); + expect(duration, isNotNull); + }); + //? + test('returns time till next workout', () async { + Duration duration = await getTimeTill(Pages.settings); + expect(duration, isNotNull); + }); + test('returns time till next workout', () async { + Duration duration = await getTimeTill(Pages.timer); + expect(duration, isNotNull); + }); + }); + }); + + group('Helper functions', () { + setUp(() async { + tz.initializeTimeZones(); + }); + + test('isSameDay returns true if two dates are the same day', () { + final date1 = DateTime(2022, 3, 6); + final date2 = DateTime(2022, 3, 6, 15, 30); + final result = isSameDay(date1, date2); + expect(result, true); + }); + + test('isSameDay returns false if two dates are not the same day', () { + final date1 = DateTime(2022, 3, 6); + final date2 = DateTime(2022, 3, 7); + final result = isSameDay(date1, date2); + expect(result, false); + }); + + test('createTZDateTimes returns a list of TZDateTime objects', () async { + final selectedDays = ['Montag', 'Dienstag']; + final selectedHours = 12; + final selectedMinutes = 30; + final result = await createTZDateTimes( + selectedDays, selectedHours, selectedMinutes); + expect(result, isA>()); + }); + }); + + +} diff --git a/test/unit_tests/settings_provider_test.dart b/test/unit_tests/settings_provider_test.dart new file mode 100644 index 0000000..4d43184 --- /dev/null +++ b/test/unit_tests/settings_provider_test.dart @@ -0,0 +1,28 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:smoke_cess_app/providers/settings_provider.dart'; + +void main() { + group('SettingsProvider', () { + test('initial state', () { + final provider = SettingsProvider(); + expect(provider.settings, isNull); + expect(provider.initialized, isFalse); + expect(provider.scanning, isFalse); + }); + + test('initialize settings', () async { + final provider = SettingsProvider(); + provider.initSettings(); + expect(provider.settings, isNotNull); + expect(provider.initialized, isTrue); + }); + + test('set scanning', () { + final provider = SettingsProvider(); + provider.scanning = true; + expect(provider.scanning, isTrue); + provider.scanning = false; + expect(provider.scanning, isFalse); + }); + }); +} diff --git a/test/unit_tests/workout_provider_test.dart b/test/unit_tests/workout_provider_test.dart new file mode 100644 index 0000000..31d7784 --- /dev/null +++ b/test/unit_tests/workout_provider_test.dart @@ -0,0 +1,75 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter/material.dart'; +import 'package:smoke_cess_app/providers/audio_provider.dart'; +import 'package:smoke_cess_app/providers/timer_provider.dart'; +import 'package:smoke_cess_app/providers/workout_provider.dart'; + +void main() { + group('WorkoutProvider', () { + late WorkoutProvider workoutProvider; + late TimerProvider timerProvider; + late AudioProvider audioProvider; + + setUp(() { + timerProvider = TimerProvider(); + audioProvider = AudioProvider(); + workoutProvider = WorkoutProvider(timerProvider, audioProvider); + }); + + test('initial values', () { + expect(workoutProvider.isWorkoutStarted, false); + expect(workoutProvider.isWorkoutComplete, false); + expect(workoutProvider.motivationBefore, 50); + expect(workoutProvider.motivationAfter, 50); + expect(workoutProvider.currentPhase, WorkoutPhases.warmUp); + expect(workoutProvider.currentPhaseDuration, const Duration(seconds: 5)); + expect(workoutProvider.isPhaseComplete, false); + expect(workoutProvider.currentPhaseColor, Colors.green); + expect(workoutProvider.currentPhaseTitle, 'Warm Up'); + }); + + test('next phase', () { + workoutProvider.nextPhase(); + + expect(workoutProvider.currentPhase, WorkoutPhases.highIntensity); + expect(workoutProvider.currentPhaseDuration, const Duration(seconds: 4)); + expect(workoutProvider.isPhaseComplete, false); + expect(workoutProvider.currentPhaseColor, Colors.red); + expect(workoutProvider.currentPhaseTitle, 'High Intensity'); + }); + + test('start workout', () { + workoutProvider.startWorkout(); + + expect(workoutProvider.isWorkoutStarted, true); + expect(workoutProvider.isWorkoutComplete, false); + expect(workoutProvider.currentPhase, WorkoutPhases.warmUp); + expect(workoutProvider.currentPhaseDuration, const Duration(seconds: 5)); + expect(workoutProvider.isPhaseComplete, false); + }); + + test('stop workout', () { + workoutProvider.startWorkout(); + workoutProvider.stopWorkout(); + + expect(workoutProvider.isWorkoutStarted, false); + expect(workoutProvider.isWorkoutComplete, true); + }); + + test('interrupt workout', () { + workoutProvider.startWorkout(); + workoutProvider.interruptWorkout(); + + expect(workoutProvider.isWorkoutStarted, false); + expect(workoutProvider.isWorkoutComplete, false); + }); + + // test('save workout', () { + // workoutProvider.motivationBefore = 70; + // workoutProvider.motivationAfter = 80; + // workoutProvider.saveWorkout(); + + // // -> hier in datenbank nachschauen obs geklappt hat + // }); + }); +} From 6c0708ca77eb96d735fbcc7f7f59454b32ec5c45 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 20:52:35 +0100 Subject: [PATCH 12/27] historylist test --- test/widget_tests/history_list_test.dart | 102 +++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 test/widget_tests/history_list_test.dart diff --git a/test/widget_tests/history_list_test.dart b/test/widget_tests/history_list_test.dart new file mode 100644 index 0000000..3ed6809 --- /dev/null +++ b/test/widget_tests/history_list_test.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:intl/date_symbol_data_local.dart'; +import 'package:intl/intl.dart'; +import 'package:smoke_cess_app/widgets/entry_detail_widget.dart'; +import 'package:smoke_cess_app/widgets/history_list_widget.dart'; + +void main() { + group('HistoryList', () { + initializeDateFormatting('de'); + final List history = ['1', '2', '3']; + dateSelector(String p0) => DateTime.now(); + entryDataSelector(String p0) => p0; + + testWidgets('should produce #(history.length) EntryDetail Widgets', + (widgetTester) async { + await widgetTester.pumpWidget(WrappedHistoryList( + history: history, + dateSelector: dateSelector, + entryDataSelector: entryDataSelector)); + final widgetFinder = find.byType(EntryDetail); + final dateFinder = + find.text(DateFormat.MMMd('de').format(DateTime.now())); + //HistoryList uses Icons.circle as default if there is no IconData provided + final iconFinder = find.byIcon(Icons.circle); + expect(widgetFinder, findsNWidgets(history.length)); + expect(dateFinder, findsNWidgets(history.length)); + expect(iconFinder, findsNWidgets(history.length)); + }); + + testWidgets( + 'should render correct icon if specified with icon selection function', + (widgetTester) async { + IconData iconDataSelector(String p0) => Icons.email; + + await widgetTester.pumpWidget(WrappedHistoryList( + history: history, + dateSelector: dateSelector, + entryDataSelector: entryDataSelector, + iconDataSelector: iconDataSelector, + )); + final circleIconFinder = find.byIcon(Icons.circle); + final correctIconFinder = find.byIcon(Icons.email); + + expect(circleIconFinder, findsNothing); + expect(correctIconFinder, findsNWidgets(history.length)); + }); + + testWidgets('icon field should overwrite iconSelector', + (widgetTester) async { + const IconData icon = Icons.abc; + IconData iconDataSelector(String p0) => Icons.email; + await widgetTester.pumpWidget(WrappedHistoryList( + history: history, + dateSelector: dateSelector, + entryDataSelector: entryDataSelector, + iconDataSelector: iconDataSelector, + icon: Icons.abc, + )); + final circleIconFinder = find.byIcon(Icons.circle); + final emailIconFinder = find.byIcon(Icons.email); + final correctIconFinder = find.byIcon(icon); + + expect(circleIconFinder, findsNothing); + expect(emailIconFinder, findsNothing); + expect(correctIconFinder, findsNWidgets(history.length)); + }); + }); +} + +class WrappedHistoryList extends StatelessWidget { + final List history; + final DateTime Function(T) dateSelector; + final String Function(T) entryDataSelector; + final IconData Function(T)? iconDataSelector; + final String Function(T)? entryCommentSelector; + final IconData? icon; + const WrappedHistoryList( + {super.key, + required this.history, + required this.dateSelector, + required this.entryDataSelector, + this.iconDataSelector, + this.icon, + this.entryCommentSelector}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + body: Column(children: [ + HistoryList( + history: history, + dateSelector: dateSelector, + entryDataSelector: entryDataSelector, + icon: icon, + iconDataSelector: iconDataSelector, + entryCommentSelector: entryCommentSelector, + ) + ]))); + } +} From 57d3b22c1be2275ac8bd697e129ae7befa8b528c Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 21:00:05 +0100 Subject: [PATCH 13/27] completed history list test --- test/widget_tests/history_list_test.dart | 28 ++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/widget_tests/history_list_test.dart b/test/widget_tests/history_list_test.dart index 3ed6809..7354473 100644 --- a/test/widget_tests/history_list_test.dart +++ b/test/widget_tests/history_list_test.dart @@ -65,6 +65,34 @@ void main() { expect(emailIconFinder, findsNothing); expect(correctIconFinder, findsNWidgets(history.length)); }); + + testWidgets( + 'EntryDetails should display ExpansionTiles if entryComment is given', + (widgetTester) async { + String entryCommentSelector(String p0) => ""; + await widgetTester.pumpWidget(WrappedHistoryList( + history: history, + dateSelector: dateSelector, + entryDataSelector: entryDataSelector, + entryCommentSelector: entryCommentSelector, + )); + final expansionTileFinder = find.byType(ExpansionTile); + expect(expansionTileFinder, findsNWidgets(history.length)); + }); + + testWidgets( + 'EntryDetails should display ExpansionTiles if entryComment is not given', + (widgetTester) async { + String entryCommentSelector(String p0) => ""; + await widgetTester.pumpWidget(WrappedHistoryList( + history: history, + dateSelector: dateSelector, + entryDataSelector: entryDataSelector, + entryCommentSelector: entryCommentSelector, + )); + final listTileFinder = find.byType(ListTile); + expect(listTileFinder, findsNWidgets(history.length)); + }); }); } From 557c9b70f0234b967ea875b77e93ca362cc33e92 Mon Sep 17 00:00:00 2001 From: "k.mannweiler" <2012491@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 21:04:35 +0100 Subject: [PATCH 14/27] Adding tests --- lib/providers/input_provider.dart | 4 +- lib/services/date_service.dart | 2 +- lib/utils/timer_util.dart | 5 +- test/unit_tests/date_service_test.dart | 37 ++++++ test/unit_tests/timer_util_test.dart | 49 ++++++++ .../widget_entry_detail_test.dart | 41 ++++++ test/widget_tests/widget_slider_test.dart | 117 ++++++++++++++++++ .../widget_text_formfield_test.dart | 51 ++++++++ 8 files changed, 303 insertions(+), 3 deletions(-) create mode 100644 test/unit_tests/date_service_test.dart create mode 100644 test/unit_tests/timer_util_test.dart create mode 100644 test/widget_tests/widget_entry_detail_test.dart create mode 100644 test/widget_tests/widget_slider_test.dart create mode 100644 test/widget_tests/widget_text_formfield_test.dart diff --git a/lib/providers/input_provider.dart b/lib/providers/input_provider.dart index b8aed63..01ab835 100644 --- a/lib/providers/input_provider.dart +++ b/lib/providers/input_provider.dart @@ -22,7 +22,9 @@ class InputProvider extends ChangeNotifier { TextEditingController get textController => _textController; set sliderValue(double newValue) { - _sliderValue = newValue; + if (_sliderValue > 0 && _sliderValue < 100) { + _sliderValue = newValue; + } notifyListeners(); } diff --git a/lib/services/date_service.dart b/lib/services/date_service.dart index 79bdd37..e4a9617 100644 --- a/lib/services/date_service.dart +++ b/lib/services/date_service.dart @@ -3,7 +3,7 @@ import 'package:timezone/timezone.dart'; import 'pages_service.dart'; -const int trainingTime = 40; +const int trainingTime = 6 * 7; const weekDays = { "Montag": 1, diff --git a/lib/utils/timer_util.dart b/lib/utils/timer_util.dart index 57b9f9c..9fba645 100644 --- a/lib/utils/timer_util.dart +++ b/lib/utils/timer_util.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; String formatTime(int seconds) { + if (seconds < 0) { + return '00:00'; + } Duration duration = Duration(seconds: seconds); String formattedTime = ''; String twoDigits(int n) => n.toString().padLeft(2, "0"); @@ -9,7 +12,7 @@ String formatTime(int seconds) { String minutes = twoDigits(duration.inMinutes.remainder(60)); String formattedSeconds = twoDigits(duration.inSeconds.remainder(60)); if (duration.inDays != 0) { - formattedTime += '$days Tag ${duration.inDays > 1 ? "e" : ""}, '; + formattedTime += '$days Tag${duration.inDays > 1 ? "e" : ""}, '; } if (duration.inHours != 0) formattedTime += '$hours:'; formattedTime += '$minutes:'; diff --git a/test/unit_tests/date_service_test.dart b/test/unit_tests/date_service_test.dart new file mode 100644 index 0000000..9afba5e --- /dev/null +++ b/test/unit_tests/date_service_test.dart @@ -0,0 +1,37 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:timezone/data/latest.dart' as tz; +import 'package:smoke_cess_app/services/date_service.dart'; +import 'package:timezone/timezone.dart'; + +void main() { + tz.initializeTimeZones(); + test('IsSameDay: false', () { + bool result = + isSameDay(DateTime.now(), DateTime.now().add(const Duration(days: 1))); + expect(result, false); + }); + test('IsSameDay: true', () { + bool result = isSameDay(DateTime.now(), DateTime.now()); + expect(result, true); + }); + test('CreateTZDateTimes: all the same days as today in next 6 weeks at 23:59', + () { + List selectedDays = [ + weekDays.keys.elementAt(DateTime.now().weekday - 1) + ]; + List expected = []; + DateTime now = DateTime.now(); + final Duration offset = now.timeZoneOffset; + final DateTime date = + DateTime(now.year, now.month, now.day, 23, 59, 0, 0, 0); + for (int i = 0; i <= trainingTime; i = i + 7) { + expected.add( + TZDateTime.local(date.year, date.month, date.day, 23, 59, 0, 0, 0) + .add(Duration(days: i)) + // subtract offset since TZDateTime uses the UTC Timezone + .subtract(offset)); + } + List result = createTZDateTimes(selectedDays, 23, 59); + expect(result, expected); + }); +} diff --git a/test/unit_tests/timer_util_test.dart b/test/unit_tests/timer_util_test.dart new file mode 100644 index 0000000..50fe28f --- /dev/null +++ b/test/unit_tests/timer_util_test.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:smoke_cess_app/utils/timer_util.dart'; + +void main() { + test('FormatTime: Seconds', () { + String result = formatTime(1); + expect(result, '00:01'); + }); + test('FormatTime: Minutes', () { + String result = formatTime(61); + expect(result, '01:01'); + }); + test('FormatTime: Hours', () { + String result = formatTime(3661); + expect(result, '01:01:01'); + }); + test('FormatTime: Day', () { + String result = formatTime(90061); + expect(result, '1 Tag, 01:01:01'); + }); + test('FormatTime: Days', () { + String result = formatTime(176461); + expect(result, '2 Tage, 01:01:01'); + }); + test('FormatTime: Negativ Value', () { + String result = formatTime(-1); + expect(result, '00:00'); + }); + + test('DurationBetween: 0', () { + TimeOfDay start = const TimeOfDay(hour: 12, minute: 0); + TimeOfDay end = const TimeOfDay(hour: 12, minute: 0); + TimeOfDay result = start.durationBetween(end); + expect(result, const TimeOfDay(hour: 0, minute: 0)); + }); + test('DurationBetween: 23h 59min', () { + TimeOfDay start = const TimeOfDay(hour: 0, minute: 0); + TimeOfDay end = const TimeOfDay(hour: 23, minute: 59); + TimeOfDay result = start.durationBetween(end); + expect(result, const TimeOfDay(hour: 23, minute: 59)); + }); + test('DurationBetween: 12h 34min', () { + TimeOfDay start = const TimeOfDay(hour: 2, minute: 12); + TimeOfDay end = const TimeOfDay(hour: 14, minute: 46); + TimeOfDay result = start.durationBetween(end); + expect(result, const TimeOfDay(hour: 12, minute: 34)); + }); +} diff --git a/test/widget_tests/widget_entry_detail_test.dart b/test/widget_tests/widget_entry_detail_test.dart new file mode 100644 index 0000000..0eed669 --- /dev/null +++ b/test/widget_tests/widget_entry_detail_test.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:intl/date_symbol_data_local.dart'; +import 'package:smoke_cess_app/widgets/entry_detail_widget.dart'; + +void main() { + initializeDateFormatting('de'); + testWidgets('Entry Detail should use ExpansionTile if Comments is set', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: EntryDetail( + date: DateTime.now(), + entryComment: 'A comment', + entryData: 'Test', + iconData: Icons.plus_one, + ), + )), + ); + + expect(find.byType(ExpansionTile), findsOneWidget); + }); + + testWidgets('Entry Detail should use ListTile if Comments is null', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: EntryDetail( + date: DateTime.now(), + entryComment: 'A comment', + entryData: 'Test', + iconData: Icons.plus_one, + ), + )), + ); + + expect(find.byType(ListTile), findsOneWidget); + }); +} diff --git a/test/widget_tests/widget_slider_test.dart b/test/widget_tests/widget_slider_test.dart new file mode 100644 index 0000000..1dc470d --- /dev/null +++ b/test/widget_tests/widget_slider_test.dart @@ -0,0 +1,117 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/providers/input_provider.dart'; +import 'package:smoke_cess_app/widgets/slider.dart'; + +void main() { + testWidgets('Slider starts at 50', (WidgetTester tester) async { + // Create an instance of the InputProvider and add it to the widget tree + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MySlider(), + ), + ), + ), + ); + + // Verify that the Slider displays 50 + expect(find.text('50'), findsOneWidget); + }); + + testWidgets('Slider puts 51 after Tap on plus in InputProvider', + (WidgetTester tester) async { + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MySlider(), + ), + ), + ), + ); + + await tester.tap(find.byIcon(Icons.add_outlined)); + await tester.pump(); + + expect(inputProvider.sliderValue, equals(51)); + }); + + testWidgets('Slider puts 49 after Tap on subtract in InputProvider', + (WidgetTester tester) async { + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MySlider(), + ), + ), + ), + ); + + await tester.tap(find.byIcon(Icons.remove_outlined)); + await tester.pump(); + + expect(inputProvider.sliderValue, equals(49)); + }); + + testWidgets('Slider doesnt go higher than 100', (WidgetTester tester) async { + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MySlider(), + ), + ), + ), + ); + + for (int i = 0; i < 100; i++) { + await tester.tap(find.byIcon(Icons.add_outlined)); + await tester.pump(); + } + + expect(inputProvider.sliderValue, equals(100)); + }); + + testWidgets('Slider doesnt go lower than 0', (WidgetTester tester) async { + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MySlider(), + ), + ), + ), + ); + + for (int i = 0; i < 100; i++) { + await tester.tap(find.byIcon(Icons.remove_outlined)); + await tester.pump(); + } + + expect(inputProvider.sliderValue, equals(0)); + }); +} diff --git a/test/widget_tests/widget_text_formfield_test.dart b/test/widget_tests/widget_text_formfield_test.dart new file mode 100644 index 0000000..84aa134 --- /dev/null +++ b/test/widget_tests/widget_text_formfield_test.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/providers/input_provider.dart'; +import 'package:smoke_cess_app/widgets/text_formfield.dart'; + +void main() { + testWidgets('TextFormField initial Value is correct', + (WidgetTester tester) async { + const String testText = 'Its a test'; + // Create an instance of the InputProvider and add it to the widget tree + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MyTextFormField(testText), + ), + ), + ), + ); + + // Verify that the Slider displays 50 + expect(find.text(testText), findsOneWidget); + }); + + testWidgets('TextFormField inputs correctly to Provider', + (WidgetTester tester) async { + const String testText = 'Its a test'; + // Create an instance of the InputProvider and add it to the widget tree + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MyTextFormField(testText), + ), + ), + ), + ); + + await tester.enterText(find.byType(TextField), testText); + expect(inputProvider.textController.text, testText); + }); +} From 75b638b8435eb8317e65b21f837ab65500fa9056 Mon Sep 17 00:00:00 2001 From: "k.mannweiler" <2012491@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 21:51:02 +0100 Subject: [PATCH 15/27] SettingsMock --- lib/mock/settings_mock.dart | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 lib/mock/settings_mock.dart diff --git a/lib/mock/settings_mock.dart b/lib/mock/settings_mock.dart new file mode 100644 index 0000000..337251c --- /dev/null +++ b/lib/mock/settings_mock.dart @@ -0,0 +1,17 @@ +Map mockSettings = { + "group": 3, + "HITT_time": 35, + "chess_time": {"hours": 8, "minutes": 30}, + "relapse_categories": ["App stresst mich", "langeweile", "lunge braucht es"], + "mood_query": { + "days": ["Montag", "Donnerstag"], + "hours": 10, + "minutes": 30 + }, + "sleep_query": { + "days": ["Dienstag", "Samstag"], + "hours": 15, + "minutes": 42 + }, + "startedAt": DateTime.now().toIso8601String(), +}; From 8a7c6e49db7673ce5373c7836a87dcb826b6feaf Mon Sep 17 00:00:00 2001 From: "k.mannweiler" <2012491@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 21:54:32 +0100 Subject: [PATCH 16/27] Adding Tests --- lib/providers/settings_provider.dart | 2 +- test/unit_tests/date_service_test.dart | 51 +++++++++++++-------- test/unit_tests/settings_provider_test.dart | 10 +++- test/unit_tests/timer_provider_test.dart | 6 --- test/unit_tests/workout_provider_test.dart | 1 + 5 files changed, 42 insertions(+), 28 deletions(-) diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart index 121ff0d..49c92b8 100644 --- a/lib/providers/settings_provider.dart +++ b/lib/providers/settings_provider.dart @@ -21,7 +21,7 @@ class SettingsProvider extends ChangeNotifier { initSettings(); } - void initSettings() async { + Future initSettings() async { _settings = await loadSettings(); _initialized = _settings != null ? true : false; notifyListeners(); diff --git a/test/unit_tests/date_service_test.dart b/test/unit_tests/date_service_test.dart index 2791f7d..bdee660 100644 --- a/test/unit_tests/date_service_test.dart +++ b/test/unit_tests/date_service_test.dart @@ -1,10 +1,17 @@ +import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:smoke_cess_app/mock/settings_mock.dart'; import 'package:smoke_cess_app/services/date_service.dart'; import 'package:smoke_cess_app/services/pages_service.dart'; +import 'package:smoke_cess_app/services/settings_service.dart'; import 'package:timezone/data/latest.dart' as tz; import 'package:timezone/timezone.dart'; -void main() { +void main() async { + tz.initializeTimeZones(); + WidgetsFlutterBinding.ensureInitialized(); + SharedPreferences.setMockInitialValues(mockSettings); group('Helpers', () { group('isSameDay', () { test('returns true when dates are the same day', () { @@ -44,7 +51,7 @@ void main() { }); test('returns empty list when no valid dates are found', () { - List tzDateTimes = createTZDateTimes(['Montag'], 10, 0); + List tzDateTimes = createTZDateTimes(['Mong'], 10, 0); expect(tzDateTimes, []); }); @@ -52,6 +59,26 @@ void main() { List tzDateTimes = createTZDateTimes(['Montag'], 10, 0); expect(tzDateTimes.length, greaterThan(0)); }); + + test('returns all the same days as today in next 6 weeks at 23:59', () { + List selectedDays = [ + weekDays.keys.elementAt(DateTime.now().weekday - 1) + ]; + List expected = []; + DateTime now = DateTime.now(); + final Duration offset = now.timeZoneOffset; + final DateTime date = + DateTime(now.year, now.month, now.day, 23, 59, 0, 0, 0); + for (int i = 0; i <= trainingTime; i = i + 7) { + expected.add( + TZDateTime.local(date.year, date.month, date.day, 23, 59, 0, 0, 0) + .add(Duration(days: i)) + // subtract offset since TZDateTime uses the UTC Timezone + .subtract(offset)); + } + List result = createTZDateTimes(selectedDays, 23, 59); + expect(result, expected); + }); }); group('getTimeTill', () { @@ -64,16 +91,6 @@ void main() { Duration duration = await getTimeTill(Pages.sleep); expect(duration, isNotNull); }); - //? - test('returns time till next workout', () async { - Duration duration = await getTimeTill(Pages.relapse); - expect(duration, isNotNull); - }); - //? - test('returns time till next workout', () async { - Duration duration = await getTimeTill(Pages.settings); - expect(duration, isNotNull); - }); test('returns time till next workout', () async { Duration duration = await getTimeTill(Pages.timer); expect(duration, isNotNull); @@ -82,10 +99,6 @@ void main() { }); group('Helper functions', () { - setUp(() async { - tz.initializeTimeZones(); - }); - test('isSameDay returns true if two dates are the same day', () { final date1 = DateTime(2022, 3, 6); final date2 = DateTime(2022, 3, 6, 15, 30); @@ -102,10 +115,10 @@ void main() { test('createTZDateTimes returns a list of TZDateTime objects', () async { final selectedDays = ['Montag', 'Dienstag']; - final selectedHours = 12; - final selectedMinutes = 30; + const selectedHours = 12; + const selectedMinutes = 30; final result = - await createTZDateTimes(selectedDays, selectedHours, selectedMinutes); + createTZDateTimes(selectedDays, selectedHours, selectedMinutes); expect(result, isA>()); }); }); diff --git a/test/unit_tests/settings_provider_test.dart b/test/unit_tests/settings_provider_test.dart index 4d43184..e8b8321 100644 --- a/test/unit_tests/settings_provider_test.dart +++ b/test/unit_tests/settings_provider_test.dart @@ -1,7 +1,12 @@ +import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:smoke_cess_app/mock/settings_mock.dart'; import 'package:smoke_cess_app/providers/settings_provider.dart'; void main() { + WidgetsFlutterBinding.ensureInitialized(); + SharedPreferences.setMockInitialValues(mockSettings); group('SettingsProvider', () { test('initial state', () { final provider = SettingsProvider(); @@ -10,11 +15,12 @@ void main() { expect(provider.scanning, isFalse); }); - test('initialize settings', () async { + test('initialize mocksettings', () async { final provider = SettingsProvider(); - provider.initSettings(); + await provider.initSettings(); expect(provider.settings, isNotNull); expect(provider.initialized, isTrue); + expect(provider.settings?.group, 3); }); test('set scanning', () { diff --git a/test/unit_tests/timer_provider_test.dart b/test/unit_tests/timer_provider_test.dart index 7f6f1df..46ed9f5 100644 --- a/test/unit_tests/timer_provider_test.dart +++ b/test/unit_tests/timer_provider_test.dart @@ -31,10 +31,4 @@ void main() { final timerProvider = TimerProvider(); expect(timerProvider.elapsedSeconds, 0); }); - - test('Timer should stop and set started to false when duration is 0', () { - final timerProvider = TimerProvider(); - timerProvider.startTimer(const Duration(seconds: 0)); - expect(timerProvider.started, false); - }); } diff --git a/test/unit_tests/workout_provider_test.dart b/test/unit_tests/workout_provider_test.dart index 31d7784..7c9cb40 100644 --- a/test/unit_tests/workout_provider_test.dart +++ b/test/unit_tests/workout_provider_test.dart @@ -5,6 +5,7 @@ import 'package:smoke_cess_app/providers/timer_provider.dart'; import 'package:smoke_cess_app/providers/workout_provider.dart'; void main() { + WidgetsFlutterBinding.ensureInitialized(); group('WorkoutProvider', () { late WorkoutProvider workoutProvider; late TimerProvider timerProvider; From 716db5240fac0f2bf57a8f1bf290ffdccf86afea Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 21:55:18 +0100 Subject: [PATCH 17/27] settings mock and database mock in test folder --- lib/globals.dart | 4 +--- {lib => test}/mock/db_mock.dart | 0 {lib => test}/mock/settings_mock.dart | 5 +++++ 3 files changed, 6 insertions(+), 3 deletions(-) rename {lib => test}/mock/db_mock.dart (100%) rename {lib => test}/mock/settings_mock.dart (74%) diff --git a/lib/globals.dart b/lib/globals.dart index 3cdf823..43ebe5e 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -1,10 +1,8 @@ library app.globals; -import 'package:smoke_cess_app/mock/db_mock.dart'; import 'package:smoke_cess_app/services/database_service.dart'; -DatabaseService databaseService = DatabaseMock(); -// DatabaseService databaseService = DatabaseService.instance; +DatabaseService databaseService = DatabaseService.instance; // set this to read settings from local json file instead of scanning a qr code bool useLocalConfig = false; diff --git a/lib/mock/db_mock.dart b/test/mock/db_mock.dart similarity index 100% rename from lib/mock/db_mock.dart rename to test/mock/db_mock.dart diff --git a/lib/mock/settings_mock.dart b/test/mock/settings_mock.dart similarity index 74% rename from lib/mock/settings_mock.dart rename to test/mock/settings_mock.dart index 337251c..1f0be5d 100644 --- a/lib/mock/settings_mock.dart +++ b/test/mock/settings_mock.dart @@ -1,3 +1,5 @@ +import 'package:shared_preferences/shared_preferences.dart'; + Map mockSettings = { "group": 3, "HITT_time": 35, @@ -15,3 +17,6 @@ Map mockSettings = { }, "startedAt": DateTime.now().toIso8601String(), }; + +void mockSharedPreferences() => + SharedPreferences.setMockInitialValues(mockSettings); From e443343c9ff6bb26af3f8acf22ff8d0ed73089db Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 22:10:09 +0100 Subject: [PATCH 18/27] test open scanner --- test/widget_tests/scanner_test.dart | 42 +++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 test/widget_tests/scanner_test.dart diff --git a/test/widget_tests/scanner_test.dart b/test/widget_tests/scanner_test.dart new file mode 100644 index 0000000..7a9a5f0 --- /dev/null +++ b/test/widget_tests/scanner_test.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mobile_scanner/mobile_scanner.dart'; +import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:smoke_cess_app/providers/settings_provider.dart'; +import 'package:smoke_cess_app/widgets/buttons/text_icon_button.dart'; +import 'package:smoke_cess_app/widgets/scanner.dart'; + +import '../mock/settings_mock.dart'; + +void main() { + mockSharedPreferences(); + + group('MyScanner', () { + testWidgets('Scanner should start after Button is pressed', + (widgetTester) async { + SettingsProvider settingsProvider = SettingsProvider(); + expect(settingsProvider.scanning, false); + + await widgetTester.pumpWidget(MaterialApp( + home: Column( + children: [ + ChangeNotifierProvider( + create: (context) => settingsProvider, child: const MyScanner()) + ], + ), + )); + + final startScannerButton = find.byType(TextIconButton); + final scanner = find.byType(MobileScanner); + expect(startScannerButton, findsOneWidget); + expect(scanner, findsNothing); + + await widgetTester.tap(startScannerButton); + await widgetTester.pump(); + expect(startScannerButton, findsNothing); + expect(scanner, findsOneWidget); + expect(settingsProvider.scanning, true); + }); + }); +} From 6b6d2c1fcd9e98d5029093103a489d876d8281e2 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 22:12:13 +0100 Subject: [PATCH 19/27] remove unused import --- test/widget_tests/scanner_test.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/test/widget_tests/scanner_test.dart b/test/widget_tests/scanner_test.dart index 7a9a5f0..3260472 100644 --- a/test/widget_tests/scanner_test.dart +++ b/test/widget_tests/scanner_test.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:provider/provider.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:smoke_cess_app/providers/settings_provider.dart'; import 'package:smoke_cess_app/widgets/buttons/text_icon_button.dart'; import 'package:smoke_cess_app/widgets/scanner.dart'; From 05f293d1b4e845cb0dfe7424b1076793e5f843f9 Mon Sep 17 00:00:00 2001 From: "k.mannweiler" <2012491@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 22:15:29 +0100 Subject: [PATCH 20/27] Added Tests --- test/unit_tests/date_service_test.dart | 3 +-- test/unit_tests/input_provider_test.dart | 5 +++++ test/unit_tests/settings_provider_test.dart | 2 +- test/unit_tests/workout_provider_test.dart | 17 +++++++++++------ 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/test/unit_tests/date_service_test.dart b/test/unit_tests/date_service_test.dart index bdee660..afb3ee5 100644 --- a/test/unit_tests/date_service_test.dart +++ b/test/unit_tests/date_service_test.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:smoke_cess_app/mock/settings_mock.dart'; import 'package:smoke_cess_app/services/date_service.dart'; import 'package:smoke_cess_app/services/pages_service.dart'; -import 'package:smoke_cess_app/services/settings_service.dart'; import 'package:timezone/data/latest.dart' as tz; import 'package:timezone/timezone.dart'; +import '../mock/settings_mock.dart'; void main() async { tz.initializeTimeZones(); diff --git a/test/unit_tests/input_provider_test.dart b/test/unit_tests/input_provider_test.dart index 088b68b..36fcd3e 100644 --- a/test/unit_tests/input_provider_test.dart +++ b/test/unit_tests/input_provider_test.dart @@ -1,8 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:smoke_cess_app/providers/input_provider.dart'; +import 'package:smoke_cess_app/globals.dart' as globals; + +import '../mock/db_mock.dart'; void main() { + WidgetsFlutterBinding.ensureInitialized(); + globals.databaseService = DatabaseMock(); group('InputProvider', () { test('Initial values are correct', () { late final inputProvider = InputProvider(); diff --git a/test/unit_tests/settings_provider_test.dart b/test/unit_tests/settings_provider_test.dart index e8b8321..61e0c65 100644 --- a/test/unit_tests/settings_provider_test.dart +++ b/test/unit_tests/settings_provider_test.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:smoke_cess_app/mock/settings_mock.dart'; import 'package:smoke_cess_app/providers/settings_provider.dart'; +import '../mock/settings_mock.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); diff --git a/test/unit_tests/workout_provider_test.dart b/test/unit_tests/workout_provider_test.dart index 7c9cb40..45c7685 100644 --- a/test/unit_tests/workout_provider_test.dart +++ b/test/unit_tests/workout_provider_test.dart @@ -3,9 +3,12 @@ import 'package:flutter/material.dart'; import 'package:smoke_cess_app/providers/audio_provider.dart'; import 'package:smoke_cess_app/providers/timer_provider.dart'; import 'package:smoke_cess_app/providers/workout_provider.dart'; +import 'package:smoke_cess_app/globals.dart' as globals; +import '../mock/db_mock.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); + globals.databaseService = DatabaseMock(); group('WorkoutProvider', () { late WorkoutProvider workoutProvider; late TimerProvider timerProvider; @@ -65,12 +68,14 @@ void main() { expect(workoutProvider.isWorkoutComplete, false); }); - // test('save workout', () { - // workoutProvider.motivationBefore = 70; - // workoutProvider.motivationAfter = 80; - // workoutProvider.saveWorkout(); + test('save workout', () async { + workoutProvider.motivationBefore = 70; + workoutProvider.motivationAfter = 80; + workoutProvider.saveWorkout(); - // // -> hier in datenbank nachschauen obs geklappt hat - // }); + final result = await globals.databaseService.getWorkoutRecords(); + + expect(result.length, 1); + }); }); } From 58ce7fdb0e4869dfc9d78de054c4618053454be1 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 22:54:09 +0100 Subject: [PATCH 21/27] mute button test --- test/widget_tests/mute_button_test.dart | 34 +++++++++++ .../widget_entry_detail_test.dart | 60 ++++++++++--------- 2 files changed, 65 insertions(+), 29 deletions(-) create mode 100644 test/widget_tests/mute_button_test.dart diff --git a/test/widget_tests/mute_button_test.dart b/test/widget_tests/mute_button_test.dart new file mode 100644 index 0000000..bd9d7fe --- /dev/null +++ b/test/widget_tests/mute_button_test.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/providers/audio_provider.dart'; +import 'package:smoke_cess_app/widgets/buttons/mute_button.dart'; + +void main() { + group('MuteButton', () { + testWidgets('should handle mute logic', (WidgetTester tester) async { + AudioProvider audioProvider = AudioProvider(); + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: ChangeNotifierProvider( + create: (context) => audioProvider, + child: const MuteButton()))), + ); + final button = find.byType(IconButton); + final mutedIcon = find.byIcon(Icons.volume_off_outlined); + final unMutedIcon = find.byIcon(Icons.volume_up_outlined); + expect(audioProvider.isMuted, false); + expect(button, findsOneWidget); + expect(mutedIcon, findsNothing); + expect(unMutedIcon, findsOneWidget); + + await tester.tap(unMutedIcon); + await tester.pump(); + + expect(audioProvider.isMuted, true); + expect(mutedIcon, findsOneWidget); + expect(unMutedIcon, findsNothing); + }); + }); +} diff --git a/test/widget_tests/widget_entry_detail_test.dart b/test/widget_tests/widget_entry_detail_test.dart index 0eed669..a2d3f5a 100644 --- a/test/widget_tests/widget_entry_detail_test.dart +++ b/test/widget_tests/widget_entry_detail_test.dart @@ -5,37 +5,39 @@ import 'package:smoke_cess_app/widgets/entry_detail_widget.dart'; void main() { initializeDateFormatting('de'); - testWidgets('Entry Detail should use ExpansionTile if Comments is set', - (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: EntryDetail( - date: DateTime.now(), - entryComment: 'A comment', - entryData: 'Test', - iconData: Icons.plus_one, - ), - )), - ); + group('EntryDetail', () { + testWidgets('should use ExpansionTile if Comments is set', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: EntryDetail( + date: DateTime.now(), + entryComment: 'A comment', + entryData: 'Test', + iconData: Icons.plus_one, + ), + )), + ); - expect(find.byType(ExpansionTile), findsOneWidget); - }); + expect(find.byType(ExpansionTile), findsOneWidget); + }); - testWidgets('Entry Detail should use ListTile if Comments is null', - (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: EntryDetail( - date: DateTime.now(), - entryComment: 'A comment', - entryData: 'Test', - iconData: Icons.plus_one, - ), - )), - ); + testWidgets('should use ListTile if Comments is null', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: EntryDetail( + date: DateTime.now(), + entryComment: 'A comment', + entryData: 'Test', + iconData: Icons.plus_one, + ), + )), + ); - expect(find.byType(ListTile), findsOneWidget); + expect(find.byType(ListTile), findsOneWidget); + }); }); } From 7985e3bd1d956341c30e400159767a3052d03644 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 23:06:33 +0100 Subject: [PATCH 22/27] mocked audio provider for workout provider test --- test/mock/audio_provider_mock.dart | 22 ++++++++++++++++++++++ test/unit_tests/workout_provider_test.dart | 3 ++- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 test/mock/audio_provider_mock.dart diff --git a/test/mock/audio_provider_mock.dart b/test/mock/audio_provider_mock.dart new file mode 100644 index 0000000..0a723b4 --- /dev/null +++ b/test/mock/audio_provider_mock.dart @@ -0,0 +1,22 @@ +import 'package:audioplayers/audioplayers.dart'; +import 'package:smoke_cess_app/providers/audio_provider.dart'; + +class AudioProviderMock extends AudioProvider { + @override + bool get isMuted => true; + + @override + void stop() {} + + @override + void playFinishSound() {} + + @override + void mutePlayer() {} + + @override + void unMutePlayer() {} + + @override + void playSourceAfterBeep(AssetSource source) {} +} diff --git a/test/unit_tests/workout_provider_test.dart b/test/unit_tests/workout_provider_test.dart index 45c7685..f708703 100644 --- a/test/unit_tests/workout_provider_test.dart +++ b/test/unit_tests/workout_provider_test.dart @@ -4,6 +4,7 @@ import 'package:smoke_cess_app/providers/audio_provider.dart'; import 'package:smoke_cess_app/providers/timer_provider.dart'; import 'package:smoke_cess_app/providers/workout_provider.dart'; import 'package:smoke_cess_app/globals.dart' as globals; +import '../mock/audio_provider_mock.dart'; import '../mock/db_mock.dart'; void main() { @@ -16,7 +17,7 @@ void main() { setUp(() { timerProvider = TimerProvider(); - audioProvider = AudioProvider(); + audioProvider = AudioProviderMock(); workoutProvider = WorkoutProvider(timerProvider, audioProvider); }); From 8a6728a1f6fefede662550117f7e23b479d61956 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 23:42:11 +0100 Subject: [PATCH 23/27] add timer widget test --- test/widget_tests/timer_widget_test.dart | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 test/widget_tests/timer_widget_test.dart diff --git a/test/widget_tests/timer_widget_test.dart b/test/widget_tests/timer_widget_test.dart new file mode 100644 index 0000000..9275262 --- /dev/null +++ b/test/widget_tests/timer_widget_test.dart @@ -0,0 +1,32 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/providers/timer_provider.dart'; +import 'package:smoke_cess_app/utils/timer_util.dart'; +import 'package:smoke_cess_app/widgets/timer_widget.dart'; + +void main() { + group('TimerWidget', () { + testWidgets('should display duration', (WidgetTester tester) async { + TimerProvider timerProvider = TimerProvider(); + Duration duration = const Duration(minutes: 1); + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: ChangeNotifierProvider( + create: (context) => timerProvider, + child: TimerWidget(duration: duration)))), + ); + + final durationTextFinder = find.text(formatTime(duration.inSeconds)); + expect(durationTextFinder, findsOneWidget); + + timerProvider.startTimer(duration); + await tester.pump(const Duration(seconds: 1)); + expect(durationTextFinder, findsNothing); + expect(find.text(formatTime(duration.inSeconds - 1)), findsOneWidget); + }); + }); +} From 52ec92b5660fd5ce37b11b699ae8317fa794ff8c Mon Sep 17 00:00:00 2001 From: "k.mannweiler" <2012491@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 23:46:49 +0100 Subject: [PATCH 24/27] Added Integrationtests --- lib/providers/tasks_provider.dart | 2 +- lib/widgets/view_form/mood_form.dart | 4 +- lib/widgets/view_form/sleep_view.dart | 2 +- test/integration_tests/mood_form_test.dart | 41 +++++++++++++ test/integration_tests/mood_view_test.dart | 49 ++++++++++++++++ test/integration_tests/relapse_form_test.dart | 57 +++++++++++++++++++ test/integration_tests/relapse_view_test.dart | 52 +++++++++++++++++ test/integration_tests/sleep_form_test.dart | 42 ++++++++++++++ test/integration_tests/sleep_view_test.dart | 53 +++++++++++++++++ 9 files changed, 298 insertions(+), 4 deletions(-) create mode 100644 test/integration_tests/mood_form_test.dart create mode 100644 test/integration_tests/mood_view_test.dart create mode 100644 test/integration_tests/relapse_form_test.dart create mode 100644 test/integration_tests/relapse_view_test.dart create mode 100644 test/integration_tests/sleep_form_test.dart create mode 100644 test/integration_tests/sleep_view_test.dart diff --git a/lib/providers/tasks_provider.dart b/lib/providers/tasks_provider.dart index 2fed9b8..17b2aa5 100644 --- a/lib/providers/tasks_provider.dart +++ b/lib/providers/tasks_provider.dart @@ -31,7 +31,7 @@ class TasksProvider extends ChangeNotifier { notifyListeners(); } - void initHistories() async { + Future initHistories() async { moodHistory = await globals.databaseService.getMoodRecords(); sleepHistory = await globals.databaseService.getSleepRecords(); workoutHistory = await globals.databaseService.getWorkoutRecords(); diff --git a/lib/widgets/view_form/mood_form.dart b/lib/widgets/view_form/mood_form.dart index 588d542..d287767 100644 --- a/lib/widgets/view_form/mood_form.dart +++ b/lib/widgets/view_form/mood_form.dart @@ -13,8 +13,8 @@ class MoodForm extends StatelessWidget { @override Widget build(BuildContext context) { - var inputModel = context.watch(); - var tasksModel = context.watch(); + InputProvider inputModel = context.watch(); + TasksProvider tasksModel = context.watch(); return ListView( padding: const EdgeInsets.fromLTRB(10, 10, 10, 10), children: [ diff --git a/lib/widgets/view_form/sleep_view.dart b/lib/widgets/view_form/sleep_view.dart index e53837c..add4e8f 100644 --- a/lib/widgets/view_form/sleep_view.dart +++ b/lib/widgets/view_form/sleep_view.dart @@ -27,7 +27,7 @@ class SleepView extends StatelessWidget { history: tasksModel.sleepHistory, dateSelector: (Sleep sleep) => sleep.date, entryDataSelector: (Sleep sleep) => - '${sleep.sleepDuration.hour}:${sleep.sleepDuration.minute}', + '${sleep.sleepDuration.hour}:${sleep.sleepDuration.minute.toString().padLeft(2, "0")}', entryCommentSelector: (Sleep sleep) => 'Kommentar: ${sleep.comment}', icon: Icons.bedtime_outlined, ) diff --git a/test/integration_tests/mood_form_test.dart b/test/integration_tests/mood_form_test.dart new file mode 100644 index 0000000..c723e0a --- /dev/null +++ b/test/integration_tests/mood_form_test.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/providers/input_provider.dart'; +import 'package:smoke_cess_app/providers/page_provider.dart'; +import 'package:smoke_cess_app/providers/tasks_provider.dart'; +import 'package:smoke_cess_app/widgets/view_form/mood_form.dart'; +import 'package:smoke_cess_app/globals.dart' as globals; +import '../mock/db_mock.dart'; + +void main() { + globals.databaseService = DatabaseMock(); + testWidgets('Mood Form saves correctly', (WidgetTester tester) async { + const String testText = 'Its a test'; + // Create an instance of the Providers and add it to the widget tree + final inputProvider = InputProvider(); + final tasksProvider = TasksProvider(null); + final pageProvider = PageProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ChangeNotifierProvider.value(value: tasksProvider), + ChangeNotifierProvider.value(value: pageProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MoodForm(), + ), + ), + ), + ); + + await tester.enterText(find.byType(TextField), testText); + await tester.tap(find.byType(ElevatedButton)); + await tester.pump(); + final result = await globals.databaseService.getMoodRecords(); + expect(result.last.comment, testText); + expect(result.last.moodValue, 50); + }); +} diff --git a/test/integration_tests/mood_view_test.dart b/test/integration_tests/mood_view_test.dart new file mode 100644 index 0000000..00bb61b --- /dev/null +++ b/test/integration_tests/mood_view_test.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:intl/date_symbol_data_local.dart'; +import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:smoke_cess_app/models/mood.dart'; +import 'package:smoke_cess_app/providers/settings_provider.dart'; +import 'package:smoke_cess_app/providers/tasks_provider.dart'; +import 'package:smoke_cess_app/globals.dart' as globals; +import 'package:smoke_cess_app/widgets/view_form/mood_view.dart'; +import '../mock/db_mock.dart'; +import '../mock/settings_mock.dart'; + +void main() { + globals.databaseService = DatabaseMock(); + TestWidgetsFlutterBinding.ensureInitialized(); + SharedPreferences.setMockInitialValues(mockSettings); + initializeDateFormatting('de'); + testWidgets('Mood View displays correctly', (WidgetTester tester) async { + const String testText = 'Its a test'; + const int testValue = 30; + // Create an instance of the Providers and add it to the widget tree + final tasksProvider = TasksProvider(null); + final settingsProvider = SettingsProvider(); + + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: tasksProvider), + ChangeNotifierProvider.value(value: settingsProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MoodView(), + ), + ), + ), + ); + await settingsProvider.initSettings(); + await globals.databaseService + .addMood(Mood(testValue, testText, DateTime.now())); + await tasksProvider.initHistories(); + await tester.pump(); + expect(find.text('Stimmung: $testValue'), findsOneWidget); + await tester.tap(find.byIcon(Icons.expand_more)); + await tester.pump(); + expect(find.text('Kommentar: $testText'), findsOneWidget); + }); +} diff --git a/test/integration_tests/relapse_form_test.dart b/test/integration_tests/relapse_form_test.dart new file mode 100644 index 0000000..cdf7321 --- /dev/null +++ b/test/integration_tests/relapse_form_test.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:smoke_cess_app/providers/input_provider.dart'; +import 'package:smoke_cess_app/providers/page_provider.dart'; +import 'package:smoke_cess_app/providers/settings_provider.dart'; +import 'package:smoke_cess_app/providers/tasks_provider.dart'; +import 'package:smoke_cess_app/globals.dart' as globals; +import 'package:smoke_cess_app/widgets/drop_down.dart'; +import 'package:smoke_cess_app/widgets/view_form/relapse_form.dart'; +import '../mock/db_mock.dart'; +import '../mock/settings_mock.dart'; + +void main() { + globals.databaseService = DatabaseMock(); + TestWidgetsFlutterBinding.ensureInitialized(); + SharedPreferences.setMockInitialValues(mockSettings); + testWidgets('Relapse Form saves correctly', (WidgetTester tester) async { + const String testText = 'Its a test'; + // Create an instance of the Providers and add it to the widget tree + final inputProvider = InputProvider(); + final tasksProvider = TasksProvider(null); + final pageProvider = PageProvider(); + final settingsProvider = SettingsProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ChangeNotifierProvider.value(value: tasksProvider), + ChangeNotifierProvider.value(value: pageProvider), + ChangeNotifierProvider.value(value: settingsProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: RelapseForm(), + ), + ), + ), + ); + + await settingsProvider.initSettings(); + + await tester.enterText(find.byType(TextField), testText); + await tester.tap(find.byType(DropDown)); + await tester.pump(); + await tester + .tap(find.text(settingsProvider.settings!.relapseCategories![1]).last); + await tester.pump(); + await tester.tap(find.byType(ElevatedButton).last); + await tester.pump(); + final result = await globals.databaseService.getRelapseRecords(); + expect(result.last.comment, testText); + expect( + result.last.category, settingsProvider.settings!.relapseCategories![1]); + }); +} diff --git a/test/integration_tests/relapse_view_test.dart b/test/integration_tests/relapse_view_test.dart new file mode 100644 index 0000000..96f3ee9 --- /dev/null +++ b/test/integration_tests/relapse_view_test.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:intl/date_symbol_data_local.dart'; +import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:smoke_cess_app/models/relapse.dart'; +import 'package:smoke_cess_app/providers/settings_provider.dart'; +import 'package:smoke_cess_app/providers/tasks_provider.dart'; +import 'package:smoke_cess_app/globals.dart' as globals; +import 'package:smoke_cess_app/widgets/view_form/relapse_view.dart'; +import '../mock/db_mock.dart'; +import '../mock/settings_mock.dart'; + +void main() { + globals.databaseService = DatabaseMock(); + TestWidgetsFlutterBinding.ensureInitialized(); + SharedPreferences.setMockInitialValues(mockSettings); + initializeDateFormatting('de'); + testWidgets('Relapse View displays correctly', (WidgetTester tester) async { + const String testText = 'Its a test'; + // Create an instance of the Providers and add it to the widget tree + final tasksProvider = TasksProvider(null); + final settingsProvider = SettingsProvider(); + + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: tasksProvider), + ChangeNotifierProvider.value(value: settingsProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: RelapseView(), + ), + ), + ), + ); + await settingsProvider.initSettings(); + await globals.databaseService.addRelapse(Relapse( + settingsProvider.settings!.relapseCategories![0], + testText, + DateTime.now(), + )); + await tasksProvider.initHistories(); + await tester.pump(); + expect(find.text(settingsProvider.settings!.relapseCategories![0]), + findsOneWidget); + await tester.tap(find.byIcon(Icons.expand_more)); + await tester.pump(); + expect(find.text('Kommentar: $testText'), findsOneWidget); + }); +} diff --git a/test/integration_tests/sleep_form_test.dart b/test/integration_tests/sleep_form_test.dart new file mode 100644 index 0000000..b833f08 --- /dev/null +++ b/test/integration_tests/sleep_form_test.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/providers/input_provider.dart'; +import 'package:smoke_cess_app/providers/page_provider.dart'; +import 'package:smoke_cess_app/providers/tasks_provider.dart'; +import 'package:smoke_cess_app/globals.dart' as globals; +import 'package:smoke_cess_app/widgets/view_form/sleep_form.dart'; +import '../mock/db_mock.dart'; + +void main() { + globals.databaseService = DatabaseMock(); + testWidgets('Sleep Form saves correctly', (WidgetTester tester) async { + const String testText = 'Its a test'; + // Create an instance of the Providers and add it to the widget tree + final inputProvider = InputProvider(); + final tasksProvider = TasksProvider(null); + final pageProvider = PageProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ChangeNotifierProvider.value(value: tasksProvider), + ChangeNotifierProvider.value(value: pageProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: SleepForm(), + ), + ), + ), + ); + + await tester.enterText(find.byType(TextField), testText); + await tester.tap(find.byType(ElevatedButton).last); + await tester.pump(); + final result = await globals.databaseService.getSleepRecords(); + expect(result.last.comment, testText); + expect(result.last.sleepQualitiyValue, 50); + expect(result.last.sleepDuration, const TimeOfDay(hour: 10, minute: 0)); + }); +} diff --git a/test/integration_tests/sleep_view_test.dart b/test/integration_tests/sleep_view_test.dart new file mode 100644 index 0000000..b8f2e1e --- /dev/null +++ b/test/integration_tests/sleep_view_test.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:intl/date_symbol_data_local.dart'; +import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:smoke_cess_app/models/sleep.dart'; +import 'package:smoke_cess_app/providers/settings_provider.dart'; +import 'package:smoke_cess_app/providers/tasks_provider.dart'; +import 'package:smoke_cess_app/globals.dart' as globals; +import 'package:smoke_cess_app/widgets/view_form/sleep_view.dart'; +import '../mock/db_mock.dart'; +import '../mock/settings_mock.dart'; + +void main() { + globals.databaseService = DatabaseMock(); + TestWidgetsFlutterBinding.ensureInitialized(); + SharedPreferences.setMockInitialValues(mockSettings); + initializeDateFormatting('de'); + testWidgets('Sleep View displays correctly', (WidgetTester tester) async { + const String testText = 'Its a test'; + const int testValue = 30; + // Create an instance of the Providers and add it to the widget tree + final tasksProvider = TasksProvider(null); + final settingsProvider = SettingsProvider(); + + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: tasksProvider), + ChangeNotifierProvider.value(value: settingsProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: SleepView(), + ), + ), + ), + ); + await settingsProvider.initSettings(); + await globals.databaseService.addSleep(Sleep( + testValue, + testText, + DateTime.now(), + const TimeOfDay(hour: 22, minute: 0), + const TimeOfDay(hour: 8, minute: 0))); + await tasksProvider.initHistories(); + await tester.pump(); + expect(find.text('10:00'), findsOneWidget); + await tester.tap(find.byIcon(Icons.expand_more)); + await tester.pump(); + expect(find.text('Kommentar: $testText'), findsOneWidget); + }); +} From 4764aa40f0a9bbbc6d2907197bb411b83d6bc1bb Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 23:50:13 +0100 Subject: [PATCH 25/27] use correct workout times --- lib/providers/workout_provider.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/providers/workout_provider.dart b/lib/providers/workout_provider.dart index ebcaf9c..0db0c82 100644 --- a/lib/providers/workout_provider.dart +++ b/lib/providers/workout_provider.dart @@ -100,25 +100,25 @@ class WorkoutProvider extends ChangeNotifier { Map> _workoutPhaseSettings = { WorkoutPhases.warmUp: { 'title': 'Warm Up', - 'duration': const Duration(seconds: 5), + 'duration': const Duration(minutes: 5), 'source': AssetSource('warmUp.mp3'), 'color': Colors.green }, WorkoutPhases.highIntensity: { 'title': 'High Intensity', - 'duration': const Duration(seconds: 4), + 'duration': const Duration(minutes: 4), 'source': AssetSource('workout.mp3'), 'color': Colors.red }, WorkoutPhases.lowIntensity: { 'title': 'Low Intensity', - 'duration': const Duration(seconds: 3), + 'duration': const Duration(minutes: 3), 'source': AssetSource('workout.mp3'), 'color': Colors.orange }, WorkoutPhases.coolDown: { 'title': 'Cool Down', - 'duration': const Duration(seconds: 5), + 'duration': const Duration(minutes: 5), 'source': AssetSource('cool_down.mp3'), 'color': Colors.blue } From 8f4ae946de84ec729105eea385e03a9fe2b058bf Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Mon, 6 Mar 2023 23:58:02 +0100 Subject: [PATCH 26/27] unused import --- test/widget_tests/timer_widget_test.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/widget_tests/timer_widget_test.dart b/test/widget_tests/timer_widget_test.dart index 9275262..2a4ef9b 100644 --- a/test/widget_tests/timer_widget_test.dart +++ b/test/widget_tests/timer_widget_test.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:provider/provider.dart'; From ebd768057fae610dd09420434f47e48c4fc20ff4 Mon Sep 17 00:00:00 2001 From: Crondung <1922635@stud.hs-mannheim.de> Date: Tue, 7 Mar 2023 00:06:07 +0100 Subject: [PATCH 27/27] adjust workout provider tests --- test/unit_tests/workout_provider_test.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit_tests/workout_provider_test.dart b/test/unit_tests/workout_provider_test.dart index f708703..1d5c84c 100644 --- a/test/unit_tests/workout_provider_test.dart +++ b/test/unit_tests/workout_provider_test.dart @@ -27,7 +27,7 @@ void main() { expect(workoutProvider.motivationBefore, 50); expect(workoutProvider.motivationAfter, 50); expect(workoutProvider.currentPhase, WorkoutPhases.warmUp); - expect(workoutProvider.currentPhaseDuration, const Duration(seconds: 5)); + expect(workoutProvider.currentPhaseDuration, const Duration(minutes: 5)); expect(workoutProvider.isPhaseComplete, false); expect(workoutProvider.currentPhaseColor, Colors.green); expect(workoutProvider.currentPhaseTitle, 'Warm Up'); @@ -37,7 +37,7 @@ void main() { workoutProvider.nextPhase(); expect(workoutProvider.currentPhase, WorkoutPhases.highIntensity); - expect(workoutProvider.currentPhaseDuration, const Duration(seconds: 4)); + expect(workoutProvider.currentPhaseDuration, const Duration(minutes: 4)); expect(workoutProvider.isPhaseComplete, false); expect(workoutProvider.currentPhaseColor, Colors.red); expect(workoutProvider.currentPhaseTitle, 'High Intensity'); @@ -49,7 +49,7 @@ void main() { expect(workoutProvider.isWorkoutStarted, true); expect(workoutProvider.isWorkoutComplete, false); expect(workoutProvider.currentPhase, WorkoutPhases.warmUp); - expect(workoutProvider.currentPhaseDuration, const Duration(seconds: 5)); + expect(workoutProvider.currentPhaseDuration, const Duration(minutes: 5)); expect(workoutProvider.isPhaseComplete, false); });