import 'package:cardash_launcher/core/theme/app_theme.dart'; import 'package:cardash_launcher/data/models/jellyfin_models.dart'; import 'package:cardash_launcher/data/repositories/settings_repository.dart'; import 'package:cardash_launcher/data/services/jellyfin_service.dart'; import 'package:cardash_launcher/data/services/secure_store.dart'; import 'package:cardash_launcher/features/settings/jellyfin_controller.dart'; import 'package:cardash_launcher/features/settings/jellyfin_settings_card.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; class _MemoryStore implements SecureStore { final values = {}; @override Future read(String key) async => values[key]; @override Future write(String key, String value) async { values[key] = value; } @override Future delete(String key) async { values.remove(key); } } class _FakeGateway implements JellyfinGateway { @override Future serverInfo(Uri baseUrl) async { return const JellyfinServerInfo(name: 'DarkTower', version: '12.2.0'); } @override Future startQuickConnect( Uri baseUrl, { required String deviceId, }) async { return const JellyfinQuickConnect(code: '491006', secret: 'secret'); } @override Future isQuickConnectApproved(Uri baseUrl, String secret) async { return false; } @override Future authenticateQuickConnect( Uri baseUrl, String secret, { required String deviceId, }) async { return const JellyfinSession( accessToken: 'token-1', userId: 'user-1', userName: 'wasp', ); } @override Future currentUser(Uri baseUrl, String token) async { return const JellyfinUser(id: 'user-1', name: 'wasp'); } @override void close() {} } void main() { testWidgets( 'Jellyfin card shows the URL field, then the Quick Connect code', (tester) async { await tester.binding.setSurfaceSize(const Size(900, 700)); addTearDown(() => tester.binding.setSurfaceSize(null)); SharedPreferences.setMockInitialValues({}); final prefs = await SharedPreferences.getInstance(); final controller = JellyfinController( SettingsRepository(prefs), _FakeGateway(), _MemoryStore(), pollInterval: const Duration(milliseconds: 10), pairingLifetime: const Duration(seconds: 30), ); addTearDown(controller.dispose); await controller.initialize(); await tester.pumpWidget( MaterialApp( theme: AppTheme.light(), home: ChangeNotifierProvider.value( value: controller, child: const Scaffold( body: SizedBox( width: 720, child: Padding( padding: EdgeInsets.all(24), child: JellyfinSettingsCard(), ), ), ), ), ), ); await tester.pumpAndSettle(); expect(find.text('Jellyfin'), findsOneWidget); expect(find.text('Off'), findsOneWidget); expect(find.text('Server URL'), findsNothing); await tester.tap(find.byType(Switch)); await tester.pumpAndSettle(); expect(find.text('Server URL'), findsOneWidget); expect(find.text('Connect'), findsOneWidget); await tester.enterText(find.byType(TextField), 'jellyfin.example.com'); await tester.tap(find.text('Connect')); await tester.pump(); await tester.pump(const Duration(milliseconds: 20)); expect(find.text('Quick Connect code'), findsOneWidget); expect(find.text('491006'), findsOneWidget); expect(find.text('Waiting for approval'), findsOneWidget); expect(tester.takeException(), isNull); controller.cancelPairing(); await tester.pump(); }, ); }