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>
80 lines
2.6 KiB
Dart
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);
|
|
});
|
|
});
|
|
}
|