Files
ZenXercise/test/history/session_repository_test.dart
CedricandClaude Opus 5.5 1ffe6269ea Stage 5: History, the shared daily Streak and Reminders
- Streak computed from all complete Sessions: Grace Hour (00:00-01:00
  counts for yesterday unless it is done), a Freeze per 7 Streak Days
  (max 2) spent automatically on a missed day (ADR 0006)
- Top bar flame (grey until today is done) opening a panel with current
  and longest Streak, Freezes and a month calendar; 'Day N of your
  streak' on a fresh summary
- History per Mode grouped by day, reopening each summary
- Two adjustable Reminders (19:00, 22:30) scheduled 14 days ahead with
  flutter_local_notifications, none on a done day; permission asked
  after the first complete Session or from Settings
- Settings: Reminders, the Player chime, exercise credits

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 00:34:49 +01:00

67 lines
2.4 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:zenxercise/src/database/database.dart';
import 'package:zenxercise/src/history/session_repository.dart';
import 'package:zenxercise/src/modes/mode.dart';
import 'package:zenxercise/src/plans/models/plan.dart';
import 'package:zenxercise/src/player/session_runner.dart';
import '../support/test_database.dart';
void main() {
late AppDatabase db;
late SessionRepository sessions;
setUp(() {
db = testDatabase();
sessions = SessionRepository(db);
});
tearDown(() => db.close());
Plan plan(Mode mode) => Plan(
id: 'p1',
mode: mode,
name: 'Legs',
items: const [WorkoutStep(exerciseId: 'Squat', sets: 1, target: WorkoutTarget.reps(10))],
createdAt: DateTime(2026),
updatedAt: DateTime(2026),
);
SessionResult result(Mode mode, DateTime end, {bool complete = true}) => SessionResult(
plan: plan(mode),
startedAt: end.subtract(const Duration(minutes: 30)),
endedAt: end,
duration: const Duration(minutes: 28),
complete: complete,
setLogs: const [SetLog(exerciseId: 'Squat', set: 1, reps: 8, weightKg: 60)],
);
test('a saved Session keeps its Plan snapshot, logs and outcome', () async {
final saved = await sessions.save(result(Mode.workout, DateTime(2026, 10, 29, 19), complete: false));
expect(saved.planName, 'Legs');
expect(saved.items.single, isA<WorkoutStep>());
expect(saved.duration, const Duration(minutes: 28));
expect(saved.complete, isFalse);
expect(saved.setLogs.single.reps, 8);
expect(saved.setLogs.single.weightKg, 60);
});
test('Sessions are listed per Mode, the latest first', () async {
await sessions.save(result(Mode.workout, DateTime(2026, 10, 28)));
await sessions.save(result(Mode.workout, DateTime(2026, 10, 29)));
await sessions.save(result(Mode.stretching, DateTime(2026, 10, 30)));
final workout = await sessions.watchSessions(Mode.workout).first;
expect(workout.map((s) => s.endedAt.day), [29, 28]);
});
test('the Streak sees complete Sessions of both Modes only', () async {
await sessions.save(result(Mode.workout, DateTime(2026, 10, 28)));
await sessions.save(result(Mode.stretching, DateTime(2026, 10, 29)));
await sessions.save(result(Mode.stretching, DateTime(2026, 10, 30), complete: false));
expect(await sessions.completeEndTimes(), unorderedEquals([DateTime(2026, 10, 28), DateTime(2026, 10, 29)]));
});
}