lum_splash_video/example/integration_test/plugin_integration_test.dart

367 lines
11 KiB
Dart

/*
* Copyright (c) 2025
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:splash_video/splash_video.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('SplashVideoPage Configuration Validation', () {
testWidgets('throws error when using both nextScreen and onVideoComplete',
(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
nextScreen: const Scaffold(),
onVideoComplete: () {},
),
),
);
// Should throw ArgumentError during build
expect(tester.takeException(), isA<ArgumentError>());
});
testWidgets('throws error when using nextScreen with looping video',
(WidgetTester tester) async {
final controller = SplashVideoController(loopVideo: true);
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
controller: controller,
nextScreen: const Scaffold(),
),
),
);
expect(tester.takeException(), isA<ArgumentError>());
controller.dispose();
});
testWidgets('throws error when using onVideoComplete with looping video',
(WidgetTester tester) async {
final controller = SplashVideoController(loopVideo: true);
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
controller: controller,
onVideoComplete: () {},
),
),
);
expect(tester.takeException(), isA<ArgumentError>());
controller.dispose();
});
});
group('SplashVideoPage Error Handling', () {
testWidgets('shows default error UI when video source is invalid',
(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: AssetSource('assets/invalid/nonexistent.mp4'),
nextScreen: const Scaffold(),
),
),
);
// Wait for error to be detected
await tester.pumpAndSettle(const Duration(seconds: 5));
// Should show error icon and message
expect(find.byIcon(Icons.error_outline), findsOneWidget);
expect(find.text('Video Load Error'), findsOneWidget);
});
testWidgets('calls onVideoError callback when provided',
(WidgetTester tester) async {
String? capturedError;
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: AssetSource('assets/invalid/nonexistent.mp4'),
onVideoError: (error) {
capturedError = error;
},
),
),
);
// Wait for error to be detected
await tester.pumpAndSettle(const Duration(seconds: 5));
expect(capturedError, isNotNull);
expect(capturedError, contains('Failed'));
});
testWidgets('handles network URL errors gracefully',
(WidgetTester tester) async {
String? error;
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: NetworkFileSource('https://invalid.example.com/video.mp4'),
onVideoError: (e) => error = e,
),
),
);
await tester.pumpAndSettle(const Duration(seconds: 5));
// Should capture network error
expect(error, isNotNull);
});
});
group('SplashVideoPage Overlays', () {
testWidgets('renders title widget overlay', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
titleWidget: const Text('Welcome'),
onVideoError: (_) {},
),
),
);
await tester.pump();
expect(find.text('Welcome'), findsOneWidget);
});
testWidgets('renders footer widget overlay', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
footerWidget: const Text('Loading...'),
onVideoError: (_) {},
),
),
);
await tester.pump();
expect(find.text('Loading...'), findsOneWidget);
});
testWidgets('renders custom overlay from builder',
(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
overlayBuilder: (context) => const Text('Custom Overlay'),
onVideoError: (_) {},
),
),
);
await tester.pump();
expect(find.text('Custom Overlay'), findsOneWidget);
});
testWidgets('renders all overlays together', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
titleWidget: const Text('Title'),
footerWidget: const Text('Footer'),
overlayBuilder: (context) => const Text('Custom'),
onVideoError: (_) {},
),
),
);
await tester.pump();
expect(find.text('Title'), findsOneWidget);
expect(find.text('Footer'), findsOneWidget);
expect(find.text('Custom'), findsOneWidget);
});
});
group('SplashVideoController Integration', () {
testWidgets('controller can skip video', (WidgetTester tester) async {
final controller = SplashVideoController(loopVideo: true);
var completeCalled = false;
await tester.pumpWidget(
MaterialApp(
home: Builder(
builder: (context) => SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
controller: controller,
footerWidget: ElevatedButton(
onPressed: () {
controller.skip();
completeCalled = true;
},
child: const Text('Skip'),
),
onVideoError: (_) {},
),
),
),
);
await tester.pump();
// Tap skip button
await tester.tap(find.text('Skip'));
await tester.pump();
expect(completeCalled, isTrue);
expect(controller.skipRequested, isTrue);
controller.dispose();
});
testWidgets('controller provides player access after initialization',
(WidgetTester tester) async {
final controller = SplashVideoController();
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
controller: controller,
onVideoError: (_) {},
),
),
);
await tester.pumpAndSettle();
// After initialization, player should be accessible
// Note: This may throw if video fails to load
try {
final player = controller.player;
expect(player, isNotNull);
} catch (e) {
// Expected if video doesn't load in test environment
expect(e, isA<StateError>());
}
controller.dispose();
});
});
group('Source Types Integration', () {
testWidgets('AssetSource works with valid asset',
(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
onVideoError: (_) {},
),
),
);
await tester.pump();
// Widget should be created without exceptions
expect(find.byType(SplashVideo), findsOneWidget);
});
testWidgets('NetworkFileSource accepts valid URL',
(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: NetworkFileSource('https://example.com/video.mp4'),
onVideoError: (_) {},
),
),
);
await tester.pump();
expect(find.byType(SplashVideo), findsOneWidget);
});
testWidgets('DeviceFileSource accepts file path',
(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: DeviceFileSource('/path/to/video.mp4'),
onVideoError: (_) {},
),
),
);
await tester.pump();
expect(find.byType(SplashVideo), findsOneWidget);
});
});
group('VideoConfig Integration', () {
testWidgets('respects useSafeArea configuration',
(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
videoConfig: const VideoConfig(useSafeArea: true),
onVideoError: (_) {},
),
),
);
await tester.pump();
expect(find.byType(SplashVideo), findsOneWidget);
});
testWidgets('supports different visibility modes',
(WidgetTester tester) async {
for (final mode in VideoScaleMode.values) {
await tester.pumpWidget(
MaterialApp(
home: SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
videoConfig: VideoConfig(scale: mode),
onVideoError: (_) {},
),
),
);
await tester.pump();
expect(find.byType(SplashVideo), findsOneWidget);
// Clean up for next iteration
await tester.pumpWidget(Container());
}
});
});
}