import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:reelbox/data/models.dart'; import 'package:reelbox/ui/catalog.dart'; import 'package:reelbox/media/download_button.dart'; import 'package:reelbox/media/downloads_page.dart'; import 'catalog_widget_test.dart' show CatalogApi, mountCatalog; void main() { testWidgets( 'embedded sources are rejected without enqueue or external handoff', (tester) async { var dispatched = 0; var navigations = 0; final state = await mountCatalog( tester, CatalogApi(), Scaffold( body: DownloadButton( title: const TitleRecord(id: 7, title: 'Movie'), source: const MediaSource( type: 'youtube', url: 'https://youtu.be/fixture', ), enqueue: ({required title, required source, episode}) async { dispatched++; }, openDownloads: (_) => navigations++, ), ), ); addTearDown(state.dispose); await tester.tap(find.text('Download in Reelbox')); await tester.pumpAndSettle(); expect(dispatched, 0); expect(navigations, 0); expect( find.textContaining('Embedded sources cannot be downloaded'), findsOneWidget, ); expect(tester.takeException(), isNull); }, ); testWidgets('source cards label the internal Reelbox download action', ( tester, ) async { final state = await mountCatalog( tester, CatalogApi(), const TitlePage(title: TitleRecord(id: 7, title: 'Fixture')), ); addTearDown(state.dispose); expect( find.widgetWithText(FilledButton, 'Download in Reelbox'), findsWidgets, ); }); testWidgets( 'enqueue failure shows its cause and allows retry without navigating', (tester) async { var attempts = 0; var navigations = 0; final state = await mountCatalog( tester, CatalogApi(), Scaffold( body: DownloadButton( title: const TitleRecord(id: 7, title: 'Movie'), source: const MediaSource(url: 'https://media.example/movie.mp4'), enqueue: ({required title, required source, episode}) async { attempts++; throw StateError('HTTP 403: this media URL has expired.'); }, openDownloads: (_) => navigations++, ), ), ); addTearDown(state.dispose); await tester.tap(find.text('Download in Reelbox')); await tester.pumpAndSettle(); expect( find.textContaining('HTTP 403: this media URL has expired.'), findsOneWidget, ); expect(navigations, 0); expect(tester.takeException(), isNull); await tester.tap(find.text('Download in Reelbox')); await tester.pump(); expect(attempts, 2); }, ); testWidgets( 'selected episode queues once while starting then opens Downloads', (tester) async { const title = TitleRecord(id: 41, title: 'Series', type: 'serie'); const source = MediaSource( id: 9, quality: '720p', url: 'https://media.example/episode.mp4', ); const episode = EpisodeRecord(id: 52, title: 'Episode 2'); final pending = Completer(); final dispatched = <(TitleRecord, MediaSource, EpisodeRecord?)>[]; final state = await mountCatalog( tester, CatalogApi(), Scaffold( body: DownloadButton( title: title, source: source, episode: episode, enqueue: ({required title, required source, episode}) { dispatched.add((title, source, episode)); return pending.future; }, ), ), ); addTearDown(state.dispose); final button = find.widgetWithText(FilledButton, 'Download in Reelbox'); await tester.tap(button); await tester.tap(button); await tester.pump(); expect(dispatched, [(title, source, episode)]); expect( tester.widget(find.byType(FilledButton)).onPressed, isNull, ); expect(find.byType(CircularProgressIndicator), findsOneWidget); expect(find.byType(DownloadsPage), findsNothing); pending.complete(); await tester.pumpAndSettle(); expect(find.byType(DownloadsPage), findsOneWidget); expect(dispatched, hasLength(1)); expect(tester.takeException(), isNull); }, variant: TargetPlatformVariant.only(TargetPlatform.linux), ); }