// Author: fruit.com.cn import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:fruitshorts/app.dart'; import 'package:fruitshorts/core/data/models/drama.dart'; import 'package:fruitshorts/core/data/models/watch_progress.dart'; import 'package:fruitshorts/core/data/repositories/favorite_repository.dart'; import 'package:fruitshorts/core/data/repositories/playback_repository.dart'; import 'package:fruitshorts/core/data/repositories/watch_history_repository.dart'; import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart'; import '../support/fake_catalog.dart'; import '../support/fake_category.dart'; import '../support/fake_interaction_repositories.dart'; import '../support/widget_player.dart'; void main() { testWidgets('should_render_following_tabs_grid_and_edit_actions', ( tester, ) async { _signIn(); final catalog = FakeCatalogRepository(); await tester.pumpWidget( _app( catalog: catalog, favorites: InMemoryFavoriteRepository( cards: catalog.dramas.take(1).toList(), saved: {catalog.dramas.first.id}, ), ), ); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('tab-follow'))); await tester.pumpAndSettle(); expect(find.byKey(const Key('following-page')), findsOneWidget); expect(find.byKey(const Key('following-tab-favorites')), findsOneWidget); expect(find.byKey(const Key('following-tab-history')), findsOneWidget); expect(find.byKey(const Key('following-tab-reserve')), findsOneWidget); expect(find.byKey(const Key('following-favorites-grid')), findsOneWidget); expect(find.byType(CustomScrollView), findsWidgets); await tester.tap(find.byKey(const Key('following-edit'))); await tester.pumpAndSettle(); expect( find.byKey(const Key('following-remove-the-signal-demo')), findsOneWidget, ); await tester.tap(find.byKey(const Key('following-remove-the-signal-demo'))); await tester.pumpAndSettle(); expect(find.byType(AlertDialog), findsOneWidget); await tester.tap( find.descendant( of: find.byType(AlertDialog), matching: find.byType(FilledButton), ), ); await tester.pumpAndSettle(); expect( find.byKey(const Key('following-remove-the-signal-demo')), findsNothing, ); expect(find.byIcon(Icons.edit_outlined), findsOneWidget); expect( find.byKey(const Key('following-card-the-signal-demo')), findsNothing, ); await tester.tap(find.byKey(const Key('following-tab-history'))); await tester.pumpAndSettle(); expect(find.byKey(const Key('following-history-empty')), findsOneWidget); await tester.tap(find.byKey(const Key('following-tab-reserve'))); await tester.pumpAndSettle(); expect(find.byKey(const Key('following-reserve-empty')), findsOneWidget); }); testWidgets('should_show_auth_gate_when_signed_out', (tester) async { SharedPreferencesAsyncPlatform.instance = InMemorySharedPreferencesAsync.empty(); await tester.pumpWidget(_app(catalog: FakeCatalogRepository())); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('tab-follow'))); await tester.pumpAndSettle(); expect(find.byKey(const Key('auth-gate-panel')), findsOneWidget); expect(find.byKey(const Key('following-favorites-grid')), findsNothing); }); testWidgets('should_show_empty_favorites_and_history', (tester) async { _signIn(); await tester.pumpWidget(_app(catalog: FakeCatalogRepository())); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('tab-follow'))); await tester.pumpAndSettle(); expect(find.byKey(const Key('following-favorites-empty')), findsOneWidget); await tester.tap(find.byKey(const Key('following-tab-history'))); await tester.pumpAndSettle(); expect(find.byKey(const Key('following-history-empty')), findsOneWidget); }); testWidgets('should_render_history_metadata_without_detail_fetch', ( tester, ) async { _signIn(); final catalog = _CountingCatalogRepository(); await tester.pumpWidget( _app( catalog: catalog, history: InMemoryWatchHistoryRepository( seed: [ WatchProgress( dramaId: 'the-signal-demo', episodeId: 'the-signal-demo-3', dramaTitle: 'Server title', dramaCover: '/files/server-cover.jpg', episodeNumber: 3, totalEpisodes: 8, position: const Duration(seconds: 25), duration: const Duration(seconds: 100), ), ], ), ), ); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('tab-follow'))); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('following-tab-history'))); await tester.pumpAndSettle(); expect(find.text('Server title'), findsOneWidget); expect(find.text('Watched to Episode 3'), findsOneWidget); expect( find.byKey(const Key('following-progress-the-signal-demo')), findsOneWidget, ); expect(catalog.detailFetches, 0); }); testWidgets('should_reset_edit_state_when_switching_tabs', (tester) async { _signIn(); final catalog = FakeCatalogRepository(); await tester.pumpWidget( _app( catalog: catalog, favorites: InMemoryFavoriteRepository( cards: catalog.dramas, saved: catalog.dramas.map((drama) => drama.id).toSet(), ), ), ); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('tab-follow'))); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('following-edit'))); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('following-tab-history'))); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('following-tab-favorites'))); await tester.pumpAndSettle(); expect( find.byKey(const Key('following-card-the-signal-demo')), findsOneWidget, ); expect(find.byIcon(Icons.edit_outlined), findsOneWidget); }); } void _signIn() { SharedPreferencesAsyncPlatform.instance = InMemorySharedPreferencesAsync.withData({ 'auth.accessToken': 'access', 'auth.refreshToken': 'refresh', 'auth.user': '{"uid":"9","nickname":"Viewer","avatarUrl":""}', }); } Widget _app({ required FakeCatalogRepository catalog, FavoriteRepository? favorites, WatchHistoryRepository? history, }) { return LumaDramaApp( playerFactory: createWidgetPlayer, catalogRepository: catalog, categoryRepository: FakeCategoryRepository(catalog: catalog), watchHistoryRepository: history ?? InMemoryWatchHistoryRepository(), favoriteRepository: favorites ?? InMemoryFavoriteRepository(), playbackRepository: FakePlaybackRepository(), commentRepository: FakeCommentRepository(), interactionRepository: FakeInteractionRepository(), ); } class _CountingCatalogRepository extends FakeCatalogRepository { int detailFetches = 0; @override Future fetchDrama(String dramaId) { detailFetches += 1; return super.fetchDrama(dramaId); } }