// Author: fruit.com.cn import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:video_player/video_player.dart'; import 'package:fruitshorts/pages/player/widgets/player_video_surface.dart'; void main() { testWidgets('should_keep_fallback_visible_before_video_is_ready', ( tester, ) async { await _pumpSurface(tester); expect(_fallbackColor(tester), Colors.black); expect(find.byKey(const Key('player-opening-frame')), findsNothing); expect(_opacity(tester), 0); }); testWidgets('should_show_opening_frame_before_decode_is_ready', ( tester, ) async { await _pumpSurface( tester, openingFrame: const ColoredBox( key: Key('fake-opening'), color: Colors.red, ), ); expect(find.byKey(const Key('player-opening-frame')), findsOneWidget); expect(find.byKey(const Key('fake-opening')), findsOneWidget); expect(_opacity(tester), 0); }); testWidgets('should_reveal_paused_frame_when_initialized', (tester) async { final controller = await _pumpSurface(tester); controller.value = const VideoPlayerValue( duration: Duration(minutes: 1), size: Size(1280, 720), position: Duration.zero, isInitialized: true, isPlaying: false, ); await tester.pump(); expect(_opacity(tester), 1); expect(find.byKey(const Key('player-opening-frame')), findsNothing); }); testWidgets('should_show_cover_until_first_playback_frame', ( tester, ) async { final controller = await _pumpSurface( tester, openingFrame: const ColoredBox(color: Colors.red), holdOpeningUntilFirstFrame: true, ); expect(_opacity(tester), 0); controller.value = const VideoPlayerValue( duration: Duration(minutes: 1), size: Size(1280, 720), position: Duration.zero, isInitialized: true, isPlaying: true, ); await tester.pump(); expect(_opacity(tester), 0); expect(find.byKey(const Key('player-opening-frame')), findsOneWidget); controller.value = const VideoPlayerValue( duration: Duration(minutes: 1), size: Size(1280, 720), position: Duration(milliseconds: 1), isInitialized: true, isPlaying: true, ); await tester.pump(); expect(_opacity(tester), 1); expect(find.byKey(const Key('player-opening-frame')), findsNothing); expect( tester .widget( find.byKey(const Key('player-video-opacity')), ) .duration, Duration.zero, ); }); testWidgets('should_skip_cover_when_prewarmed_frame_is_available', ( tester, ) async { await _pumpSurface( tester, openingFrame: const ColoredBox(color: Colors.red), holdOpeningUntilFirstFrame: true, preparedFrameAvailable: true, value: const VideoPlayerValue( duration: Duration(minutes: 1), size: Size(1280, 720), position: Duration.zero, isInitialized: true, isPlaying: false, ), ); expect(find.byKey(const Key('player-opening-frame')), findsNothing); expect(_opacity(tester), 1); }); testWidgets('should_show_video_error_above_retained_fallback', ( tester, ) async { await _pumpSurface( tester, value: const VideoPlayerValue.erroneous('No route to host'), ); expect(find.byKey(const Key('player-video-error')), findsOneWidget); expect(find.text('No route to host'), findsOneWidget); expect(_fallbackColor(tester), Colors.black); expect(_opacity(tester), 0); }); testWidgets('should_cover_new_video_only_while_handoff_is_held', ( tester, ) async { final current = VideoPlayerController.networkUrl( Uri.parse('http://192.168.31.187:8081/files/720.m3u8'), ); final previous = VideoPlayerController.networkUrl( Uri.parse('http://192.168.31.187:8081/files/360.m3u8'), ); addTearDown(current.dispose); addTearDown(previous.dispose); const ready = VideoPlayerValue( duration: Duration(minutes: 1), size: Size(1280, 720), position: Duration(seconds: 3), isInitialized: true, isPlaying: true, ); current.value = ready; previous.value = ready; Future pump(VideoPlayerController? handoff) { return tester.pumpWidget( MaterialApp( home: Scaffold( body: PlayerVideoSurface( controller: current, handoff: handoff, videoUrl: current.dataSource, theater: false, openingFrame: const ColoredBox(color: Colors.red), ), ), ), ); } await pump(previous); expect(find.byKey(const Key('player-video-handoff')), findsOneWidget); expect(find.byKey(const Key('player-opening-frame')), findsNothing); expect(_opacity(tester), 1); await pump(null); expect(find.byKey(const Key('player-video-handoff')), findsNothing); expect(find.byType(VideoPlayer), findsOneWidget); }); } Future _pumpSurface( WidgetTester tester, { VideoPlayerValue? value, Widget? openingFrame, bool holdOpeningUntilFirstFrame = false, bool preparedFrameAvailable = false, }) async { final controller = VideoPlayerController.networkUrl( Uri.parse('http://192.168.31.187:8081/files/video.mp4'), ); addTearDown(controller.dispose); if (value != null) controller.value = value; await tester.pumpWidget( MaterialApp( home: Scaffold( body: PlayerVideoSurface( controller: controller, videoUrl: controller.dataSource, theater: false, openingFrame: openingFrame, holdOpeningUntilFirstFrame: holdOpeningUntilFirstFrame, preparedFrameAvailable: preparedFrameAvailable, ), ), ), ); await tester.pump(); return controller; } Color _fallbackColor(WidgetTester tester) { return tester .widget(find.byKey(const Key('player-fallback-background'))) .color; } double _opacity(WidgetTester tester) { return tester .widget(find.byKey(const Key('player-video-opacity'))) .opacity; }