Start working on automatic screenshot generation

This commit is contained in:
Roland Geider
2022-04-11 17:50:08 +02:00
parent a6338ab6d6
commit 826810f17a
11 changed files with 553 additions and 223 deletions

View File

@@ -0,0 +1,8 @@
Start emulator and run
`flutter drive --driver=test_driver/screenshot_driver.dart --target=integration_test/app_test.dart`
See
* <https://github.com/openfoodfacts/smooth-app/issues/217#issuecomment-1092678779>
* <https://dev.to/mjablecnik/take-screenshot-during-flutter-integration-tests-435k>

View File

@@ -0,0 +1,434 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart';
import 'package:wger/models/body_weight/weight_entry.dart';
import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/models/nutrition/ingredient.dart';
import 'package:wger/models/nutrition/log.dart';
import 'package:wger/models/nutrition/meal.dart';
import 'package:wger/models/nutrition/meal_item.dart';
import 'package:wger/models/nutrition/nutritional_plan.dart';
import 'package:wger/models/workouts/day.dart';
import 'package:wger/models/workouts/set.dart';
import 'package:wger/models/workouts/setting.dart';
import 'package:wger/models/workouts/workout_plan.dart';
import 'package:wger/providers/body_weight.dart';
import 'package:wger/providers/exercises.dart';
import 'package:wger/providers/nutrition.dart';
import 'package:wger/providers/workout_plans.dart';
import 'package:wger/screens/form_screen.dart';
import 'package:wger/screens/gym_mode.dart';
import 'package:wger/screens/nutritional_plan_screen.dart';
import 'package:wger/screens/weight_screen.dart';
import 'package:wger/screens/workout_plan_screen.dart';
import 'package:wger/theme/theme.dart';
import '../test/other/base_provider_test.mocks.dart';
import '../test/utils.dart';
import '../test/workout/gym_mode_screen_test.mocks.dart';
import '../test_data/exercises.dart';
import '../test_data/workouts.dart';
Future<void> takeScreenshot(tester, binding, name) async {
if (Platform.isAndroid) {
await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle();
}
await binding.takeScreenshot(name);
}
// Languages for which the translations are almost complete in weblate
const languages = ['de', 'en', 'es', 'it', 'jp', 'ca', 'pt', 'ru', 'tr', 'zh', 'fr', 'he'];
void main() {
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
Widget createNutritionalPlanScreen({locale = 'en'}) {
final key = GlobalKey<NavigatorState>();
final client = MockClient();
final muesli = Ingredient(
id: 1,
code: '123456787',
name: 'Müsli',
creationDate: DateTime(2021, 5, 1),
energy: 500,
carbohydrates: 10,
carbohydratesSugar: 2,
protein: 5,
fat: 20,
fatSaturated: 7,
fibres: 12,
sodium: 0.5,
);
final milk = Ingredient(
id: 1,
code: '123456787',
name: 'Milk',
creationDate: DateTime(2021, 5, 1),
energy: 500,
carbohydrates: 10,
carbohydratesSugar: 2,
protein: 5,
fat: 20,
fatSaturated: 7,
fibres: 12,
sodium: 0.5,
);
final apple = Ingredient(
id: 1,
code: '123456787',
name: 'Apple',
creationDate: DateTime(2021, 5, 1),
energy: 500,
carbohydrates: 10,
carbohydratesSugar: 2,
protein: 5,
fat: 20,
fatSaturated: 7,
fibres: 12,
sodium: 0.5,
);
final mealItem1 = MealItem(ingredientId: 1, amount: 100, ingredient: muesli);
final mealItem2 = MealItem(ingredientId: 2, amount: 75, ingredient: milk);
final mealItem3 = MealItem(ingredientId: 3, amount: 100, ingredient: apple);
final meal1 = Meal(
id: 1,
plan: 1,
time: const TimeOfDay(hour: 8, minute: 30),
name: 'Breakfast',
mealItems: [mealItem1, mealItem2],
);
final meal2 = Meal(
id: 2,
plan: 1,
time: const TimeOfDay(hour: 11, minute: 0),
name: 'Snack 1',
mealItems: [mealItem3],
);
final NutritionalPlan plan = NutritionalPlan(
id: 1,
description: 'Mini diet',
creationDate: DateTime(2021, 5, 23),
meals: [meal1, meal2],
);
// Add logs
plan.logs.add(Log.fromMealItem(mealItem1, 1, 1, DateTime(2021, 6, 1)));
plan.logs.add(Log.fromMealItem(mealItem2, 1, 1, DateTime(2021, 6, 1)));
plan.logs.add(Log.fromMealItem(mealItem3, 1, 1, DateTime(2021, 6, 10)));
return MultiProvider(
providers: [
ChangeNotifierProvider<NutritionPlansProvider>(
create: (context) => NutritionPlansProvider(testAuthProvider, [], client),
),
ChangeNotifierProvider<BodyWeightProvider>(
create: (context) => BodyWeightProvider(testAuthProvider, [], client),
),
],
child: MaterialApp(
locale: Locale(locale),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
theme: wgerTheme,
navigatorKey: key,
home: TextButton(
onPressed: () => key.currentState!.push(
MaterialPageRoute<void>(
settings: RouteSettings(arguments: plan),
builder: (_) => NutritionalPlanScreen(),
),
),
child: const SizedBox(),
),
),
);
}
Widget createWeightScreen({locale = 'en'}) {
return ChangeNotifierProvider<BodyWeightProvider>(
create: (context) => BodyWeightProvider(
testAuthProvider,
[
WeightEntry(id: 1, weight: 86, date: DateTime(2021, 01, 01)),
WeightEntry(id: 2, weight: 81, date: DateTime(2021, 01, 10)),
WeightEntry(id: 3, weight: 82, date: DateTime(2021, 01, 20)),
WeightEntry(id: 4, weight: 83, date: DateTime(2021, 01, 30)),
WeightEntry(id: 5, weight: 86, date: DateTime(2021, 02, 20)),
WeightEntry(id: 6, weight: 90, date: DateTime(2021, 02, 28)),
WeightEntry(id: 7, weight: 91, date: DateTime(2021, 03, 20)),
WeightEntry(id: 8, weight: 91.1, date: DateTime(2021, 03, 30)),
WeightEntry(id: 9, weight: 90, date: DateTime(2021, 05, 1)),
WeightEntry(id: 10, weight: 91, date: DateTime(2021, 6, 5)),
WeightEntry(id: 11, weight: 89, date: DateTime(2021, 6, 20)),
WeightEntry(id: 12, weight: 88, date: DateTime(2021, 7, 15)),
WeightEntry(id: 13, weight: 86, date: DateTime(2021, 7, 20)),
WeightEntry(id: 14, weight: 83, date: DateTime(2021, 7, 30)),
WeightEntry(id: 15, weight: 80, date: DateTime(2021, 8, 10))
],
MockClient(),
),
child: MaterialApp(
locale: Locale(locale),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
theme: wgerTheme,
home: WeightScreen(),
routes: {
FormScreen.routeName: (ctx) => FormScreen(),
},
),
);
}
Widget createGymModeScreen({locale = 'en'}) {
final key = GlobalKey<NavigatorState>();
final client = MockClient();
final squats = Exercise(
id: 1,
uuid: 'uuid',
creationDate: DateTime(2021, 1, 15),
name: 'Squats',
description: 'add clever text',
base: tBase1,
language: tLanguage1,
);
final benchPress = Exercise(
id: 1,
uuid: 'uuid',
creationDate: DateTime(2021, 1, 15),
name: 'Bench press',
description: 'add clever text',
base: tBase1,
language: tLanguage1,
);
final deadLift = Exercise(
id: 1,
uuid: 'uuid',
creationDate: DateTime(2021, 1, 15),
name: 'deadLift',
description: 'add clever text',
base: tBase1,
language: tLanguage1,
);
final crunches = Exercise(
id: 1,
uuid: 'uuid',
creationDate: DateTime(2021, 1, 15),
name: 'Crunches',
description: 'add clever text',
base: tBase1,
language: tLanguage1,
);
final mockExerciseProvider = MockExercisesProvider();
when(mockExerciseProvider.findExerciseById(1)).thenReturn(squats);
when(mockExerciseProvider.findExerciseById(2)).thenReturn(benchPress);
when(mockExerciseProvider.findExerciseById(3)).thenReturn(crunches);
final setting1 = Setting(
setId: 1,
order: 1,
exerciseId: 1,
repetitionUnitId: 1,
reps: 5,
weightUnitId: 1,
comment: 'ddd',
rir: '2',
);
setting1.repetitionUnit = repetitionUnit1;
setting1.weightUnit = weightUnit1;
setting1.exercise = squats;
setting1.weight = 100;
final setting2 = Setting(
setId: 1,
order: 1,
exerciseId: 2,
repetitionUnitId: 1,
reps: 6,
weightUnitId: 1,
comment: 'ddd',
rir: '1.5',
);
setting2.repetitionUnit = repetitionUnit1;
setting2.weightUnit = weightUnit1;
setting2.exercise = benchPress;
setting2.weight = 80;
final setting2b = Setting(
setId: 1,
order: 1,
exerciseId: 2,
repetitionUnitId: 1,
reps: 8,
weightUnitId: 1,
comment: 'ddd',
rir: '2',
);
setting2b.repetitionUnit = repetitionUnit1;
setting2b.weightUnit = weightUnit1;
setting2b.exercise = benchPress;
setting2b.weight = 60;
final setting3 = Setting(
setId: 1,
order: 1,
exerciseId: 2,
repetitionUnitId: 1,
reps: 20,
weightUnitId: 1,
comment: '',
rir: null,
);
setting3.repetitionUnit = repetitionUnit1;
setting3.weightUnit = weightUnit1;
setting3.exercise = crunches;
final setting4 = Setting(
setId: 1,
order: 1,
exerciseId: 2,
repetitionUnitId: 1,
reps: 8,
weightUnitId: 1,
comment: '',
rir: null,
);
setting4.repetitionUnit = repetitionUnit1;
setting4.weightUnit = weightUnit1;
setting4.exercise = deadLift;
setting4.weight = 120;
final set1 = Set.withData(
id: 1,
day: 1,
sets: 3,
order: 1,
);
set1.addExercise(squats);
set1.settings.add(setting1);
set1.settings.add(setting1);
set1.settings.add(setting1);
set1.settings.add(setting1);
final set2 = Set.withData(
id: 2,
day: 1,
sets: 3,
order: 1,
);
set2.addExercise(benchPress);
set2.settings.add(setting2);
set2.settings.add(setting2);
set2.settings.add(setting2b);
set2.settings.add(setting2b);
final set3 = Set.withData(
id: 3,
day: 1,
sets: 3,
order: 1,
);
set3.addExercise(crunches);
set3.settings.add(setting3);
final set4 = Set.withData(
id: 4,
day: 1,
sets: 3,
order: 1,
);
set4.addExercise(deadLift);
set4.settings.add(setting4);
set4.settings.add(setting4);
set4.settings.add(setting4);
set4.settings.add(setting4);
final day1 = Day()
..id = 1
..workoutId = 1
..description = 'test day 1'
..daysOfWeek = [1, 2];
day1.sets.add(set1);
day1.sets.add(set2);
day1.sets.add(set4);
day1.sets.add(set3);
final workout = WorkoutPlan(
id: 1,
creationDate: DateTime(2021, 01, 01),
name: 'test workout 1',
days: [day1],
);
return ChangeNotifierProvider<WorkoutPlansProvider>(
create: (context) => WorkoutPlansProvider(
testAuthProvider,
mockExerciseProvider,
[workout],
client,
),
child: ChangeNotifierProvider<ExercisesProvider>(
create: (context) => mockExerciseProvider,
child: MaterialApp(
locale: Locale(locale),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
navigatorKey: key,
theme: wgerTheme,
home: TextButton(
onPressed: () => key.currentState!.push(
MaterialPageRoute<void>(
settings: RouteSettings(arguments: workout.days.first),
builder: (_) => GymModeScreen(),
),
),
child: const SizedBox(),
),
routes: {
WorkoutPlanScreen.routeName: (ctx) => WorkoutPlanScreen(),
},
),
),
);
}
group('Generate screenshots', () {
for (final language in languages) {
testWidgets('nutritional plan detail - $language', (WidgetTester tester) async {
await tester.pumpWidget(createNutritionalPlanScreen(locale: language));
await tester.tap(find.byType(TextButton));
await tester.pumpAndSettle();
await takeScreenshot(tester, binding, '$language/03-nutritional-plan');
});
testWidgets('body weight screen - $language', (WidgetTester tester) async {
await tester.pumpWidget(createWeightScreen(locale: language));
await tester.pumpAndSettle();
await takeScreenshot(tester, binding, '$language/05-weight');
});
testWidgets('gym mode screen - $language', (WidgetTester tester) async {
await tester.pumpWidget(createGymModeScreen(locale: language));
await tester.tap(find.byType(TextButton));
await tester.pumpAndSettle();
await takeScreenshot(tester, binding, '$language/05-gym-mode');
});
}
});
}

