From ffe5867727bb1f18e6fa65976d9feddb58259882 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Fri, 24 Jan 2025 17:00:55 +0100 Subject: [PATCH] Add simple tests for SlotEntryForm --- test/workout/slot_entry_form_test.dart | 95 ++++ test/workout/slot_entry_form_test.mocks.dart | 489 +++++++++++++++++++ 2 files changed, 584 insertions(+) create mode 100644 test/workout/slot_entry_form_test.dart create mode 100644 test/workout/slot_entry_form_test.mocks.dart diff --git a/test/workout/slot_entry_form_test.dart b/test/workout/slot_entry_form_test.dart new file mode 100644 index 00000000..02f44ba7 --- /dev/null +++ b/test/workout/slot_entry_form_test.dart @@ -0,0 +1,95 @@ +/* + * This file is part of wger Workout Manager . + * Copyright (C) 2020, 2021 wger Team + * + * wger Workout Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * wger Workout Manager is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:provider/provider.dart'; +import 'package:wger/helpers/consts.dart'; +import 'package:wger/providers/routines.dart'; +import 'package:wger/widgets/routines/forms/reps_unit.dart'; +import 'package:wger/widgets/routines/forms/rir.dart'; +import 'package:wger/widgets/routines/forms/slot.dart'; +import 'package:wger/widgets/routines/forms/weight_unit.dart'; + +import '../../test_data/routines.dart'; +import './slot_entry_form_test.mocks.dart'; + +@GenerateMocks([RoutinesProvider]) +void main() { + var mockRoutinesProvider = MockRoutinesProvider(); + + final slotEntry = getTestRoutine().days[0].slots[0].entries[0]; + + setUp(() { + mockRoutinesProvider = MockRoutinesProvider(); + when(mockRoutinesProvider.weightUnits).thenReturn(testWeightUnits); + when(mockRoutinesProvider.findWeightUnitById(any)).thenReturn(testWeightUnit1); + when(mockRoutinesProvider.repetitionUnits).thenReturn(testRepetitionUnits); + when(mockRoutinesProvider.findRepetitionUnitById(any)).thenReturn(testRepetitionUnit1); + }); + + Widget renderWidget({simpleMode = true, locale = 'en'}) { + final key = GlobalKey(); + + return ChangeNotifierProvider( + create: (context) => mockRoutinesProvider, + child: MaterialApp( + locale: Locale(locale), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + navigatorKey: key, + home: Scaffold(body: SlotEntryForm(slotEntry, simpleMode: simpleMode)), + ), + ); + } + + testWidgets('Checks correct widgets are rendered in simple mode', (WidgetTester tester) async { + await tester.pumpWidget(renderWidget()); + await tester.pumpAndSettle(); + + expect(find.byType(TextFormField), findsNWidgets(2)); + expect(find.byType(Slider), findsOne); + expect(find.byType(WeightUnitInputWidget), findsNothing); + expect(find.byType(RepetitionUnitInputWidget), findsNothing); + expect(find.byType(RiRInputWidget), findsNothing); + }); + + testWidgets('Checks correct widgets are rendered in expanded mode', (WidgetTester tester) async { + await tester.pumpWidget(renderWidget(simpleMode: false)); + await tester.pumpAndSettle(); + + expect(find.byType(TextFormField), findsNWidgets(6)); + expect(find.byType(Slider), findsNWidgets(2)); + expect(find.byType(WeightUnitInputWidget), findsOne); + expect(find.byType(RepetitionUnitInputWidget), findsOne); + expect(find.byType(RiRInputWidget), findsOne); + }); + + testWidgets('Correctly updates the values on the server', (WidgetTester tester) async { + await tester.pumpWidget(renderWidget(simpleMode: true)); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(const Key(SUBMIT_BUTTON_KEY_NAME))); + await tester.pumpAndSettle(); + + verify(mockRoutinesProvider.editSlotEntry(any)).called(1); + verify(mockRoutinesProvider.handleConfig(any, any, any)).called(8); + }); +} diff --git a/test/workout/slot_entry_form_test.mocks.dart b/test/workout/slot_entry_form_test.mocks.dart new file mode 100644 index 00000000..78ac108c --- /dev/null +++ b/test/workout/slot_entry_form_test.mocks.dart @@ -0,0 +1,489 @@ +// Mocks generated by Mockito 5.4.5 from annotations +// in wger/test/workout/slot_entry_form_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i13; +import 'dart:ui' as _i17; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i16; +import 'package:wger/models/exercises/exercise.dart' as _i15; +import 'package:wger/models/workouts/base_config.dart' as _i9; +import 'package:wger/models/workouts/day.dart' as _i6; +import 'package:wger/models/workouts/day_data.dart' as _i14; +import 'package:wger/models/workouts/log.dart' as _i11; +import 'package:wger/models/workouts/repetition_unit.dart' as _i4; +import 'package:wger/models/workouts/routine.dart' as _i5; +import 'package:wger/models/workouts/session.dart' as _i10; +import 'package:wger/models/workouts/slot.dart' as _i7; +import 'package:wger/models/workouts/slot_entry.dart' as _i8; +import 'package:wger/models/workouts/weight_unit.dart' as _i3; +import 'package:wger/providers/base_provider.dart' as _i2; +import 'package:wger/providers/routines.dart' as _i12; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeWgerBaseProvider_0 extends _i1.SmartFake implements _i2.WgerBaseProvider { + _FakeWgerBaseProvider_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakeWeightUnit_1 extends _i1.SmartFake implements _i3.WeightUnit { + _FakeWeightUnit_1(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); +} + +class _FakeRepetitionUnit_2 extends _i1.SmartFake implements _i4.RepetitionUnit { + _FakeRepetitionUnit_2(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakeRoutine_3 extends _i1.SmartFake implements _i5.Routine { + _FakeRoutine_3(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); +} + +class _FakeDay_4 extends _i1.SmartFake implements _i6.Day { + _FakeDay_4(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); +} + +class _FakeSlot_5 extends _i1.SmartFake implements _i7.Slot { + _FakeSlot_5(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); +} + +class _FakeSlotEntry_6 extends _i1.SmartFake implements _i8.SlotEntry { + _FakeSlotEntry_6(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); +} + +class _FakeBaseConfig_7 extends _i1.SmartFake implements _i9.BaseConfig { + _FakeBaseConfig_7(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); +} + +class _FakeWorkoutSession_8 extends _i1.SmartFake implements _i10.WorkoutSession { + _FakeWorkoutSession_8(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakeLog_9 extends _i1.SmartFake implements _i11.Log { + _FakeLog_9(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); +} + +/// A class which mocks [RoutinesProvider]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockRoutinesProvider extends _i1.Mock implements _i12.RoutinesProvider { + MockRoutinesProvider() { + _i1.throwOnMissingStub(this); + } + + @override + _i2.WgerBaseProvider get baseProvider => (super.noSuchMethod( + Invocation.getter(#baseProvider), + returnValue: _FakeWgerBaseProvider_0( + this, + Invocation.getter(#baseProvider), + ), + ) as _i2.WgerBaseProvider); + + @override + List<_i5.Routine> get items => (super.noSuchMethod( + Invocation.getter(#items), + returnValue: <_i5.Routine>[], + ) as List<_i5.Routine>); + + @override + List<_i3.WeightUnit> get weightUnits => (super.noSuchMethod( + Invocation.getter(#weightUnits), + returnValue: <_i3.WeightUnit>[], + ) as List<_i3.WeightUnit>); + + @override + _i3.WeightUnit get defaultWeightUnit => (super.noSuchMethod( + Invocation.getter(#defaultWeightUnit), + returnValue: _FakeWeightUnit_1( + this, + Invocation.getter(#defaultWeightUnit), + ), + ) as _i3.WeightUnit); + + @override + List<_i4.RepetitionUnit> get repetitionUnits => (super.noSuchMethod( + Invocation.getter(#repetitionUnits), + returnValue: <_i4.RepetitionUnit>[], + ) as List<_i4.RepetitionUnit>); + + @override + _i4.RepetitionUnit get defaultRepetitionUnit => (super.noSuchMethod( + Invocation.getter(#defaultRepetitionUnit), + returnValue: _FakeRepetitionUnit_2( + this, + Invocation.getter(#defaultRepetitionUnit), + ), + ) as _i4.RepetitionUnit); + + @override + bool get hasListeners => + (super.noSuchMethod(Invocation.getter(#hasListeners), returnValue: false) as bool); + + @override + void clear() => super.noSuchMethod( + Invocation.method(#clear, []), + returnValueForMissingStub: null, + ); + + @override + _i3.WeightUnit findWeightUnitById(int? id) => (super.noSuchMethod( + Invocation.method(#findWeightUnitById, [id]), + returnValue: _FakeWeightUnit_1( + this, + Invocation.method(#findWeightUnitById, [id]), + ), + ) as _i3.WeightUnit); + + @override + _i4.RepetitionUnit findRepetitionUnitById(int? id) => (super.noSuchMethod( + Invocation.method(#findRepetitionUnitById, [id]), + returnValue: _FakeRepetitionUnit_2( + this, + Invocation.method(#findRepetitionUnitById, [id]), + ), + ) as _i4.RepetitionUnit); + + @override + List<_i5.Routine> getPlans() => (super.noSuchMethod( + Invocation.method(#getPlans, []), + returnValue: <_i5.Routine>[], + ) as List<_i5.Routine>); + + @override + _i5.Routine findById(int? id) => (super.noSuchMethod( + Invocation.method(#findById, [id]), + returnValue: _FakeRoutine_3( + this, + Invocation.method(#findById, [id]), + ), + ) as _i5.Routine); + + @override + int findIndexById(int? id) => (super.noSuchMethod( + Invocation.method(#findIndexById, [id]), + returnValue: 0, + ) as int); + + @override + void setCurrentPlan(int? id) => super.noSuchMethod( + Invocation.method(#setCurrentPlan, [id]), + returnValueForMissingStub: null, + ); + + @override + void resetCurrentRoutine() => super.noSuchMethod( + Invocation.method(#resetCurrentRoutine, []), + returnValueForMissingStub: null, + ); + + @override + _i13.Future fetchAndSetAllRoutinesFull() => (super.noSuchMethod( + Invocation.method(#fetchAndSetAllRoutinesFull, []), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future fetchAndSetAllPlansSparse() => (super.noSuchMethod( + Invocation.method(#fetchAndSetAllPlansSparse, []), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + void setExercisesAndUnits(List<_i14.DayData>? entries) => super.noSuchMethod( + Invocation.method(#setExercisesAndUnits, [entries]), + returnValueForMissingStub: null, + ); + + @override + _i13.Future<_i5.Routine> fetchAndSetRoutineSparse(int? planId) => (super.noSuchMethod( + Invocation.method(#fetchAndSetRoutineSparse, [planId]), + returnValue: _i13.Future<_i5.Routine>.value( + _FakeRoutine_3( + this, + Invocation.method(#fetchAndSetRoutineSparse, [planId]), + ), + ), + ) as _i13.Future<_i5.Routine>); + + @override + _i13.Future<_i5.Routine> fetchAndSetRoutineFull(int? routineId) => (super.noSuchMethod( + Invocation.method(#fetchAndSetRoutineFull, [routineId]), + returnValue: _i13.Future<_i5.Routine>.value( + _FakeRoutine_3( + this, + Invocation.method(#fetchAndSetRoutineFull, [routineId]), + ), + ), + ) as _i13.Future<_i5.Routine>); + + @override + _i13.Future<_i5.Routine> addRoutine(_i5.Routine? routine) => (super.noSuchMethod( + Invocation.method(#addRoutine, [routine]), + returnValue: _i13.Future<_i5.Routine>.value( + _FakeRoutine_3(this, Invocation.method(#addRoutine, [routine])), + ), + ) as _i13.Future<_i5.Routine>); + + @override + _i13.Future editRoutine(_i5.Routine? routine) => (super.noSuchMethod( + Invocation.method(#editRoutine, [routine]), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future deleteRoutine(int? id) => (super.noSuchMethod( + Invocation.method(#deleteRoutine, [id]), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future> fetchLogData( + _i5.Routine? workout, + _i15.Exercise? base, + ) => + (super.noSuchMethod( + Invocation.method(#fetchLogData, [workout, base]), + returnValue: _i13.Future>.value( + {}, + ), + ) as _i13.Future>); + + @override + _i13.Future fetchAndSetRepetitionUnits() => (super.noSuchMethod( + Invocation.method(#fetchAndSetRepetitionUnits, []), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future fetchAndSetWeightUnits() => (super.noSuchMethod( + Invocation.method(#fetchAndSetWeightUnits, []), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future fetchAndSetUnits() => (super.noSuchMethod( + Invocation.method(#fetchAndSetUnits, []), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future<_i6.Day> addDay(_i6.Day? day, {dynamic refresh = false}) => (super.noSuchMethod( + Invocation.method(#addDay, [day], {#refresh: refresh}), + returnValue: _i13.Future<_i6.Day>.value( + _FakeDay_4( + this, + Invocation.method(#addDay, [day], {#refresh: refresh}), + ), + ), + ) as _i13.Future<_i6.Day>); + + @override + _i13.Future editDay(_i6.Day? day) => (super.noSuchMethod( + Invocation.method(#editDay, [day]), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future editDays(List<_i6.Day>? days) => (super.noSuchMethod( + Invocation.method(#editDays, [days]), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future deleteDay(int? dayId) => (super.noSuchMethod( + Invocation.method(#deleteDay, [dayId]), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future<_i7.Slot> addSlot(_i7.Slot? slot) => (super.noSuchMethod( + Invocation.method(#addSlot, [slot]), + returnValue: _i13.Future<_i7.Slot>.value( + _FakeSlot_5(this, Invocation.method(#addSlot, [slot])), + ), + ) as _i13.Future<_i7.Slot>); + + @override + _i13.Future deleteSlot(int? slotId) => (super.noSuchMethod( + Invocation.method(#deleteSlot, [slotId]), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future editSlot(_i7.Slot? slot) => (super.noSuchMethod( + Invocation.method(#editSlot, [slot]), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future editSlots(List<_i7.Slot>? slots) => (super.noSuchMethod( + Invocation.method(#editSlots, [slots]), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future<_i8.SlotEntry> addSlotEntry(_i8.SlotEntry? entry) => (super.noSuchMethod( + Invocation.method(#addSlotEntry, [entry]), + returnValue: _i13.Future<_i8.SlotEntry>.value( + _FakeSlotEntry_6(this, Invocation.method(#addSlotEntry, [entry])), + ), + ) as _i13.Future<_i8.SlotEntry>); + + @override + _i13.Future deleteSlotEntry(int? id) => (super.noSuchMethod( + Invocation.method(#deleteSlotEntry, [id]), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future editSlotEntry(_i8.SlotEntry? entry) => (super.noSuchMethod( + Invocation.method(#editSlotEntry, [entry]), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + String getConfigUrl(_i8.ConfigType? type) => (super.noSuchMethod( + Invocation.method(#getConfigUrl, [type]), + returnValue: _i16.dummyValue( + this, + Invocation.method(#getConfigUrl, [type]), + ), + ) as String); + + @override + _i13.Future<_i9.BaseConfig> editConfig( + _i9.BaseConfig? config, + _i8.ConfigType? type, + ) => + (super.noSuchMethod( + Invocation.method(#editConfig, [config, type]), + returnValue: _i13.Future<_i9.BaseConfig>.value( + _FakeBaseConfig_7( + this, + Invocation.method(#editConfig, [config, type]), + ), + ), + ) as _i13.Future<_i9.BaseConfig>); + + @override + _i13.Future<_i9.BaseConfig> addConfig( + _i9.BaseConfig? config, + _i8.ConfigType? type, + ) => + (super.noSuchMethod( + Invocation.method(#addConfig, [config, type]), + returnValue: _i13.Future<_i9.BaseConfig>.value( + _FakeBaseConfig_7( + this, + Invocation.method(#addConfig, [config, type]), + ), + ), + ) as _i13.Future<_i9.BaseConfig>); + + @override + _i13.Future deleteConfig(int? id, _i8.ConfigType? type) => (super.noSuchMethod( + Invocation.method(#deleteConfig, [id, type]), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future handleConfig( + _i8.SlotEntry? entry, + String? input, + _i8.ConfigType? type, + ) => + (super.noSuchMethod( + Invocation.method(#handleConfig, [entry, input, type]), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future fetchSessionData() => (super.noSuchMethod( + Invocation.method(#fetchSessionData, []), + returnValue: _i13.Future.value(), + ) as _i13.Future); + + @override + _i13.Future<_i10.WorkoutSession> addSession(_i10.WorkoutSession? session) => (super.noSuchMethod( + Invocation.method(#addSession, [session]), + returnValue: _i13.Future<_i10.WorkoutSession>.value( + _FakeWorkoutSession_8( + this, + Invocation.method(#addSession, [session]), + ), + ), + ) as _i13.Future<_i10.WorkoutSession>); + + @override + _i13.Future<_i11.Log> addLog(_i11.Log? log) => (super.noSuchMethod( + Invocation.method(#addLog, [log]), + returnValue: _i13.Future<_i11.Log>.value( + _FakeLog_9(this, Invocation.method(#addLog, [log])), + ), + ) as _i13.Future<_i11.Log>); + + @override + _i13.Future deleteLog(_i11.Log? log) => (super.noSuchMethod( + Invocation.method(#deleteLog, [log]), + returnValue: _i13.Future.value(), + returnValueForMissingStub: _i13.Future.value(), + ) as _i13.Future); + + @override + void addListener(_i17.VoidCallback? listener) => super.noSuchMethod( + Invocation.method(#addListener, [listener]), + returnValueForMissingStub: null, + ); + + @override + void removeListener(_i17.VoidCallback? listener) => super.noSuchMethod( + Invocation.method(#removeListener, [listener]), + returnValueForMissingStub: null, + ); + + @override + void dispose() => super.noSuchMethod( + Invocation.method(#dispose, []), + returnValueForMissingStub: null, + ); + + @override + void notifyListeners() => super.noSuchMethod( + Invocation.method(#notifyListeners, []), + returnValueForMissingStub: null, + ); +}