Commit c0ced9e

derdilla <derdilla06@gmail.com>
2023-09-02 06:48:09
group code in AddMeasurementPage and write tests
1 parent 578b3eb
lib/components/measurement_list/measurement_list_entry.dart
@@ -1,5 +1,6 @@
 import 'package:blood_pressure_app/model/blood_pressure.dart';
 import 'package:blood_pressure_app/model/settings_store.dart';
+import 'package:blood_pressure_app/screens/add_measurement.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_gen/gen_l10n/app_localizations.dart';
 import 'package:intl/intl.dart';
@@ -27,9 +28,7 @@ class MeasurementListRow extends StatelessWidget {
                 Text(formatter.format(record.creationTime), textAlign: TextAlign.right,),
                 const Spacer(),
                 IconButton(
-                  onPressed: () {
-                    // TODO: implement
-                  },
+                  onPressed: () => _editEntry(context),
                   icon: const Icon(Icons.edit, color: Colors.blue,),
                   tooltip: localizations.edit,
                 ),
@@ -106,4 +105,8 @@ class MeasurementListRow extends StatelessWidget {
       ));
     }
   }
+
+  void _editEntry(BuildContext context) async {
+    Navigator.push(context, MaterialPageRoute(builder: (context) => AddMeasurementPage.edit(record)));
+  }
 }
