// Author: fruit.com.cn import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:fruitshorts/app.dart'; import 'package:fruitshorts/core/data/models/comment.dart'; import 'package:fruitshorts/core/data/repositories/comment_repository.dart'; import 'package:fruitshorts/core/data/repositories/favorite_repository.dart'; import 'package:fruitshorts/core/data/repositories/interaction_repository.dart'; import 'package:fruitshorts/core/data/repositories/playback_repository.dart'; import 'package:fruitshorts/core/data/repositories/watch_history_repository.dart'; import 'package:fruitshorts/core/data/services/playback_session.dart'; import 'package:fruitshorts/pages/player/player_view.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() { void seedSignedInSession() { SharedPreferencesAsyncPlatform .instance = InMemorySharedPreferencesAsync.withData({ 'auth.accessToken': 'test-access', 'auth.refreshToken': 'test-refresh', 'auth.user': '{"uid":"M1CZWVYE","nickname":"Vicky sheng","avatarUrl":""}', }); } setUp(seedSignedInSession); Widget appUnderTest({ PlayerFactory? playerFactory, CommentRepository? commentRepository, InteractionRepository? interactionRepository, }) { final catalog = FakeCatalogRepository(); return LumaDramaApp( playerFactory: playerFactory ?? createWidgetPlayer, catalogRepository: catalog, categoryRepository: FakeCategoryRepository(catalog: catalog), watchHistoryRepository: InMemoryWatchHistoryRepository(), favoriteRepository: InMemoryFavoriteRepository(cards: catalog.dramas), playbackRepository: FakePlaybackRepository(), commentRepository: commentRepository ?? FakeCommentRepository(), interactionRepository: interactionRepository ?? FakeInteractionRepository(), ); } testWidgets('should_preload_next_episode_when_fullscreen_player_opens', ( tester, ) async { final created = []; await tester.pumpWidget( appUnderTest( playerFactory: (episode) { created.add(episode.id); return WidgetPlayer(); }, ), ); await tester.pumpAndSettle(); await _openTheaterPlayer(tester); expect(created, hasLength(2)); expect(find.byType(CircularProgressIndicator), findsNothing); await tester.drag(find.byType(PageView), const Offset(0, -550)); await tester.pumpAndSettle(); expect( tester.widget(find.byKey(const Key('player-title'))).data, contains('Episode 2'), ); expect(created, hasLength(3)); expect(created.toSet(), hasLength(3)); }); testWidgets('should_open_fullscreen_player_when_home_card_is_tapped', ( tester, ) async { await tester.pumpWidget(appUnderTest()); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('home-drama-card-the-signal-demo'))); await tester.pumpAndSettle(); final player = tester.widget(find.byType(PlayerPage)); expect(player.homeMode, isFalse); expect(find.byKey(const Key('player-controls-top')), findsOneWidget); }); testWidgets('should_keep_four_root_tabs_on_one_route_and_return_home', ( tester, ) async { tester.view.physicalSize = const Size(390, 844); tester.view.devicePixelRatio = 1; addTearDown(tester.view.resetPhysicalSize); addTearDown(tester.view.resetDevicePixelRatio); await tester.pumpWidget(appUnderTest()); await tester.pumpAndSettle(); await _openTheaterPlayer(tester); expect(find.byType(PlayerPage), findsOneWidget); await tester.tap(find.byKey(const Key('player-back'))); await tester.pumpAndSettle(); expect(find.byKey(const Key('home-all-dramas-grid')), findsOneWidget); expect( Navigator.of( tester.element(find.byKey(const Key('home-all-dramas-grid'))), ).canPop(), isFalse, ); await tester.binding.handlePopRoute(); await tester.pumpAndSettle(); expect(find.byKey(const Key('home-browse-page')), findsOneWidget); await tester.tap(find.byKey(const Key('tab-create'))); await tester.pumpAndSettle(); expect(find.byKey(const Key('create-page')), findsOneWidget); await tester.tap(find.byKey(const Key('tab-mine'))); await tester.pumpAndSettle(); expect(find.byKey(const Key('mine-menu')), findsOneWidget); expect( Navigator.of(tester.element(find.byKey(const Key('mine-menu')))).canPop(), isFalse, ); }); testWidgets('should_follow_system_locale_without_language_switch', ( tester, ) async { await tester.pumpWidget(appUnderTest()); await tester.pumpAndSettle(); expect(find.byTooltip('Captions'), findsNothing); await tester.tap(find.byKey(const Key('tab-mine'))); await tester.pumpAndSettle(); expect(find.text('Vicky sheng'), findsOneWidget); expect(find.text('Coins'), findsOneWidget); expect(find.text('App Language'), findsNothing); expect(find.byKey(const Key('mine-wallet')), findsOneWidget); await tester.tap(find.byKey(const Key('tab-theater'))); await tester.pumpAndSettle(); expect(find.text('Theater'), findsWidgets); }); testWidgets('should_fit_compact_viewport_when_player_is_opened', ( tester, ) async { tester.view.physicalSize = const Size(360, 720); tester.view.devicePixelRatio = 1; addTearDown(tester.view.resetPhysicalSize); addTearDown(tester.view.resetDevicePixelRatio); await tester.pumpWidget(appUnderTest()); await tester.pumpAndSettle(); await _openTheaterPlayer(tester); expect(find.byType(Slider), findsOneWidget); await tester.drag(find.byType(PageView), const Offset(0, -500)); await tester.pumpAndSettle(); expect( tester.widget(find.byKey(const Key('player-title'))).data, contains('Episode 2'), ); expect(tester.takeException(), isNull); }); testWidgets('should_render_theater_with_filters_and_same_route_tabs', ( tester, ) async { tester.view.physicalSize = const Size(360, 720); tester.view.devicePixelRatio = 1; addTearDown(tester.view.resetPhysicalSize); addTearDown(tester.view.resetDevicePixelRatio); await tester.pumpWidget(appUnderTest()); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('tab-theater'))); await tester.pumpAndSettle(); expect(find.byKey(const Key('discover-search')), findsOneWidget); expect(find.byKey(const Key('theater-category-chips')), findsOneWidget); expect(find.byKey(const Key('theater-language-chips')), findsOneWidget); expect(find.byKey(const Key('home-all-dramas-grid')), findsOneWidget); expect(find.byKey(const Key('discover-profile')), findsOneWidget); expect( find.byKey(const Key('home-drama-card-city-lights-demo')), findsOneWidget, ); expect(tester.takeException(), isNull); }); testWidgets('should_save_comment_like_and_share_from_player_more', ( tester, ) async { String? sharedText; final interactions = FakeInteractionRepository(); final comments = FakeCommentRepository(pages: [const CommentPage()]); const channel = MethodChannel('com.stormg.lumadrama/share'); tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, ( call, ) async { sharedText = (call.arguments as Map)['text'] as String; return null; }); addTearDown( () => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( channel, null, ), ); await tester.pumpWidget( appUnderTest( commentRepository: comments, interactionRepository: interactions, ), ); await tester.pumpAndSettle(); await _openTheaterPlayer(tester); await tester.tap(find.byKey(const Key('player-comments'))); await tester.pumpAndSettle(); expect(find.text('No comments yet.'), findsOneWidget); await tester.enterText(find.byKey(const Key('comment-input')), 'Nice demo'); await tester.tap(find.byKey(const Key('comment-post'))); await tester.pumpAndSettle(); expect(find.text('Nice demo'), findsOneWidget); await tester.binding.handlePopRoute(); await tester.pumpAndSettle(); await _tapPlayerMore(tester, const Key('player-more-like')); expect(interactions.likeTargets, contains('DRAMA:city-lights-demo')); await _tapPlayerMore(tester, const Key('player-more-favorite')); await _tapPlayerMore(tester, const Key('player-more-share')); expect(sharedText, contains('City Lights & Velvet Nights')); expect(sharedText, contains('FruitShorts')); expect(tester.takeException(), isNull); }); testWidgets('should_open_auth_gate_without_liking_when_signed_out', ( tester, ) async { SharedPreferencesAsyncPlatform.instance = InMemorySharedPreferencesAsync.empty(); final interactions = FakeInteractionRepository(); await tester.pumpWidget(appUnderTest(interactionRepository: interactions)); await tester.pumpAndSettle(); await _openTheaterPlayer(tester); await _tapPlayerMore(tester, const Key('player-more-like')); expect(find.text('Sign in to continue'), findsOneWidget); expect(interactions.likeTargets, isEmpty); }); testWidgets('should_show_saved_player_drama_in_favorites', (tester) async { tester.view.physicalSize = const Size(390, 844); tester.view.devicePixelRatio = 1; addTearDown(tester.view.resetPhysicalSize); addTearDown(tester.view.resetDevicePixelRatio); await tester.pumpWidget(appUnderTest()); await tester.pumpAndSettle(); await _openTheaterPlayer(tester); await _tapPlayerMore(tester, const Key('player-more-favorite')); await tester.tap(find.byKey(const Key('player-back'))); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('tab-mine'))); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('mine-watchlist'))); await tester.pumpAndSettle(); expect(find.text('City Lights & Velvet Nights'), findsWidgets); }); } Future _openTheaterPlayer(WidgetTester tester) async { await tester.tap(find.byKey(const Key('tab-theater'))); await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('home-drama-card-city-lights-demo'))); await tester.pumpAndSettle(); } Future _tapPlayerMore(WidgetTester tester, Key action) async { await tester.tap(find.byKey(const Key('player-more'))); await tester.pumpAndSettle(); await tester.ensureVisible(find.byKey(action)); await tester.pumpAndSettle(); await tester.tap(find.byKey(action)); await tester.pumpAndSettle(); }