jellyfin_settings_card_test.dart 4.4 KB

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