fix proxy name resolution

This commit is contained in:
Fabian Freund
2026-05-24 09:29:02 +02:00
parent e34acf2777
commit 0b0ef38636
10 changed files with 233 additions and 15 deletions
@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -5,6 +7,9 @@ import 'package:weblibre/features/geckoview/features/tabs/data/models/container_
import 'package:weblibre/features/geckoview/features/tabs/presentation/screens/container_edit.dart';
import 'package:weblibre/features/proxy/data/proxy_connection.dart';
import 'package:weblibre/features/proxy/domain/providers/proxy_connection_options.dart';
import 'package:weblibre/features/proxy/domain/repositories/singbox_proxy_profiles.dart';
import 'package:weblibre/features/user/data/database/definitions.drift.dart'
show ProxyProfile;
void main() {
testWidgets(
@@ -16,6 +21,9 @@ void main() {
proxyConnectionOptionsProvider.overrideWith(
(ref) => const <ProxyConnectionOption>[],
),
singboxProxyProfilesRepositoryProvider.overrideWith(
() => _LoadedProfilesRepository(const []),
),
],
child: MaterialApp(
home: ContainerEditScreen.create(
@@ -24,7 +32,9 @@ void main() {
color: Colors.blue,
orderKey: 'a',
metadata: ContainerMetadata.withDefaults(
proxyConnectionId: const SingboxProxyConnectionId('missing-proxy'),
proxyConnectionId: const SingboxProxyConnectionId(
'missing-proxy',
),
),
),
),
@@ -56,6 +66,9 @@ void main() {
proxyConnectionOptionsProvider.overrideWith(
(ref) => const <ProxyConnectionOption>[],
),
singboxProxyProfilesRepositoryProvider.overrideWith(
() => _LoadedProfilesRepository(const []),
),
],
child: MaterialApp(
home: ContainerEditScreen.create(
@@ -83,4 +96,58 @@ void main() {
expect(find.text('New Container'), findsOneWidget);
},
);
testWidgets('does not offer to clear selected proxy while profiles load', (
tester,
) async {
await tester.pumpWidget(
ProviderScope(
overrides: [
proxyConnectionOptionsProvider.overrideWith(
(ref) => const <ProxyConnectionOption>[],
),
singboxProxyProfilesRepositoryProvider.overrideWith(
() => _LoadingProfilesRepository(),
),
],
child: MaterialApp(
home: ContainerEditScreen.create(
initialContainer: ContainerData(
id: 'container-1',
color: Colors.blue,
orderKey: 'a',
metadata: ContainerMetadata.withDefaults(
proxyConnectionId: const SingboxProxyConnectionId('profile-1'),
),
),
),
),
),
);
await tester.pumpAndSettle();
expect(find.text('Loading proxy...'), findsOneWidget);
await tester.tap(find.text('Proxy Connection'));
await tester.pumpAndSettle();
expect(find.text('Unknown proxy'), findsNothing);
expect(find.text('Clear'), findsNothing);
});
}
class _LoadedProfilesRepository extends SingboxProxyProfilesRepository {
final List<ProxyProfile> profiles;
_LoadedProfilesRepository(this.profiles);
@override
Stream<List<ProxyProfile>> build() => Stream.value(profiles);
}
class _LoadingProfilesRepository extends SingboxProxyProfilesRepository {
@override
Stream<List<ProxyProfile>> build() async* {
await Completer<void>().future;
}
}
@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_singbox_proxy/flutter_singbox_proxy.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -5,8 +7,11 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:weblibre/features/geckoview/features/tabs/data/models/container_data.dart';
import 'package:weblibre/features/proxy/data/proxy_connection.dart';
import 'package:weblibre/features/proxy/domain/providers/proxy_connection_options.dart';
import 'package:weblibre/features/proxy/domain/repositories/singbox_proxy_profiles.dart';
import 'package:weblibre/features/proxy/domain/repositories/singbox_proxy_runtime.dart';
import 'package:weblibre/features/proxy/presentation/controllers/ensure_proxy_started.dart';
import 'package:weblibre/features/user/data/database/definitions.drift.dart'
show ProxyProfile;
void main() {
testWidgets(
@@ -47,10 +52,7 @@ void main() {
await tester.pumpAndSettle();
expect(find.text('Start Proxy Connection?'), findsOneWidget);
expect(
find.textContaining('This tab needs Mullvad'),
findsOneWidget,
);
expect(find.textContaining('This tab needs Mullvad'), findsOneWidget);
await tester.tap(find.text('Start'));
await tester.pumpAndSettle();
@@ -59,6 +61,56 @@ void main() {
expect(find.text('result:true'), findsOneWidget);
},
);
testWidgets('resolves sing-box prompt title while profile options load', (
tester,
) async {
final runtimeRepository = _ErrorRuntimeRepository();
final profilesRepository = _LoadingProfilesRepository([
_profile(id: 'profile-1', name: 'Mullvad'),
]);
final container = ContainerData(
id: 'container-1',
color: Colors.blue,
orderKey: 'a',
metadata: ContainerMetadata.withDefaults(
proxyConnectionId: const SingboxProxyConnectionId('profile-1'),
),
);
await tester.pumpWidget(
ProviderScope(
overrides: [
singboxProxyRuntimeRepositoryProvider.overrideWith(
() => runtimeRepository,
),
singboxProxyProfilesRepositoryProvider.overrideWith(
() => profilesRepository,
),
],
child: MaterialApp(home: _EnsureProxyHarness(container: container)),
),
);
await tester.pumpAndSettle();
await tester.tap(find.text('Open container'));
await tester.pumpAndSettle();
expect(find.textContaining('This tab needs Mullvad'), findsOneWidget);
expect(find.textContaining('Unknown proxy'), findsNothing);
});
}
ProxyProfile _profile({required String id, required String name}) {
final createdAt = DateTime(2026);
return ProxyProfile(
id: id,
name: name,
type: SingboxProxyProfileType.customOutbound,
configJson: '{"type":"socks"}',
createdAt: createdAt,
updatedAt: createdAt,
);
}
class _EnsureProxyHarness extends ConsumerStatefulWidget {
@@ -128,3 +180,22 @@ class _ErrorRuntimeRepository extends SingboxProxyRuntimeRepository {
);
}
}
class _LoadingProfilesRepository extends SingboxProxyProfilesRepository {
final List<ProxyProfile> profiles;
_LoadingProfilesRepository(this.profiles);
@override
Stream<List<ProxyProfile>> build() async* {
await Completer<void>().future;
}
@override
Future<ProxyProfile?> findProfile(String id) async {
for (final profile in profiles) {
if (profile.id == id) return profile;
}
return null;
}
}