feat(server): implemente synchronisation et serveur avec fixtures (#187)

- Implémente la couche de synchronisation avec le serveur
- Ajoute les fixtures versionnées pour les tests
- Met à jour Drift database et repositories pour le support sync
- Améliore les tests de synchronisation
- Corrige et améliore le watch companion pour la collecte de métriques

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-04 23:07:31 +02:00
parent d1edb2397e
commit fe3608cc4a
31 changed files with 5056 additions and 394 deletions

View File

@ -224,6 +224,131 @@ void main() {
expect(find.text('Dribble routine'), findsOneWidget);
});
testWidgets('filtre les exercices par types métier en OR', (tester) async {
final exerciseRepository = _FakeExerciseRepository()
..exercises.addAll([
Exercise(
metadata: _metadata('exercise-1'),
name: 'Tir hérité',
hasTimeMeasure: true,
hasRepsMeasure: false,
hasScoreMeasure: false,
category: ExerciseCategory.shoot,
),
Exercise(
metadata: _metadata('exercise-2'),
name: 'Dribble appuyé',
hasTimeMeasure: false,
hasRepsMeasure: true,
hasScoreMeasure: false,
businessTypes: const [BusinessExerciseType.dribble],
),
Exercise(
metadata: _metadata('exercise-3'),
name: 'Routine libre',
hasTimeMeasure: true,
hasRepsMeasure: false,
hasScoreMeasure: false,
),
]);
await tester.pumpWidget(
MaterialApp(
home: ExerciseLibraryScreen(
exerciseUseCases: _exerciseUseCases(exerciseRepository),
mediaUseCases: _mediaUseCases(exerciseRepository),
),
),
);
await tester.pump();
await tester.pump();
expect(find.widgetWithText(FilterChip, 'Tir'), findsOneWidget);
expect(find.widgetWithText(FilterChip, 'Dribble'), findsOneWidget);
expect(find.widgetWithText(FilterChip, 'Libre / autre'), findsOneWidget);
await tester.tap(find.widgetWithText(FilterChip, 'Tir'));
await tester.pump();
expect(find.text('Tir hérité'), findsOneWidget);
expect(find.text('Dribble appuyé'), findsNothing);
expect(find.text('Routine libre'), findsNothing);
await tester.tap(find.widgetWithText(FilterChip, 'Dribble'));
await tester.pump();
expect(find.text('Tir hérité'), findsOneWidget);
expect(find.text('Dribble appuyé'), findsOneWidget);
expect(find.text('Routine libre'), findsNothing);
await tester.tap(find.widgetWithText(FilterChip, 'Libre / autre'));
await tester.pump();
expect(find.text('Tir hérité'), findsOneWidget);
expect(find.text('Dribble appuyé'), findsOneWidget);
expect(find.text('Routine libre'), findsOneWidget);
await tester.tap(find.text('Effacer les filtres'));
await tester.pump();
expect(
tester
.widget<FilterChip>(find.widgetWithText(FilterChip, 'Tir'))
.selected,
isFalse,
);
expect(
tester
.widget<FilterChip>(find.widgetWithText(FilterChip, 'Dribble'))
.selected,
isFalse,
);
expect(
tester
.widget<FilterChip>(find.widgetWithText(FilterChip, 'Libre / autre'))
.selected,
isFalse,
);
});
testWidgets('masque le filtre type quand un seul type est disponible', (
tester,
) async {
final exerciseRepository = _FakeExerciseRepository()
..exercises.addAll([
Exercise(
metadata: _metadata('exercise-1'),
name: 'Tir proche',
hasTimeMeasure: true,
hasRepsMeasure: false,
hasScoreMeasure: false,
category: ExerciseCategory.shoot,
),
Exercise(
metadata: _metadata('exercise-2'),
name: 'Tir loin',
hasTimeMeasure: false,
hasRepsMeasure: true,
hasScoreMeasure: false,
category: ExerciseCategory.shoot,
),
]);
await tester.pumpWidget(
MaterialApp(
home: ExerciseLibraryScreen(
exerciseUseCases: _exerciseUseCases(exerciseRepository),
mediaUseCases: _mediaUseCases(exerciseRepository),
),
),
);
await tester.pump();
await tester.pump();
expect(find.text('Type'), findsNothing);
expect(find.widgetWithText(FilterChip, 'Tir'), findsNothing);
});
testWidgets('basculer en chrono intégré masque lunité et affiche le badge', (
tester,
) async {