fix(jellyfin): harden local discovery flow
This commit is contained in:
@@ -132,6 +132,8 @@ void main() {
|
||||
await tester.testTextInput.receiveAction(TextInputAction.go);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(FocusManager.instance.primaryFocus?.debugLabel, 'AddJellyfin:Username');
|
||||
|
||||
await tester.tap(find.byType(TextField).first);
|
||||
await tester.pump();
|
||||
|
||||
@@ -191,6 +193,51 @@ void main() {
|
||||
expect(find.text('Jellyfin 10.9.0'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('D-pad can navigate through discovered Jellyfin servers', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
InputModeTracker(
|
||||
child: MaterialApp(
|
||||
home: AddJellyfinScreen(
|
||||
localDiscoveryFactory: () async => [
|
||||
DiscoveredJellyfinServer(address: 'http://192.168.1.20:8096', id: 'srv-1', name: 'Home'),
|
||||
DiscoveredJellyfinServer(address: 'http://192.168.1.30:8096', id: 'srv-2', name: 'Office'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Home'), findsOneWidget);
|
||||
expect(find.text('Office'), findsOneWidget);
|
||||
expect(find.byType(OutlinedButton), findsNothing);
|
||||
|
||||
await tester.tap(find.byType(TextField).first);
|
||||
await tester.pump();
|
||||
|
||||
expect(FocusManager.instance.primaryFocus?.debugLabel, 'AddJellyfin:Url');
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
|
||||
await tester.pump();
|
||||
|
||||
expect(FocusManager.instance.primaryFocus?.debugLabel, 'AddJellyfin:Discovered:srv-1');
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
|
||||
await tester.pump();
|
||||
|
||||
expect(FocusManager.instance.primaryFocus?.debugLabel, 'AddJellyfin:Discovered:srv-2');
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
|
||||
await tester.pump();
|
||||
|
||||
expect(FocusManager.instance.primaryFocus?.debugLabel, 'AddJellyfin:FindServer');
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp);
|
||||
await tester.pump();
|
||||
|
||||
expect(FocusManager.instance.primaryFocus?.debugLabel, 'AddJellyfin:Discovered:srv-2');
|
||||
});
|
||||
|
||||
group('Jellyfin profile binding decisions', () {
|
||||
test('creates a local profile only on true first-run with no profiles', () {
|
||||
expect(shouldCreateLocalJellyfinProfile(targetProfile: null, activeProfile: null, hasProfiles: false), isTrue);
|
||||
|
||||
@@ -58,7 +58,7 @@ void main() {
|
||||
final result = await discovery.raceEndpoints(
|
||||
input.probeBaseUrls,
|
||||
baseUrlsToPersist: input.explicitBaseUrls,
|
||||
baseUrlsToValidate: input.explicitBaseUrls,
|
||||
baseUrlValidationGroups: input.validationBaseUrlGroups,
|
||||
);
|
||||
|
||||
expect(result.activeBaseUrl, 'http://jf.example.com:8096');
|
||||
@@ -79,7 +79,7 @@ void main() {
|
||||
final result = await discovery.raceEndpoints(
|
||||
input.probeBaseUrls,
|
||||
baseUrlsToPersist: input.explicitBaseUrls,
|
||||
baseUrlsToValidate: input.explicitBaseUrls,
|
||||
baseUrlValidationGroups: input.validationBaseUrlGroups,
|
||||
);
|
||||
|
||||
expect(result.baseUrls, ['http://192.168.1.10:8096']);
|
||||
@@ -102,12 +102,36 @@ void main() {
|
||||
final result = await discovery.raceEndpoints(
|
||||
input.probeBaseUrls,
|
||||
baseUrlsToPersist: input.explicitBaseUrls,
|
||||
baseUrlsToValidate: input.explicitBaseUrls,
|
||||
baseUrlValidationGroups: input.validationBaseUrlGroups,
|
||||
);
|
||||
|
||||
expect(result.baseUrls, [result.activeBaseUrl]);
|
||||
});
|
||||
|
||||
test('rejects different servers reached from separate shorthand entries', () async {
|
||||
final discovery = JellyfinEndpointDiscovery(
|
||||
testHttpClientFactory: () => MockClient((req) async {
|
||||
if (req.url.scheme == 'http' && req.url.host == 'one.example.com' && req.url.port == 8096) {
|
||||
return _info(id: 'srv-1');
|
||||
}
|
||||
if (req.url.scheme == 'http' && req.url.host == 'two.example.com' && req.url.port == 8096) {
|
||||
return _info(id: 'srv-2');
|
||||
}
|
||||
throw TimeoutException('offline');
|
||||
}),
|
||||
);
|
||||
final input = JellyfinEndpointDiscovery.buildUserInputCandidates(['one.example.com', 'two.example.com']);
|
||||
|
||||
await expectLater(
|
||||
discovery.raceEndpoints(
|
||||
input.probeBaseUrls,
|
||||
baseUrlsToPersist: input.explicitBaseUrls,
|
||||
baseUrlValidationGroups: input.validationBaseUrlGroups,
|
||||
),
|
||||
throwsA(isA<MediaServerUrlException>()),
|
||||
);
|
||||
});
|
||||
|
||||
test('retains explicit user-entered failover URLs when using input candidates', () async {
|
||||
final discovery = JellyfinEndpointDiscovery(
|
||||
testHttpClientFactory: () => MockClient((req) async {
|
||||
@@ -125,7 +149,7 @@ void main() {
|
||||
final result = await discovery.raceEndpoints(
|
||||
input.probeBaseUrls,
|
||||
baseUrlsToPersist: input.explicitBaseUrls,
|
||||
baseUrlsToValidate: input.explicitBaseUrls,
|
||||
baseUrlValidationGroups: input.validationBaseUrlGroups,
|
||||
);
|
||||
|
||||
expect(result.activeBaseUrl, 'https://jf.example.com');
|
||||
|
||||
@@ -31,5 +31,15 @@ void main() {
|
||||
isNull,
|
||||
);
|
||||
});
|
||||
|
||||
test('sorts discovered servers deterministically', () {
|
||||
final sorted = JellyfinLanDiscoveryService.sortDiscoveredServers([
|
||||
DiscoveredJellyfinServer(address: 'http://192.168.1.20:8096', id: 'srv-2', name: 'Home'),
|
||||
DiscoveredJellyfinServer(address: 'http://192.168.1.10:8096', id: 'srv-3', name: 'Office'),
|
||||
DiscoveredJellyfinServer(address: 'http://192.168.1.20:8096', id: 'srv-1', name: 'Home'),
|
||||
]);
|
||||
|
||||
expect(sorted.map((server) => server.id), ['srv-1', 'srv-2', 'srv-3']);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user