View File

@@ -53,10 +53,15 @@ class MealItem {
required this.ingredientId,
this.weightUnitId,
required this.amount,
Ingredient? ingredient,
}) {
if (mealId != null) {
this.mealId = mealId;
}
if (ingredient != null) {
ingredientObj = ingredient;
ingredientId = ingredient.id;
}
}
MealItem.empty();

View File

@@ -270,8 +270,8 @@ class MuscleRowWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
//mainAxisAlignment: MainAxisAlignment.spaceAround,
//crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Padding(

View File

@@ -7,14 +7,14 @@ packages:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "34.0.0"
version: "38.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.0"
version: "3.4.1"
android_metadata:
dependency: "direct main"
description:
@@ -28,7 +28,7 @@ packages:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.1"
version: "3.1.6"
args:
dependency: transitive
description:
@@ -112,7 +112,7 @@ packages:
name: camera
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.4+17"
version: "0.9.4+19"
camera_platform_interface:
dependency: transitive
description:
@@ -175,7 +175,7 @@ packages:
name: chewie
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.3.1"
chewie_audio:
dependency: transitive
description:
@@ -190,13 +190,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1"
cli_util:
dependency: transitive
description:
name: cli_util
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.5"
clock:
dependency: transitive
description:
@@ -259,7 +252,7 @@ packages:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
version: "2.2.2"
equatable:
dependency: "direct main"
description:
@@ -314,6 +307,11 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
flutter_driver:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
flutter_html:
dependency: "direct main"
description:
@@ -355,7 +353,7 @@ packages:
name: flutter_layout_grid
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
version: "1.0.6"
flutter_lints:
dependency: "direct dev"
description:
@@ -420,6 +418,11 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
glob:
dependency: transitive
description:
@@ -475,6 +478,13 @@ packages:
name: image_picker
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.5"
image_picker_android:
dependency: transitive
description:
name: image_picker_android
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.4+11"
image_picker_for_web:
dependency: transitive
@@ -483,6 +493,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.6"
image_picker_ios:
dependency: transitive
description:
name: image_picker_ios
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.4+11"
image_picker_platform_interface:
dependency: transitive
description:
@@ -490,6 +507,11 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.4"
integration_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
intl:
dependency: "direct main"
description:
@@ -727,7 +749,7 @@ packages:
name: pub_semver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.1"
pubspec_parse:
dependency: transitive
description:
@@ -748,14 +770,14 @@ packages:
name: rfc_6901
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
version: "0.1.1"
rive:
dependency: "direct main"
description:
name: rive
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.1"
version: "0.8.4"
shared_preferences:
dependency: "direct main"
description:
@@ -818,7 +840,7 @@ packages:
name: shelf
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.3.0"
shelf_web_socket:
dependency: transitive
description:
@@ -887,6 +909,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
sync_http:
dependency: transitive
description:
name: sync_http
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
table_calendar:
dependency: "direct main"
description:
@@ -977,7 +1006,7 @@ packages:
name: url_launcher_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.6"
version: "2.0.9"
url_launcher_windows:
dependency: transitive
description:
@@ -1026,21 +1055,21 @@ packages:
name: video_player_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.0"
version: "2.3.2"
video_player_avfoundation:
dependency: transitive
description:
name: video_player_avfoundation
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.0"
version: "2.3.1"
video_player_platform_interface:
dependency: transitive
description:
name: video_player_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.0"
version: "5.1.1"
video_player_web:
dependency: transitive
description:
@@ -1048,13 +1077,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.7"
vm_service:
dependency: transitive
description:
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
version: "7.5.0"
wakelock:
dependency: transitive
description:
name: wakelock
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.1+1"
version: "0.6.1+2"
wakelock_macos:
dependency: transitive
description:
@@ -1097,6 +1133,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
webdriver:
dependency: transitive
description:
name: webdriver
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
webview_flutter:
dependency: transitive
description:
@@ -1110,7 +1153,7 @@ packages:
name: webview_flutter_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.3"
version: "2.8.5"
webview_flutter_platform_interface:
dependency: transitive
description:
@@ -1124,14 +1167,14 @@ packages:
name: webview_flutter_wkwebview
url: "https://pub.dartlang.org"
source: hosted
version: "2.7.1"
version: "2.7.2"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.1"
version: "2.5.1"
xdg_directories:
dependency: transitive
description:
@@ -1154,5 +1197,5 @@ packages:
source: hosted
version: "3.1.0"
sdks:
dart: ">=2.15.1 <3.0.0"
flutter: ">=2.8.0"
dart: ">=2.16.0 <3.0.0"
flutter: ">=2.10.0"

