Files

132 lines
4.3 KiB
Dart
Raw Permalink Normal View History

import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:zenxercise/src/app.dart';
import 'package:zenxercise/src/exercises/exercise.dart';
import 'package:zenxercise/src/exercises/exercise_library.dart';
import 'package:zenxercise/src/modes/mode.dart';
import 'package:zenxercise/src/history/session_repository.dart';
import 'package:zenxercise/src/plans/plan_repository.dart';
import 'package:zenxercise/src/player/player_effects.dart';
import 'package:zenxercise/src/settings/settings_controller.dart';
import 'package:zenxercise/src/streak/reminder_scheduler.dart';
import 'test_database.dart';
Exercise exercise(
String id,
Mode mode, {
String? name,
List<String> primary = const ['hamstrings'],
List<String> secondary = const [],
String? equipment = 'body only',
String level = 'beginner',
List<String> instructions = const ['Breathe.'],
int imageCount = 0,
}) => Exercise(
id: id,
name: name ?? id.replaceAll('_', ' '),
mode: mode,
category: mode == Mode.stretching ? 'stretching' : 'strength',
level: level,
equipment: equipment,
primaryMuscles: primary,
secondaryMuscles: secondary,
instructions: instructions,
imageCount: imageCount,
);
/// Two stretches and a squat. The 90/90 Hamstring's images exist in the real assets.
final sampleLibrary = ExerciseLibrary([
exercise(
'90_90_Hamstring',
Mode.stretching,
name: '90/90 Hamstring',
secondary: const ['calves'],
instructions: const ['Lie on your back.', 'Straighten one leg.'],
imageCount: 2,
),
exercise('Calf_Stretch', Mode.stretching, primary: const ['calves'], equipment: 'other', level: 'intermediate'),
exercise('Barbell_Squat', Mode.workout, primary: const ['quadriceps'], equipment: 'barbell'),
]);
/// Counts chimes instead of playing them and leaves the screen alone.
class FakePlayerEffects implements PlayerEffects {
final chimes = <Mode>[];
bool screenOn = false;
@override
Future<void> chime(Mode mode) async => chimes.add(mode);
@override
Future<void> keepScreenOn(bool on) async => screenOn = on;
}
/// Records what would be scheduled instead of talking to Android.
class FakeNotifier implements Notifier {
final scheduled = <(DateTime, String)>[];
var permissionRequests = 0;
@override
Future<void> init() async {}
@override
Future<bool> requestPermission() async {
permissionRequests++;
return true;
}
@override
Future<bool> enabled() async => true;
@override
Future<void> cancelAll() async => scheduled.clear();
@override
Future<void> schedule({required int id, required DateTime at, required String title, required String body}) async =>
scheduled.add((at, body));
}
/// A Pixel-sized screen instead of the default 800×600, so the floating
/// navigation bar does not cover what a test taps.
void usePhoneScreen(WidgetTester tester) {
tester.view.physicalSize = const Size(1080, 2400);
tester.view.devicePixelRatio = 2.75;
addTearDown(tester.view.reset);
}
/// The whole app over [library], with preferences starting from [prefs].
Future<SettingsController> pumpApp(
WidgetTester tester, {
ExerciseLibrary? library,
Map<String, Object> prefs = const {},
PlanRepository? plans,
SessionRepository? sessions,
PlayerEffects? effects,
FakeNotifier? notifier,
}) async {
SharedPreferences.setMockInitialValues(prefs);
final settings = SettingsController(SettingsService());
await settings.loadSettings();
final db = testDatabase();
addTearDown(db.close);
final sessionRepository = sessions ?? SessionRepository(db);
final fakeNotifier = notifier ?? FakeNotifier();
await tester.pumpWidget(
MultiProvider(
providers: [
ChangeNotifierProvider.value(value: settings),
Provider.value(value: library ?? sampleLibrary),
Provider.value(value: plans ?? PlanRepository(db)),
Provider.value(value: sessionRepository),
Provider<PlayerEffects>.value(value: effects ?? FakePlayerEffects()),
Provider<Notifier>.value(value: fakeNotifier),
Provider.value(value: ReminderScheduler(fakeNotifier, settings, sessionRepository)),
],
child: const ZenXerciseApp(),
),
);
await tester.pumpAndSettle();
return settings;
}