Files
plezy/test/utils/live_tv_player_navigation_test.dart
T
edde746 316a69a1de refactor: share the paginated grid tab, cached remote store, and tile focus
- PaginatedCardGridTabState: the collections and playlists tabs were 95%
  identical; they now supply only pageSize/fetchPage/idOf instead of each
  duplicating the grid, memo, inflation budget and focus wiring.
- EtagCachedRemoteStore: the anime-lists and fribb mapping stores now share
  one download/cache/isolate-parse/conditional-GET lifecycle.
- FocusableTileStateMixin manages its own initState/didUpdateWidget/dispose
  instead of requiring every caller to forward three lifecycle hooks.

Also drops unused ServerCapabilities entries and dead code in
focusable_list_tile and music/track_row.
2026-07-26 06:09:48 +02:00

151 lines
5.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:plezy/i18n/strings.g.dart';
import 'package:plezy/models/livetv_channel.dart';
import 'package:plezy/media/ids.dart';
import 'package:plezy/media/media_backend.dart';
import 'package:plezy/media/media_server_client.dart';
import 'package:plezy/media/server_capabilities.dart';
import 'package:plezy/providers/multi_server_provider.dart';
import 'package:plezy/screens/video_player_screen.dart';
import 'package:plezy/services/multi_server_manager.dart';
import 'package:plezy/utils/live_tv_player_navigation.dart';
import '../test_helpers/multi_server_fixtures.dart';
void main() {
late MultiServerManager manager;
late MultiServerProvider multiServer;
setUp(() async {
await LocaleSettings.setLocale(AppLocale.bg);
manager = MultiServerManager();
multiServer = testMultiServerProvider(manager);
});
tearDown(() {
multiServer.dispose();
manager.dispose();
LocaleSettings.setLocaleSync(AppLocale.en);
});
Future<void> pumpLauncher(WidgetTester tester, LiveTvChannel channel) async {
await tester.pumpWidget(
TranslationProvider(
child: MaterialApp(
home: Scaffold(
body: Builder(
builder: (context) => TextButton(
onPressed: () =>
navigateToLiveTv(context, multiServer: multiServer, channel: channel, channels: [channel]),
child: const Text('Open'),
),
),
),
),
),
);
}
test('scoped Live TV selection fails closed and unscoped selection retains fallback', () {
final aDvr = LiveTvServerInfo(serverId: 'server-a', dvrKey: 'dvr-a');
final aOtherDvr = LiveTvServerInfo(serverId: 'server-a', dvrKey: 'dvr-other');
final bDvr = LiveTvServerInfo(serverId: 'server-b', dvrKey: 'dvr-b');
multiServer.debugSetLiveTvServersForTesting([bDvr]);
expect(
liveTvServerInfoForChannel(
multiServer,
LiveTvChannel(key: 'channel-a', serverId: 'server-a', liveDvrKey: 'dvr-a'),
),
isNull,
);
multiServer.debugSetLiveTvServersForTesting([aOtherDvr, bDvr]);
expect(
liveTvServerInfoForChannel(
multiServer,
LiveTvChannel(key: 'channel-a', serverId: 'server-a', liveDvrKey: 'dvr-a'),
),
isNull,
reason: 'an explicit DVR must not relax to another DVR on the same server',
);
expect(
liveTvServerInfoForChannel(multiServer, LiveTvChannel(key: 'channel-a', serverId: 'server-a')),
same(aOtherDvr),
);
multiServer.debugSetLiveTvServersForTesting([bDvr, aDvr]);
expect(
liveTvServerInfoForChannel(
multiServer,
LiveTvChannel(key: 'channel-a', serverId: 'server-a', liveDvrKey: 'dvr-a'),
),
same(aDvr),
);
expect(liveTvServerInfoForChannel(multiServer, LiveTvChannel(key: 'legacy-channel')), same(bDvr));
multiServer.debugSetLiveTvServersForTesting(const []);
expect(liveTvServerInfoForChannel(multiServer, LiveTvChannel(key: 'legacy-channel')), isNull);
});
testWidgets('missing scoped server is not replaced by an online server', (tester) async {
manager.debugRegisterClientForTesting(_TestClient(ServerId('server-b')));
multiServer.debugSetLiveTvServersForTesting([LiveTvServerInfo(serverId: 'server-b', dvrKey: 'dvr-b')]);
final channel = LiveTvChannel(key: 'channel-a', title: 'Channel A', serverId: 'server-a', liveDvrKey: 'dvr-a');
await pumpLauncher(tester, channel);
await tester.tap(find.text('Open'));
await tester.pump();
expect(find.byType(VideoPlayerScreen), findsNothing);
expect(find.text('Сървърът за телевизия на живо не е наличен.'), findsOneWidget);
});
testWidgets('unavailable Live TV server error uses the active locale', (tester) async {
final channel = LiveTvChannel(key: 'channel-1', title: 'Channel');
await pumpLauncher(tester, channel);
await tester.tap(find.text('Open'));
await tester.pump();
expect(find.text('Сървърът за телевизия на живо не е наличен.'), findsOneWidget);
expect(find.text('Live TV server is not available.'), findsNothing);
});
testWidgets('disconnected Live TV server error uses the active locale', (tester) async {
const serverId = 'server-1';
final channel = LiveTvChannel(key: 'channel-1', title: 'Channel', serverId: serverId, liveDvrKey: 'dvr-1');
multiServer.debugSetLiveTvServersForTesting([LiveTvServerInfo(serverId: serverId, dvrKey: 'dvr-1')]);
await pumpLauncher(tester, channel);
await tester.tap(find.text('Open'));
await tester.pump();
expect(find.text('Сървърът за телевизия на живо не е свързан.'), findsOneWidget);
expect(find.text('Live TV server is not connected.'), findsNothing);
});
}
class _TestClient implements MediaServerClient {
_TestClient(this.serverId);
@override
final ServerId serverId;
@override
String? get serverName => 'Test server';
@override
MediaBackend get backend => MediaBackend.jellyfin;
@override
ServerCapabilities get capabilities => const ServerCapabilities(liveTv: true);
@override
void close() {}
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}