@@ -0,0 +1,93 @@
|
||||
import 'package:drift/native.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:plezy/connection/connection.dart';
|
||||
import 'package:plezy/connection/connection_registry.dart';
|
||||
import 'package:plezy/database/app_database.dart';
|
||||
import 'package:plezy/focus/input_mode_tracker.dart';
|
||||
import 'package:plezy/providers/download_provider.dart';
|
||||
import 'package:plezy/providers/multi_server_provider.dart';
|
||||
import 'package:plezy/screens/downloads/downloads_screen.dart';
|
||||
import 'package:plezy/services/data_aggregation_service.dart';
|
||||
import 'package:plezy/services/download_manager_service.dart';
|
||||
import 'package:plezy/services/download_storage_service.dart';
|
||||
import 'package:plezy/services/jellyfin_api_cache.dart';
|
||||
import 'package:plezy/services/multi_server_manager.dart';
|
||||
import 'package:plezy/services/plex_api_cache.dart';
|
||||
import 'package:plezy/services/settings_service.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../test_helpers/prefs.dart';
|
||||
|
||||
class _FakeConnectionRegistry extends ConnectionRegistry {
|
||||
_FakeConnectionRegistry(super.db);
|
||||
|
||||
@override
|
||||
Stream<List<Connection>> watchConnections() => Stream.value(const []);
|
||||
}
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
late AppDatabase db;
|
||||
late DownloadProvider downloadProvider;
|
||||
late MultiServerProvider multiServerProvider;
|
||||
late MultiServerManager serverManager;
|
||||
|
||||
setUp(() async {
|
||||
resetSharedPreferencesForTest();
|
||||
SettingsService.resetForTesting();
|
||||
await SettingsService.getInstance();
|
||||
|
||||
db = AppDatabase.forTesting(NativeDatabase.memory());
|
||||
PlexApiCache.initialize(db);
|
||||
JellyfinApiCache.initialize(db);
|
||||
|
||||
final downloadManager = DownloadManagerService(database: db, storageService: DownloadStorageService.instance);
|
||||
downloadProvider = DownloadProvider.forTesting(downloadManager: downloadManager, database: db);
|
||||
await downloadProvider.ensureInitialized();
|
||||
|
||||
serverManager = MultiServerManager();
|
||||
multiServerProvider = MultiServerProvider(serverManager, DataAggregationService(serverManager));
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
downloadProvider.dispose();
|
||||
multiServerProvider.dispose();
|
||||
await db.close();
|
||||
});
|
||||
|
||||
testWidgets('right from Movies focuses and opens Sync Rules action', (tester) async {
|
||||
final screenKey = GlobalKey<DownloadsScreenState>();
|
||||
|
||||
await tester.pumpWidget(
|
||||
InputModeTracker(
|
||||
child: MultiProvider(
|
||||
providers: [
|
||||
Provider<ConnectionRegistry>.value(value: _FakeConnectionRegistry(db)),
|
||||
ChangeNotifierProvider<DownloadProvider>.value(value: downloadProvider),
|
||||
ChangeNotifierProvider<MultiServerProvider>.value(value: multiServerProvider),
|
||||
],
|
||||
child: MaterialApp(
|
||||
theme: ThemeData(platform: TargetPlatform.macOS),
|
||||
home: DownloadsScreen(key: screenKey),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final state = screenKey.currentState!;
|
||||
state.tabController.index = 2;
|
||||
state.getTabChipFocusNode(2).requestFocus();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.enter);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Sync rules'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
import 'package:drift/native.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/testing.dart';
|
||||
import 'package:plezy/connection/connection.dart';
|
||||
import 'package:plezy/connection/connection_registry.dart';
|
||||
import 'package:plezy/database/app_database.dart';
|
||||
import 'package:plezy/focus/input_mode_tracker.dart';
|
||||
import 'package:plezy/media/media_backend.dart';
|
||||
import 'package:plezy/media/media_item.dart';
|
||||
import 'package:plezy/media/media_kind.dart';
|
||||
@@ -123,7 +125,7 @@ void main() {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> pumpScreen(WidgetTester tester) async {
|
||||
Future<void> pumpScreen(WidgetTester tester, {bool keyboardMode = false}) async {
|
||||
downloadProvider.debugSeedState(
|
||||
metadata: {
|
||||
'plex-srv:show-1': _show('plex-srv', 'show-1', 'Plex Show'),
|
||||
@@ -133,19 +135,40 @@ void main() {
|
||||
},
|
||||
);
|
||||
|
||||
Widget buildScreen() => MultiProvider(
|
||||
providers: [
|
||||
Provider<ConnectionRegistry>.value(value: connectionRegistry),
|
||||
ChangeNotifierProvider<DownloadProvider>.value(value: downloadProvider),
|
||||
ChangeNotifierProvider<MultiServerProvider>.value(value: multiServerProvider!),
|
||||
],
|
||||
child: const MaterialApp(home: SyncRulesScreen()),
|
||||
);
|
||||
|
||||
if (!keyboardMode) {
|
||||
await tester.pumpWidget(buildScreen());
|
||||
await tester.pump();
|
||||
return;
|
||||
}
|
||||
|
||||
final showScreen = ValueNotifier(false);
|
||||
addTearDown(showScreen.dispose);
|
||||
await tester.pumpWidget(
|
||||
MultiProvider(
|
||||
providers: [
|
||||
Provider<ConnectionRegistry>.value(value: connectionRegistry),
|
||||
ChangeNotifierProvider<DownloadProvider>.value(value: downloadProvider),
|
||||
ChangeNotifierProvider<MultiServerProvider>.value(value: multiServerProvider!),
|
||||
],
|
||||
child: const MaterialApp(home: SyncRulesScreen()),
|
||||
InputModeTracker(
|
||||
child: ValueListenableBuilder<bool>(
|
||||
valueListenable: showScreen,
|
||||
builder: (context, show, _) => show ? buildScreen() : const MaterialApp(home: SizedBox.shrink()),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
|
||||
await tester.pump();
|
||||
showScreen.value = true;
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
String? primaryFocusLabel() => FocusManager.instance.primaryFocus?.debugLabel;
|
||||
|
||||
testWidgets('shows server context and active-profile availability for device sync rules', (tester) async {
|
||||
connections.add(
|
||||
PlexAccountConnection(
|
||||
@@ -192,4 +215,81 @@ void main() {
|
||||
expect(find.text('Unknown Show'), findsOneWidget);
|
||||
expect(find.text('Server: unknown-srv • Unknown server'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('removes orphaned sync rules from the sync rules screen', (tester) async {
|
||||
multiServerProvider = MultiServerProvider(serverManager, DataAggregationService(serverManager));
|
||||
await insertRule('orphan-srv', '76672');
|
||||
|
||||
await pumpScreen(tester);
|
||||
|
||||
expect(find.text('76672'), findsOneWidget);
|
||||
|
||||
await tester.drag(find.text('76672'), const Offset(-140, 0));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.byKey(const ValueKey('sync_rule_swipe_delete')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Stop syncing "76672"? Downloaded episodes will be kept.'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.widgetWithText(FilledButton, 'Remove sync rule'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(downloadProvider.syncRules, isEmpty);
|
||||
expect(find.text('76672'), findsNothing);
|
||||
expect(find.text('No sync rules'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('does not autofocus the first sync rule in pointer mode', (tester) async {
|
||||
multiServerProvider = MultiServerProvider(serverManager, DataAggregationService(serverManager));
|
||||
await insertRule('orphan-srv', '76672');
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
|
||||
await pumpScreen(tester);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(primaryFocusLabel(), isNot('sync_rule_row'));
|
||||
});
|
||||
|
||||
testWidgets('keyboard navigation reaches and toggles the sync rule switch', (tester) async {
|
||||
multiServerProvider = MultiServerProvider(serverManager, DataAggregationService(serverManager));
|
||||
await insertRule('orphan-srv', '76672');
|
||||
|
||||
await pumpScreen(tester, keyboardMode: true);
|
||||
|
||||
expect(primaryFocusLabel(), 'sync_rule_row');
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
|
||||
await tester.pumpAndSettle();
|
||||
expect(primaryFocusLabel(), 'sync_rule_switch');
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.enter);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(downloadProvider.syncRules.values.single.enabled, isFalse);
|
||||
});
|
||||
|
||||
testWidgets('setting sync rule count to zero removes the rule', (tester) async {
|
||||
multiServerProvider = MultiServerProvider(serverManager, DataAggregationService(serverManager));
|
||||
await insertRule('orphan-srv', '76672');
|
||||
|
||||
await pumpScreen(tester, keyboardMode: true);
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.enter);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.enterText(find.byType(TextField), '0');
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.enter);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Stop syncing "76672"? Downloaded episodes will be kept.'), findsOneWidget);
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.enter);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(downloadProvider.syncRules, isEmpty);
|
||||
expect(find.text('No sync rules'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user