jellyfin_settings_card_test.dart 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import 'package:cardash_launcher/core/theme/app_theme.dart';
  2. import 'package:cardash_launcher/data/models/jellyfin_models.dart';
  3. import 'package:cardash_launcher/data/repositories/settings_repository.dart';
  4. import 'package:cardash_launcher/data/services/jellyfin_service.dart';
  5. import 'package:cardash_launcher/data/services/secure_store.dart';
  6. import 'package:cardash_launcher/features/settings/jellyfin_controller.dart';
  7. import 'package:cardash_launcher/features/settings/jellyfin_settings_card.dart';
  8. import 'package:flutter/material.dart';
  9. import 'package:flutter_test/flutter_test.dart';
  10. import 'package:provider/provider.dart';
  11. import 'package:shared_preferences/shared_preferences.dart';
  12. class _MemoryStore implements SecureStore {
  13. final values = <String, String>{};
  14. @override
  15. Future<String?> read(String key) async => values[key];
  16. @override
  17. Future<void> write(String key, String value) async {
  18. values[key] = value;
  19. }
  20. @override
  21. Future<void> delete(String key) async {
  22. values.remove(key);
  23. }
  24. }
  25. class _FakeGateway implements JellyfinGateway {
  26. @override
  27. Future<JellyfinServerInfo> serverInfo(Uri baseUrl) async {
  28. return const JellyfinServerInfo(name: 'DarkTower', version: '12.2.0');
  29. }
  30. @override
  31. Future<JellyfinQuickConnect> startQuickConnect(
  32. Uri baseUrl, {
  33. required String deviceId,
  34. }) async {
  35. return const JellyfinQuickConnect(code: '491006', secret: 'secret');
  36. }
  37. @override
  38. Future<bool> isQuickConnectApproved(Uri baseUrl, String secret) async {
  39. return false;
  40. }
  41. @override
  42. Future<JellyfinSession> authenticateQuickConnect(
  43. Uri baseUrl,
  44. String secret, {
  45. required String deviceId,
  46. }) async {
  47. return const JellyfinSession(
  48. accessToken: 'token-1',
  49. userId: 'user-1',
  50. userName: 'wasp',
  51. );
  52. }
  53. @override
  54. Future<JellyfinUser> currentUser(Uri baseUrl, String token) async {
  55. return const JellyfinUser(id: 'user-1', name: 'wasp');
  56. }
  57. @override
  58. void close() {}
  59. }
  60. void main() {
  61. testWidgets(
  62. 'Jellyfin card shows the URL field, then the Quick Connect code',
  63. (tester) async {
  64. await tester.binding.setSurfaceSize(const Size(900, 700));
  65. addTearDown(() => tester.binding.setSurfaceSize(null));
  66. SharedPreferences.setMockInitialValues({});
  67. final prefs = await SharedPreferences.getInstance();
  68. final controller = JellyfinController(
  69. SettingsRepository(prefs),
  70. _FakeGateway(),
  71. _MemoryStore(),
  72. pollInterval: const Duration(milliseconds: 10),
  73. pairingLifetime: const Duration(seconds: 30),
  74. );
  75. addTearDown(controller.dispose);
  76. await controller.initialize();
  77. await tester.pumpWidget(
  78. MaterialApp(
  79. theme: AppTheme.light(),
  80. home: ChangeNotifierProvider<JellyfinController>.value(
  81. value: controller,
  82. child: const Scaffold(
  83. body: SizedBox(
  84. width: 720,
  85. child: Padding(
  86. padding: EdgeInsets.all(24),
  87. child: JellyfinSettingsCard(),
  88. ),
  89. ),
  90. ),
  91. ),
  92. ),
  93. );
  94. await tester.pumpAndSettle();
  95. expect(find.text('Jellyfin'), findsOneWidget);
  96. expect(find.text('Off'), findsOneWidget);
  97. expect(find.text('Server URL'), findsNothing);
  98. await tester.tap(find.byType(Switch));
  99. await tester.pumpAndSettle();
  100. expect(find.text('Server URL'), findsOneWidget);
  101. expect(find.text('Connect'), findsOneWidget);
  102. await tester.enterText(find.byType(TextField), 'jellyfin.example.com');
  103. await tester.tap(find.text('Connect'));
  104. await tester.pump();
  105. await tester.pump(const Duration(milliseconds: 20));
  106. expect(find.text('Quick Connect code'), findsOneWidget);
  107. expect(find.text('491006'), findsOneWidget);
  108. expect(find.text('Waiting for approval'), findsOneWidget);
  109. expect(tester.takeException(), isNull);
  110. controller.cancelPairing();
  111. await tester.pump();
  112. },
  113. );
  114. }