Use "clock" for mocking dates and datetimes

This should make the tests a bit more robust, specially in CI since these
tended to fail depending on how long and when the tests run. Also, rework
a bit the way the start and end dates in sessions were being handled and
initialised
This commit is contained in:
Roland Geider
2025-09-16 13:54:41 +02:00
parent 15805f20bf
commit 9b3957fe35
5 changed files with 193 additions and 183 deletions

View File

@@ -67,8 +67,8 @@ String dateToUtcIso8601(DateTime dateTime) {
* Needed e.g. when the wger api only sends a time but no date information.
*/
TimeOfDay stringToTime(String? time) {
final String out = time ?? '00:00';
return TimeOfDay.fromDateTime(DateTime.parse('2020-01-01 $out'));
time ??= '00:00';
return TimeOfDay.fromDateTime(DateTime.parse('2020-01-01 $time'));
}
TimeOfDay? stringToTimeNull(String? time) {

View File

@@ -1,3 +1,4 @@
import 'package:clock/clock.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logging/logging.dart';
@@ -26,7 +27,7 @@ class GymState {
DateTime? validUntil,
TimeOfDay? startTime}) {
this.validUntil = validUntil ?? DateTime.now().add(DEFAULT_DURATION);
this.startTime = startTime ?? TimeOfDay.now();
this.startTime = startTime ?? TimeOfDay.fromDateTime(clock.now());
}
GymState copyWith({

View File

@@ -44,8 +44,8 @@ class SessionForm extends StatefulWidget {
dayId: dayId,
impression: DEFAULT_IMPRESSION,
date: clock.now(),
timeEnd: TimeOfDay.now(),
timeStart: TimeOfDay.now(),
timeEnd: TimeOfDay.fromDateTime(clock.now()),
timeStart: null,
);
@override
@@ -68,8 +68,10 @@ class _SessionFormState extends State<SessionForm> {
void initState() {
super.initState();
timeStartController.text = timeToString(widget._session.timeStart) ?? '';
timeEndController.text = timeToString(widget._session.timeEnd) ?? '';
timeStartController.text =
widget._session.timeStart == null ? '' : timeToString(widget._session.timeStart)!;
timeEndController.text =
widget._session.timeEnd == null ? '' : timeToString(widget._session.timeEnd)!;
notesController.text = widget._session.notes;
selectedImpression[widget._session.impression - 1] = true;
@@ -129,6 +131,7 @@ class _SessionFormState extends State<SessionForm> {
},
),
Row(
spacing: 10,
children: [
Flexible(
child: TextFormField(
@@ -163,16 +166,19 @@ class _SessionFormState extends State<SessionForm> {
if (timeStartController.text.isEmpty && timeEndController.text.isEmpty) {
return null;
}
final TimeOfDay startTime = stringToTime(timeStartController.text);
final TimeOfDay endTime = stringToTime(timeEndController.text);
if (startTime.isAfter(endTime)) {
return AppLocalizations.of(context).timeStartAhead;
if (timeStartController.text.isNotEmpty && timeEndController.text.isNotEmpty) {
final TimeOfDay startTime = stringToTime(timeStartController.text);
final TimeOfDay endTime = stringToTime(timeEndController.text);
if (startTime.isAfter(endTime)) {
return AppLocalizations.of(context).timeStartAhead;
}
}
return null;
},
),
),
const SizedBox(width: 10),
Flexible(
child: TextFormField(
key: const ValueKey('time-end'),

View File

@@ -45,8 +45,8 @@ class SessionPage extends StatelessWidget {
routineId: _routine.id!,
impression: DEFAULT_IMPRESSION,
date: clock.now(),
timeEnd: TimeOfDay.now(),
timeStart: start,
timeEnd: TimeOfDay.fromDateTime(clock.now()),
),
);

View File

@@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:clock/clock.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart' as riverpod;
import 'package:flutter_test/flutter_test.dart';
@@ -24,7 +25,6 @@ import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart';
import 'package:wger/helpers/json.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/base_provider.dart';
import 'package:wger/providers/exercises.dart';
@@ -101,192 +101,195 @@ void main() {
exerciseIdToExclude: anyNamed('exerciseIdToExclude'),
)).thenReturn([]);
await tester.pumpWidget(renderGymMode());
//await tester.pumpWidget(createHomeScreen());
await tester.tap(find.byType(TextButton));
//print(find.byType(TextButton));
await tester.pumpAndSettle();
//await tester.ensureVisible(find.byKey(Key(key as String)));
//
// Start page
//
expect(find.byType(StartPage), findsOneWidget);
expect(find.text('Your workout today'), findsOneWidget);
expect(find.text('Bench press'), findsOneWidget);
expect(find.text('Side raises'), findsOneWidget);
expect(find.byIcon(Icons.close), findsOneWidget);
expect(find.byIcon(Icons.toc), findsOneWidget);
expect(find.byIcon(Icons.chevron_left), findsNothing);
expect(find.byIcon(Icons.chevron_right), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
await withClock(Clock.fixed(DateTime(2025, 3, 29, 14, 33)), () async {
await tester.pumpWidget(renderGymMode());
//
// Bench press - exercise overview page
//
expect(find.text('Bench press'), findsOneWidget);
expect(find.byType(ExerciseOverview), findsOneWidget);
expect(find.byIcon(Icons.close), findsOneWidget);
expect(find.byIcon(Icons.toc), findsOneWidget);
expect(find.byIcon(Icons.chevron_left), findsOneWidget);
expect(find.byIcon(Icons.chevron_right), findsOneWidget);
await tester.drag(find.byType(ExerciseOverview), const Offset(-500.0, 0.0));
await tester.pumpAndSettle();
await tester.pumpAndSettle();
await tester.tap(find.byType(TextButton));
//
// Bench press - Log
//
expect(find.text('Bench press'), findsOneWidget);
expect(find.byType(LogPage), findsOneWidget);
expect(find.byType(Form), findsOneWidget);
// print(find.byType(Form));
expect(find.byType(ListTile), findsNWidgets(3), reason: 'Two logs and the switch tile');
expect(find.text('10 × 10 kg (1.5 RiR)'), findsOneWidget);
expect(find.text('12 × 10 kg (2 RiR)'), findsOneWidget);
expect(find.text('Make sure to warm up'), findsOneWidget, reason: 'Set comment');
expect(find.byIcon(Icons.close), findsOneWidget);
expect(find.byIcon(Icons.toc), findsOneWidget);
expect(find.byIcon(Icons.chevron_left), findsOneWidget);
expect(find.byIcon(Icons.chevron_right), findsOneWidget);
await tester.pumpAndSettle();
//await tester.ensureVisible(find.byKey(Key(key as String)));
//
// Start page
//
expect(find.byType(StartPage), findsOneWidget);
expect(find.text('Your workout today'), findsOneWidget);
expect(find.text('Bench press'), findsOneWidget);
expect(find.text('Side raises'), findsOneWidget);
expect(find.byIcon(Icons.close), findsOneWidget);
expect(find.byIcon(Icons.toc), findsOneWidget);
expect(find.byIcon(Icons.chevron_left), findsNothing);
expect(find.byIcon(Icons.chevron_right), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
// Form shows only weight and reps
expect(find.byType(SwitchListTile), findsOneWidget);
expect(find.byType(TextFormField), findsNWidgets(2));
expect(find.byType(RepetitionUnitInputWidget), findsNothing);
expect(find.byType(WeightUnitInputWidget), findsNothing);
expect(find.byType(RiRInputWidget), findsNothing);
//
// Bench press - exercise overview page
//
expect(find.text('Bench press'), findsOneWidget);
expect(find.byType(ExerciseOverview), findsOneWidget);
expect(find.byIcon(Icons.close), findsOneWidget);
expect(find.byIcon(Icons.toc), findsOneWidget);
expect(find.byIcon(Icons.chevron_left), findsOneWidget);
expect(find.byIcon(Icons.chevron_right), findsOneWidget);
await tester.drag(find.byType(ExerciseOverview), const Offset(-500.0, 0.0));
await tester.pumpAndSettle();
// Form shows unit and rir after tapping the toggle button
await tester.tap(find.byType(SwitchListTile));
await tester.pump();
expect(find.byType(RepetitionUnitInputWidget), findsOneWidget);
expect(find.byType(WeightUnitInputWidget), findsOneWidget);
expect(find.byType(RiRInputWidget), findsOneWidget);
await tester.drag(find.byType(LogPage), const Offset(-500.0, 0.0));
await tester.pumpAndSettle();
//
// Bench press - Log
//
expect(find.text('Bench press'), findsOneWidget);
expect(find.byType(LogPage), findsOneWidget);
expect(find.byType(Form), findsOneWidget);
// print(find.byType(Form));
expect(find.byType(ListTile), findsNWidgets(3), reason: 'Two logs and the switch tile');
expect(find.text('10 × 10 kg (1.5 RiR)'), findsOneWidget);
expect(find.text('12 × 10 kg (2 RiR)'), findsOneWidget);
expect(find.text('Make sure to warm up'), findsOneWidget, reason: 'Set comment');
expect(find.byIcon(Icons.close), findsOneWidget);
expect(find.byIcon(Icons.toc), findsOneWidget);
expect(find.byIcon(Icons.chevron_left), findsOneWidget);
expect(find.byIcon(Icons.chevron_right), findsOneWidget);
//
// Bench press - pause
//
expect(find.text('Pause'), findsOneWidget);
expect(find.byType(TimerCountdownWidget), findsOneWidget);
expect(find.byIcon(Icons.close), findsOneWidget);
expect(find.byIcon(Icons.toc), findsOneWidget);
expect(find.byIcon(Icons.chevron_left), findsOneWidget);
expect(find.byIcon(Icons.chevron_right), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
// Form shows only weight and reps
expect(find.byType(SwitchListTile), findsOneWidget);
expect(find.byType(TextFormField), findsNWidgets(2));
expect(find.byType(RepetitionUnitInputWidget), findsNothing);
expect(find.byType(WeightUnitInputWidget), findsNothing);
expect(find.byType(RiRInputWidget), findsNothing);
//
// Bench press - log
//
expect(find.text('Bench press'), findsOneWidget);
expect(find.byType(LogPage), findsOneWidget);
expect(find.byType(Form), findsOneWidget);
await tester.drag(find.byType(LogPage), const Offset(-500.0, 0.0));
await tester.pumpAndSettle();
// Form shows unit and rir after tapping the toggle button
await tester.tap(find.byType(SwitchListTile));
await tester.pump();
expect(find.byType(RepetitionUnitInputWidget), findsOneWidget);
expect(find.byType(WeightUnitInputWidget), findsOneWidget);
expect(find.byType(RiRInputWidget), findsOneWidget);
await tester.drag(find.byType(LogPage), const Offset(-500.0, 0.0));
await tester.pumpAndSettle();
//
// Pause
//
expect(find.text('Pause'), findsOneWidget);
expect(find.byType(TimerCountdownWidget), findsOneWidget);
expect(find.byIcon(Icons.chevron_left), findsOneWidget);
expect(find.byIcon(Icons.close), findsOneWidget);
expect(find.byIcon(Icons.chevron_right), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Bench press - pause
//
expect(find.text('Pause'), findsOneWidget);
expect(find.byType(TimerCountdownWidget), findsOneWidget);
expect(find.byIcon(Icons.close), findsOneWidget);
expect(find.byIcon(Icons.toc), findsOneWidget);
expect(find.byIcon(Icons.chevron_left), findsOneWidget);
expect(find.byIcon(Icons.chevron_right), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Bench press - log
//
expect(find.text('Bench press'), findsOneWidget);
expect(find.byType(LogPage), findsOneWidget);
expect(find.byType(Form), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Bench press - log
//
expect(find.text('Bench press'), findsOneWidget);
expect(find.byType(LogPage), findsOneWidget);
expect(find.byType(Form), findsOneWidget);
await tester.drag(find.byType(LogPage), const Offset(-500.0, 0.0));
await tester.pumpAndSettle();
//
// Pause
//
expect(find.text('Pause'), findsOneWidget);
expect(find.byType(TimerCountdownWidget), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Pause
//
expect(find.text('Pause'), findsOneWidget);
expect(find.byType(TimerCountdownWidget), findsOneWidget);
expect(find.byIcon(Icons.chevron_left), findsOneWidget);
expect(find.byIcon(Icons.close), findsOneWidget);
expect(find.byIcon(Icons.chevron_right), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Side raises - overview
//
expect(find.text('Side raises'), findsOneWidget);
expect(find.byType(ExerciseOverview), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Bench press - log
//
expect(find.text('Bench press'), findsOneWidget);
expect(find.byType(LogPage), findsOneWidget);
expect(find.byType(Form), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Side raises - log
//
expect(find.text('Side raises'), findsOneWidget);
expect(find.byType(LogPage), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Pause
//
expect(find.text('Pause'), findsOneWidget);
expect(find.byType(TimerCountdownWidget), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Side raises - timer
//
expect(find.byType(TimerWidget), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Side raises - overview
//
expect(find.text('Side raises'), findsOneWidget);
expect(find.byType(ExerciseOverview), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Side raises - log
//
expect(find.text('Side raises'), findsOneWidget);
expect(find.byType(LogPage), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Side raises - log
//
expect(find.text('Side raises'), findsOneWidget);
expect(find.byType(LogPage), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Side raises - timer
//
expect(find.byType(TimerWidget), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Side raises - timer
//
expect(find.byType(TimerWidget), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Side raises - log
//
expect(find.text('Side raises'), findsOneWidget);
expect(find.byType(LogPage), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Side raises - log
//
expect(find.text('Side raises'), findsOneWidget);
expect(find.byType(LogPage), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Side raises - timer
//
expect(find.byType(TimerWidget), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Side raises - timer
//
expect(find.byType(TimerWidget), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Session
//
expect(find.text('Workout session'), findsOneWidget);
expect(find.byType(SessionPage), findsOneWidget);
expect(find.byType(Form), findsOneWidget);
expect(find.byIcon(Icons.sentiment_very_dissatisfied), findsOneWidget);
expect(find.byIcon(Icons.sentiment_neutral), findsOneWidget);
expect(find.byIcon(Icons.sentiment_very_satisfied), findsOneWidget);
expect(
find.text(timeToString(TimeOfDay.now())!),
findsNWidgets(2),
reason: 'start and end time are the same',
);
final toggleButtons = tester.widget<ToggleButtons>(find.byType(ToggleButtons));
expect(toggleButtons.isSelected[1], isTrue);
expect(find.byIcon(Icons.chevron_left), findsOneWidget);
expect(find.byIcon(Icons.close), findsOneWidget);
expect(find.byIcon(Icons.chevron_right), findsNothing);
//
// Side raises - log
//
expect(find.text('Side raises'), findsOneWidget);
expect(find.byType(LogPage), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
//
// Side raises - timer
//
expect(find.byType(TimerWidget), findsOneWidget);
await tester.tap(find.byIcon(Icons.chevron_right));
await tester.pumpAndSettle();
//
// Session
//
expect(find.text('Workout session'), findsOneWidget);
expect(find.byType(SessionPage), findsOneWidget);
expect(find.byType(Form), findsOneWidget);
expect(find.byIcon(Icons.sentiment_very_dissatisfied), findsOneWidget);
expect(find.byIcon(Icons.sentiment_neutral), findsOneWidget);
expect(find.byIcon(Icons.sentiment_very_satisfied), findsOneWidget);
expect(
find.text('14:33'),
findsNWidgets(2),
reason: 'start and end time are the same',
);
final toggleButtons = tester.widget<ToggleButtons>(find.byType(ToggleButtons));
expect(toggleButtons.isSelected[1], isTrue);
expect(find.byIcon(Icons.chevron_left), findsOneWidget);
expect(find.byIcon(Icons.close), findsOneWidget);
expect(find.byIcon(Icons.chevron_right), findsNothing);
//
});
});
}