import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:reelbox/app.dart'; import 'package:reelbox/data/api_service.dart'; import 'package:reelbox/data/models.dart'; import 'package:reelbox/state/app_state.dart'; import 'package:reelbox/ui/catalog.dart'; import 'package:reelbox/ui/library.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'api_service_test.dart' as fixtures; import 'api_selector_test.dart' show iranBase; void main() { TestWidgetsFlutterBinding.ensureInitialized(); setUp(() => SharedPreferences.setMockInitialValues({})); fixtures.StubAdapter adapter() => fixtures.StubAdapter( (r) => r.uri.path.contains('/first/') ? fixtures.jsonBody({'posters': []}) : fixtures.jsonBody([]), ); for (final locale in ['en', 'fa']) { testWidgets( 'settings hides connection details and preserves migrated library in $locale', (tester) async { final network = adapter(); final state = AppState( api: ApiService(dio: Dio()..httpClientAdapter = network), ); addTearDown(state.dispose); await state.initialize(discover: false); await state.updateSettings(state.prefs.copyWith(locale: locale)); const title = TitleRecord(id: 9, title: 'Saved title'); await state.toggleSaved(title); await state.recordWatch( title, sourceUrl: 'https://media.example/film.mp4?token=exact', positionSeconds: 12, ); await state.createCollection('Keep collection'); final storedLibrary = (await SharedPreferences.getInstance()).getString( AppState.storageKey, ); var notifications = 0; state.addListener(() => notifications++); await tester.pumpWidget( AppScope( state: state, child: const MaterialApp(home: SettingsPage()), ), ); await tester.drag(find.byType(ListView), const Offset(0, -10000)); await tester.pumpAndSettle(); expect(state.api.baseUrl, iranBase); expect(find.text(iranBase), findsNothing); expect(find.byKey(const Key('catalog-api-endpoint')), findsNothing); expect( find.text(locale == 'en' ? 'Iran Catalogue' : 'فهرست ایران'), findsNothing, ); expect(find.byKey(const Key('catalog-api-selector')), findsNothing); expect(find.text('Original API'), findsNothing); expect(find.text('API اصلی'), findsNothing); expect(find.text('Refresh API server'), findsNothing); expect(notifications, 0); expect( network.requests, isEmpty, reason: 'Endpoint information must not probe or offer fallback', ); expect( (await SharedPreferences.getInstance()).getString( AppState.storageKey, ), storedLibrary, ); final preferences = await SharedPreferences.getInstance(); await preferences.setString( 'reelbox.api-selection.v1', 'https://ninwinios.info/api/', ); await preferences.setString( 'reelbox.trusted-api.v1', 'https://ninwinios.info/api/', ); final restarted = AppState( api: ApiService(dio: Dio()..httpClientAdapter = adapter()), ); addTearDown(restarted.dispose); await restarted.initialize(discover: false); expect(preferences.getString(AppState.storageKey), storedLibrary); expect(restarted.api.baseUrl, iranBase); expect(restarted.saved.single.title, 'Saved title'); expect( restarted.history.single.sourceUrl, 'https://media.example/film.mp4?token=exact', ); expect(restarted.collections.single.name, 'Keep collection'); expect(restarted.locale, locale); }, ); } testWidgets( 'Iran-only catalogue normalizes a legacy views browse on first mount', (tester) async { final network = adapter(); final state = AppState( api: ApiService(dio: Dio()..httpClientAdapter = network), ); addTearDown(state.dispose); await state.initialize(discover: false); await tester.pumpWidget( AppScope( state: state, child: const MaterialApp(home: BrowsePage(initialOrder: 'views')), ), ); await tester.pumpAndSettle(); expect(find.text('Most viewed'), findsNothing); expect(find.text('Recently added'), findsOneWidget); final iranRequests = network.requests.where( (r) => r.uri.host == 'reelbox.dartty.top', ); expect(iranRequests.any((r) => r.uri.path.contains('/created/')), isTrue); expect(iranRequests.any((r) => r.uri.path.contains('/views/')), isFalse); await tester.tap(find.byTooltip('Sort titles')); await tester.pumpAndSettle(); expect(find.text('Most viewed'), findsNothing); await tester.tap(find.text('Release year')); await tester.pumpAndSettle(); await tester.pumpWidget( AppScope( state: state, child: const MaterialApp(home: DiscoveryDirectoryPage()), ), ); await tester.pumpAndSettle(); final list = tester.widget(find.byType(ListView)); final children = (list.childrenDelegate as SliverChildListDelegate).children; final titles = children .whereType() .map((tile) => (tile.title as Text).data) .toList(); expect(titles, isNot(contains('Most-viewed movies'))); expect(titles, isNot(contains('Most-viewed series'))); }, ); testWidgets( 'catalogue tabs survive simplified settings without changing local library', (tester) async { final network = adapter(); final state = AppState( api: ApiService(dio: Dio()..httpClientAdapter = network), ); addTearDown(state.dispose); await state.initialize(discover: false); await state.updateSettings(state.prefs.copyWith(introCompleted: true)); await state.toggleSaved(const TitleRecord(id: 9, title: 'Saved title')); await tester.pumpWidget(MyApp(state: state)); await tester.pumpAndSettle(); for (final tab in ['Browse', 'Search', 'Library', 'More']) { await tester.tap(find.widgetWithText(NavigationDestination, tab)); await tester.pumpAndSettle(); } await tester.tap(find.text('Settings')); await tester.pumpAndSettle(); await tester.drag(find.byType(ListView), const Offset(0, -10000)); await tester.pumpAndSettle(); expect(find.text(iranBase), findsNothing); expect(find.byKey(const Key('catalog-api-endpoint')), findsNothing); expect(find.byKey(const Key('catalog-api-selector')), findsNothing); await tester.pageBack(); await tester.pumpAndSettle(); final iranRequests = network.requests .where((r) => r.uri.origin == 'https://reelbox.dartty.top') .toList(); expect(iranRequests.any((r) => r.uri.path.contains('/first/')), isTrue); expect( iranRequests.any((r) => r.uri.path.contains('/movie/by/filtres/')), isTrue, ); expect( iranRequests.any( (r) => r.uri.queryParameters['action'] == 'search-trand', ), isTrue, ); expect(state.saved.single.title, 'Saved title'); await tester.tap(find.widgetWithText(NavigationDestination, 'Library')); await tester.pumpAndSettle(); expect(find.text('Watchlist (1)'), findsOneWidget); expect(tester.takeException(), isNull); }, ); }