lib/components/measurement_list.dart
@@ -87,18 +87,9 @@ class MeasurementList extends StatelessWidget {
                                 confirmDismiss: (direction) async {
                                   final model = Provider.of<BloodPressureModel>(context, listen: false);
                                   if (direction == DismissDirection.startToEnd) { // edit
-                                    model.delete(data[index].creationTime);
                                     Navigator.push(
                                       context,
-                                      MaterialPageRoute(
-                                          builder: (context) => AddMeasurementPage(
-                                            initTime: data[index].creationTime,
-                                            initSys: data[index].systolic,
-                                            initDia: data[index].diastolic,
-                                            initPul: data[index].pulse,
-                                            initNote: data[index].notes,
-                                            addInitialValuesOnCancel: true,
-                                          )),
+                                      MaterialPageRoute(builder: (context) => AddMeasurementPage.edit(data[index])),
                                     );
                                     return false;
                                   } else { // delete
lib/model/ram_only_implementations.dart
@@ -11,6 +11,14 @@ import 'horizontal_graph_line.dart';
 
 class RamBloodPressureModel extends ChangeNotifier implements BloodPressureModel {
   final List<BloodPressureRecord> _records = [];
+  
+  static RamBloodPressureModel fromEntries(List<BloodPressureRecord> records) {
+    final m = RamBloodPressureModel();
+    for (var e in records) {
+      m.add(e);
+    }
+    return m;
+  }
 
   @override
   Future<void> add(BloodPressureRecord measurement) async {
lib/screens/add_measurement.dart
@@ -15,7 +15,7 @@ class AddMeasurementPage extends StatefulWidget {
   final int? initDia;
   final int? initPul;
   final String? initNote;
-  final bool addInitialValuesOnCancel;
+  final bool isEdit;
 
   const AddMeasurementPage(
       {super.key,
@@ -24,7 +24,18 @@ class AddMeasurementPage extends StatefulWidget {
       this.initDia,
       this.initPul,
       this.initNote,
-      this.addInitialValuesOnCancel = false});
+      this.isEdit = false});
+
+  static AddMeasurementPage edit(BloodPressureRecord record) {
+    return AddMeasurementPage(
+      initTime: record.creationTime,
+      initSys: record.systolic,
+      initDia: record.diastolic,
+      initPul: record.pulse,
+      initNote: record.notes,
+      isEdit: true,
+    );
+  }
 
   @override
   State<AddMeasurementPage> createState() => _AddMeasurementPageState();
@@ -146,6 +157,7 @@ class _AddMeasurementPageState extends State<AddMeasurementPage> {
                           }
                       ),
                       TextFormField(
+                        key: const Key('txtNote'),
                         initialValue: (_note ?? '').toString(),
                         minLines: 1,
                         maxLines: 4,
@@ -163,15 +175,6 @@ class _AddMeasurementPageState extends State<AddMeasurementPage> {
                           TextButton(
                             key: const Key('btnCancel'),
                             onPressed: () {
-                              if (widget.addInitialValuesOnCancel) {
-                                assert(widget.initTime != null);
-                                Provider.of<BloodPressureModel>(context, listen: false).add(BloodPressureRecord(
-                                    widget.initTime ?? DateTime.now(),
-                                    widget.initSys,
-                                    widget.initDia,
-                                    widget.initPul,
-                                    widget.initNote ?? ''));
-                              }
                               Navigator.of(context).pop();
                             },
 
@@ -189,6 +192,12 @@ class _AddMeasurementPageState extends State<AddMeasurementPage> {
                                 final model = Provider.of<BloodPressureModel>(context, listen: false);
                                 final navigator = Navigator.of(context);
 
+                                if (widget.isEdit) {
+                                  assert(widget.initTime != null);
+                                  if (widget.initTime != null) {
+                                    await model.delete(widget.initTime!);
+                                  }
+                                }
                                 await model.add(BloodPressureRecord(_time, _systolic, _diastolic, _pulse, _note ?? ''));
                                 if (settings.exportAfterEveryEntry && context.mounted) {
                                   final exporter = Exporter(settings, model, ScaffoldMessenger.of(context),
test/ui/add_measurement.dart
@@ -0,0 +1,112 @@
+import 'package:blood_pressure_app/model/blood_pressure.dart';
+import 'package:blood_pressure_app/model/ram_only_implementations.dart';
+import 'package:blood_pressure_app/model/settings_store.dart';
+import 'package:blood_pressure_app/screens/add_measurement.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:provider/provider.dart';
+
+void main() {
+  group("Add measurements page", () {
+    group('normal mode', () {
+      testWidgets('smoke test', (tester) async {
+        await _initPage(tester, const AddMeasurementPage());
+        expect(find.text('Systolic'), findsOneWidget);
+        expect(find.text('SAVE'), findsOneWidget);
+      });
+      testWidgets('should start empty', (tester) async {
+        await _initPage(tester, const AddMeasurementPage());
+        final sysInput = tester.widget<TextFormField>(
+            find.descendant(of: find.byKey(const Key('txtSys')), matching: find.byType(TextFormField)));
+        expect(sysInput.initialValue, '');
+        final diaInput = tester.widget<TextFormField>(
+            find.descendant(of: find.byKey(const Key('txtDia')), matching: find.byType(TextFormField)));
+        expect(diaInput.initialValue, '');
+        final pulInput = tester.widget<TextFormField>(
+            find.descendant(of: find.byKey(const Key('txtPul')), matching: find.byType(TextFormField)));
+        expect(pulInput.initialValue, '');
+        final noteInput = tester.widget<TextFormField>(find.byKey(const Key('txtNote')));
+        expect(noteInput.initialValue, '');
+      });
+    });
+    group('edit mode', () {
+      testWidgets('smoke test', (tester) async {
+        final record = BloodPressureRecord(DateTime.now(), 123, 89, 56, 'simple test note');
+        await _initPage(tester, AddMeasurementPage.edit(record),
+            model: RamBloodPressureModel.fromEntries([record])
+        );
+        expect(find.text('Systolic'), findsOneWidget);
+        expect(find.text('SAVE'), findsOneWidget);
+      });
+      testWidgets('should prefill', (tester) async {
+        final record = BloodPressureRecord(DateTime.now(), 123, 89, 56, 'simple test note');
+        await _initPage(tester, AddMeasurementPage.edit(record),
+            model: RamBloodPressureModel.fromEntries([record])
+        );
+
+        final sysInput = tester.widget<TextFormField>(
+            find.descendant(of: find.byKey(const Key('txtSys')), matching: find.byType(TextFormField)));
+        expect(sysInput.initialValue, record.systolic.toString());
+        final diaInput = tester.widget<TextFormField>(
+            find.descendant(of: find.byKey(const Key('txtDia')), matching: find.byType(TextFormField)));
+        expect(diaInput.initialValue, record.diastolic.toString());
+        final pulInput = tester.widget<TextFormField>(
+            find.descendant(of: find.byKey(const Key('txtPul')), matching: find.byType(TextFormField)));
+        expect(pulInput.initialValue, record.pulse.toString());
+        final noteInput = tester.widget<TextFormField>(find.byKey(const Key('txtNote')));
+        expect(noteInput.initialValue, record.notes);
+      });
+      testWidgets('should not delete on cancel', (tester) async {
+        final record = BloodPressureRecord(DateTime.now(), 123, 89, 56, 'simple test note');
+        final model = RamBloodPressureModel.fromEntries([record]);
+        await _initPage(tester, AddMeasurementPage.edit(record), model: model);
+        expect((await model.all).first, record);
+
+        expect(find.byKey(const Key ('txtNote')), findsOneWidget);
+        await tester.enterText(find.byKey(const Key ('txtNote')), 'edited text');
+
+        expect(find.byKey(const Key('btnCancel')), findsOneWidget);
+        await tester.tap(find.byKey(const Key('btnCancel')));
+        await tester.pumpAndSettle();
+        expect((await model.all).first.notes, 'simple test note');
+        expect((await model.all).first, record);
+      });
+      testWidgets('should save changes', (tester) async {
+        final record = BloodPressureRecord(DateTime.now(), 123, 89, 56, 'simple test note');
+        final model = RamBloodPressureModel.fromEntries([record]);
+        await _initPage(tester, AddMeasurementPage.edit(record), model: model);
+        expect((await model.all).first, record);
+
+        expect(find.byKey(const Key ('txtNote')), findsOneWidget);
+        await tester.enterText(find.byKey(const Key ('txtNote')), 'edited text');
+
+        expect(find.byKey(const Key('btnSave')), findsOneWidget);
+        await tester.tap(find.byKey(const Key('btnSave')));
+        await tester.pumpAndSettle();
+        expect((await model.all).first.notes, 'edited text');
+      });
+    });
+  });
+}
+
+Future<void> _initPage(WidgetTester widgetTester, Widget pageWidget, {Settings? settings, BloodPressureModel? model}) async {
+  await widgetTester.pumpWidget(
+    MaterialApp(
+      home: MultiProvider(
+          providers: [
+            ChangeNotifierProvider<Settings>(create: (_) => settings ?? RamSettings()),
+            ChangeNotifierProvider<BloodPressureModel>(create: (_) => model ?? RamBloodPressureModel()),
+          ],
+          child: Localizations(
+            delegates: AppLocalizations.localizationsDelegates,
+            locale: const Locale('en'),
+            child: pageWidget,
+          )
+      )
+    ),
+  );
+
+  await widgetTester.pumpAndSettle();
+}
+