View File

@@ -60,8 +60,8 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
#flutter_driver:
# sdk: flutter
integration_test:
sdk: flutter
build_runner: ^2.1.2
flutter_launcher_icons: ^0.9.1
json_serializable: ^6.1.5

View File

@@ -24,7 +24,7 @@ import 'package:wger/providers/exercises.dart';
import 'package:wger/widgets/exercises/exercises.dart';
import '../../test_data/exercises.dart';
import '../gym_mode_screen_test.mocks.dart';
import '../workout/gym_mode_screen_test.mocks.dart';
void main() {
final mockProvider = MockExercisesProvider();

View File

@@ -1,184 +0,0 @@
// Mocks generated by Mockito 5.0.15 from annotations
// in wger/test/gym_mode_screen_test.dart.
// Do not manually edit this file.
import 'dart:async' as _i9;
import 'dart:ui' as _i11;
import 'package:mockito/mockito.dart' as _i1;
import 'package:wger/models/exercises/base.dart' as _i10;
import 'package:wger/models/exercises/category.dart' as _i4;
import 'package:wger/models/exercises/equipment.dart' as _i5;
import 'package:wger/models/exercises/exercise.dart' as _i3;
import 'package:wger/models/exercises/language.dart' as _i7;
import 'package:wger/models/exercises/muscle.dart' as _i6;
import 'package:wger/providers/base_provider.dart' as _i2;
import 'package:wger/providers/exercises.dart' as _i8;
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
class _FakeWgerBaseProvider_0 extends _i1.Fake implements _i2.WgerBaseProvider {}
class _FakeExercise_1 extends _i1.Fake implements _i3.Exercise {}
class _FakeExerciseCategory_2 extends _i1.Fake implements _i4.ExerciseCategory {}
class _FakeEquipment_3 extends _i1.Fake implements _i5.Equipment {}
class _FakeMuscle_4 extends _i1.Fake implements _i6.Muscle {}
class _FakeLanguage_5 extends _i1.Fake implements _i7.Language {}
/// A class which mocks [ExercisesProvider].
///
/// See the documentation for Mockito's code generation for more information.
class MockExercisesProvider extends _i1.Mock implements _i8.ExercisesProvider {
MockExercisesProvider() {
_i1.throwOnMissingStub(this);
}
@override
_i2.WgerBaseProvider get baseProvider =>
(super.noSuchMethod(Invocation.getter(#baseProvider), returnValue: _FakeWgerBaseProvider_0())
as _i2.WgerBaseProvider);
@override
set exercises(List<_i3.Exercise>? exercises) =>
super.noSuchMethod(Invocation.setter(#exercises, exercises), returnValueForMissingStub: null);
@override
set filteredExerciseBases(List<_i3.Exercise>? newfilteredExercises) =>
super.noSuchMethod(Invocation.setter(#filteredExercises, newfilteredExercises),
returnValueForMissingStub: null);
@override
List<_i3.Exercise> get items =>
(super.noSuchMethod(Invocation.getter(#items), returnValue: <_i3.Exercise>[])
as List<_i3.Exercise>);
@override
List<_i4.ExerciseCategory> get categories =>
(super.noSuchMethod(Invocation.getter(#categories), returnValue: <_i4.ExerciseCategory>[])
as List<_i4.ExerciseCategory>);
@override
bool get hasListeners =>
(super.noSuchMethod(Invocation.getter(#hasListeners), returnValue: false) as bool);
@override
_i9.Future<void> setFilters(_i8.Filters? newFilters) =>
(super.noSuchMethod(Invocation.method(#setFilters, [newFilters]),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
@override
_i9.Future<void> findByFilters() => (super.noSuchMethod(Invocation.method(#findByFilters, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
@override
List<_i3.Exercise> findByCategory(_i4.ExerciseCategory? category) =>
(super.noSuchMethod(Invocation.method(#findByCategory, [category]),
returnValue: <_i3.Exercise>[]) as List<_i3.Exercise>);
@override
_i3.Exercise findExerciseById(int? id) => (super
.noSuchMethod(Invocation.method(#findExerciseById, [id]), returnValue: _FakeExercise_1())
as _i3.Exercise);
@override
_i4.ExerciseCategory findCategoryById(int? id) =>
(super.noSuchMethod(Invocation.method(#findCategoryById, [id]),
returnValue: _FakeExerciseCategory_2()) as _i4.ExerciseCategory);
@override
_i5.Equipment findEquipmentById(int? id) =>
(super.noSuchMethod(Invocation.method(#findEquipmentById, [id]),
returnValue: _FakeEquipment_3()) as _i5.Equipment);
@override
_i6.Muscle findMuscleById(int? id) =>
(super.noSuchMethod(Invocation.method(#findMuscleById, [id]), returnValue: _FakeMuscle_4())
as _i6.Muscle);
@override
_i7.Language findLanguageById(int? id) => (super
.noSuchMethod(Invocation.method(#findLanguageById, [id]), returnValue: _FakeLanguage_5())
as _i7.Language);
@override
_i9.Future<void> fetchAndSetCategories() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetCategories, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
@override
_i9.Future<void> fetchAndSetVariations() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetVariations, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
@override
_i9.Future<void> fetchAndSetMuscles() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetMuscles, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
@override
_i9.Future<void> fetchAndSetEquipment() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetEquipment, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
@override
_i9.Future<void> fetchAndSetLanguages() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetLanguages, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
@override
_i9.Future<_i3.Exercise> fetchAndSetExercise(int? exerciseId) =>
(super.noSuchMethod(Invocation.method(#fetchAndSetExercise, [exerciseId]),
returnValue: Future<_i3.Exercise>.value(_FakeExercise_1())) as _i9.Future<_i3.Exercise>);
@override
List<_i10.ExerciseBase> mapImages(dynamic data, List<_i10.ExerciseBase>? bases) =>
(super.noSuchMethod(Invocation.method(#mapImages, [data, bases]),
returnValue: <_i10.ExerciseBase>[]) as List<_i10.ExerciseBase>);
@override
List<_i10.ExerciseBase> setBaseData(dynamic data, List<_i3.Exercise>? exercises) =>
(super.noSuchMethod(Invocation.method(#setBaseData, [data, exercises]),
returnValue: <_i10.ExerciseBase>[]) as List<_i10.ExerciseBase>);
@override
List<dynamic> mapBases(List<_i10.ExerciseBase>? bases, List<_i3.Exercise>? exercises) => (super
.noSuchMethod(Invocation.method(#mapBases, [bases, exercises]), returnValue: <dynamic>[])
as List<dynamic>);
@override
List<_i3.Exercise> mapLanguages(List<_i3.Exercise>? exercises) =>
(super.noSuchMethod(Invocation.method(#mapLanguages, [exercises]),
returnValue: <_i3.Exercise>[]) as List<_i3.Exercise>);
@override
List<_i3.Exercise> mapAliases(dynamic data, List<_i3.Exercise>? exercises) =>
(super.noSuchMethod(Invocation.method(#mapAliases, [data, exercises]),
returnValue: <_i3.Exercise>[]) as List<_i3.Exercise>);
@override
List<_i3.Exercise> mapComments(dynamic data, List<_i3.Exercise>? exercises) =>
(super.noSuchMethod(Invocation.method(#mapComments, [data, exercises]),
returnValue: <_i3.Exercise>[]) as List<_i3.Exercise>);
@override
_i9.Future<void> checkExerciseCacheVersion() =>
(super.noSuchMethod(Invocation.method(#checkExerciseCacheVersion, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
@override
_i9.Future<void> fetchAndSetExercises() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetExercises, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
@override
_i9.Future<List<_i3.Exercise>> searchExercise(String? name, [String? languageCode = r'en']) =>
(super.noSuchMethod(Invocation.method(#searchExercise, [name, languageCode]),
returnValue: Future<List<_i3.Exercise>>.value(<_i3.Exercise>[]))
as _i9.Future<List<_i3.Exercise>>);
@override
String toString() => super.toString();
@override
void addListener(_i11.VoidCallback? listener) => super
.noSuchMethod(Invocation.method(#addListener, [listener]), returnValueForMissingStub: null);
@override
void removeListener(_i11.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);
}

View File

@@ -69,6 +69,11 @@ class MockExercisesProvider extends _i1.Mock implements _i8.ExercisesProvider {
Invocation.setter(#filteredExerciseBases, newFilteredExercises),
returnValueForMissingStub: null);
@override
Map<int, List<_i9.ExerciseBase>> get exerciseBasesByVariation =>
(super.noSuchMethod(Invocation.getter(#exerciseBasesByVariation),
returnValue: <int, List<_i9.ExerciseBase>>{})
as Map<int, List<_i9.ExerciseBase>>);
@override
List<_i3.Exercise> get items => (super.noSuchMethod(Invocation.getter(#items),
returnValue: <_i3.Exercise>[]) as List<_i3.Exercise>);
@override

View File

@@ -20,8 +20,12 @@ import 'package:wger/models/exercises/base.dart';
import 'package:wger/models/exercises/category.dart';
import 'package:wger/models/exercises/equipment.dart';
import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/models/exercises/language.dart';
import 'package:wger/models/exercises/muscle.dart';
const tLanguage1 = Language(id: 1, shortName: 'de', fullName: 'Deutsch');
const tLanguage2 = Language(id: 2, shortName: 'en', fullName: 'English');
const tMuscle1 = Muscle(id: 1, name: 'Flutterus maximus', isFront: true);
const tMuscle2 = Muscle(id: 2, name: 'Biceps', isFront: true);
const tMuscle3 = Muscle(id: 3, name: 'Booty', isFront: false);
@@ -70,35 +74,32 @@ final tBase3 = ExerciseBase(
final tExercise1 = Exercise(
id: 1,
baseId: 1,
uuid: 'uuid',
languageId: 1,
creationDate: DateTime(2021, 1, 15),
name: 'test exercise 1',
description: 'add clever text',
base: tBase1,
language: tLanguage1,
);
final tExercise2 = Exercise(
id: 2,
baseId: 2,
uuid: '111-2222-44444',
languageId: 2,
creationDate: DateTime(2021, 1, 15),
name: 'test exercise 2',
description: 'Lorem ipsum etc',
base: tBase2,
language: tLanguage2,
);
final tExercise3 = Exercise(
id: 3,
baseId: 2,
uuid: 'a3b6c7bb-9d22-4119-a5fc-818584d5e9bc',
languageId: 2,
creationDate: DateTime(2021, 4, 1),
name: 'test exercise 3',
description: 'The man in black fled across the desert, and the gunslinger followed',
base: tBase3,
language: tLanguage2,
);
List<Exercise> getTestExercises() {

View File

@@ -0,0 +1,18 @@
import 'dart:io';
import 'package:integration_test/integration_test_driver_extended.dart';
// cf. https://dev.to/mjablecnik/take-screenshot-during-flutter-integration-tests-435k
Future<void> main() async {
try {
await integrationDriver(
onScreenshot: (String screenshotName, List<int> screenshotBytes) async {
final File image = await File('screenshots/$screenshotName.png').create(recursive: true);
image.writeAsBytesSync(screenshotBytes);
return true;
},
);
} catch (e) {
print('An error occurred: $e');
}
}