Files
impact/test/services/tutorial_service_test.dart
qlionbleusamandClaude Opus 5 32582aba3d feat(tutorial): guide the first launch with spotlighted steps and gesture hands
Ajoute un didacticiel joué à la première utilisation : un voile sombre perce un
trou de lumière autour de l'élément à découvrir, une main animée mime le geste
attendu (tap, appui long, glisser, pincement à deux doigts pour zoomer) et une
bulle explique l'étape avec sa progression.

- visite d'accueil : nouvelle session, télémétrie, barre de navigation, réglages
- visite de l'éditeur d'impacts : ajouter, déplacer, zoomer au pincement, valider
- chaque visite n'est jouée qu'une fois (SharedPreferences)
- Paramètres > Aide & didacticiel > Revoir le didacticiel : réinitialise tout et
  relance la visite au retour sur l'écran concerné

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 11:46:02 +02:00

80 lines
2.6 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:bully/features/tutorial/tutorial_provider.dart';
import 'package:bully/services/tutorial_service.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
setUp(() => SharedPreferences.setMockInitialValues({}));
group('TutorialService', () {
test('aucune visite n\'est marquée vue à la première utilisation',
() async {
expect(await TutorialService().loadCompletedTours(), isEmpty);
});
test('mémorise puis réinitialise les visites vues', () async {
final service = TutorialService();
await service.markCompleted(TutorialTours.home);
expect(await service.loadCompletedTours(), {TutorialTours.home});
await service.markCompleted(TutorialTours.impactEditor);
expect(
await service.loadCompletedTours(),
{TutorialTours.home, TutorialTours.impactEditor},
);
await service.resetAll();
expect(await service.loadCompletedTours(), isEmpty);
});
});
group('TutorialProvider', () {
test('joue chaque visite une seule fois', () async {
final provider = TutorialProvider();
await provider.load();
expect(provider.isLoaded, isTrue);
expect(provider.shouldRun(TutorialTours.home), isTrue);
expect(provider.hasSeenIntro, isFalse);
await provider.complete(TutorialTours.home);
expect(provider.shouldRun(TutorialTours.home), isFalse);
expect(provider.hasSeenIntro, isTrue);
// Les autres visites restent disponibles.
expect(provider.shouldRun(TutorialTours.impactEditor), isTrue);
});
test('la réactivation depuis les paramètres rejoue toutes les visites',
() async {
final provider = TutorialProvider();
await provider.load();
await provider.complete(TutorialTours.home);
await provider.complete(TutorialTours.impactEditor);
await provider.restart();
expect(provider.shouldRun(TutorialTours.home), isTrue);
expect(provider.shouldRun(TutorialTours.impactEditor), isTrue);
// La remise à zéro est bien persistée.
expect(await TutorialService().loadCompletedTours(), isEmpty);
});
test('l\'état vu survit à un redémarrage de l\'application', () async {
final first = TutorialProvider();
await first.load();
await first.complete(TutorialTours.home);
final second = TutorialProvider();
await second.load();
expect(second.shouldRun(TutorialTours.home), isFalse);
expect(second.shouldRun(TutorialTours.impactEditor), isTrue);
});
});
}