Files
FlClash/test/manager/vpn_manager_test.dart
T
chen08209 d3fa2252b0 feat(android): add launcher shortcuts and one-step on-demand access
Changelog: Launcher shortcuts and one-step on-demand access
2026-10-11 12:28:52 +08:00

179 lines
5.0 KiB
Dart

import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/l10n/l10n.dart';
import 'package:fl_clash/manager/status_manager.dart';
import 'package:fl_clash/manager/vpn_manager.dart';
import 'package:fl_clash/models/models.dart';
import 'package:fl_clash/providers/action.dart';
import 'package:fl_clash/providers/app.dart';
import 'package:fl_clash/providers/config.dart';
import 'package:fl_clash/providers/state.dart';
import 'package:fl_clash/state.dart';
import 'package:material_ui/material_ui.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
class _RestartRecordingSetupAction extends SetupAction {
int restarts = 0;
@override
Future<void> restartVpn() async {
restarts++;
}
}
void main() {
late ProviderContainer container;
late _RestartRecordingSetupAction setupAction;
setUp(() {
setupAction = _RestartRecordingSetupAction();
container = ProviderContainer(
overrides: [setupActionProvider.overrideWith(() => setupAction)],
);
globalState.container = container;
});
tearDown(() => container.dispose());
Future<void> pumpVpnManager(WidgetTester tester) async {
await tester.pumpWidget(
UncontrolledProviderScope(
container: container,
child: MaterialApp(
navigatorKey: globalState.navigatorKey,
localizationsDelegates: const [
AppLocalizations.delegate,
...GlobalMaterialLocalizations.delegates,
],
supportedLocales: AppLocalizations.delegate.supportedLocales,
builder: (_, child) {
return StatusManager(child: VpnManager(child: child!));
},
home: const SizedBox(),
),
),
);
await tester.pump();
}
Future<void> outlastTip(WidgetTester tester) async {
await tester.pump(const Duration(seconds: 7));
await tester.pump(const Duration(milliseconds: 500));
}
Future<void> drainTimers(WidgetTester tester) async {
await outlastTip(tester);
await tester.pumpWidget(const SizedBox.shrink());
}
void startService() {
container.read(runningVpnOptionsProvider.notifier).value = container.read(
vpnOptionsProvider,
);
}
void updateVpn(VpnProps Function(VpnProps state) update) {
container.read(vpnSettingProvider.notifier).update(update);
}
Finder tip() => find.text(currentAppLocalizations.vpnConfigChangeDetected);
testWidgets('a change the running service reads asks for a restart', (
tester,
) async {
await pumpVpnManager(tester);
startService();
updateVpn((state) => state.copyWith(ipv6: !state.ipv6));
await tester.pump();
expect(tip(), findsOneWidget);
await tester.pump(const Duration(milliseconds: 500));
await tester.tap(find.text(currentAppLocalizations.restart));
await tester.pump();
expect(setupAction.restarts, 1);
await drainTimers(tester);
});
testWidgets('a mixed port change asks for a restart under a system proxy', (
tester,
) async {
await pumpVpnManager(tester);
startService();
container
.read(patchClashConfigProvider.notifier)
.update((state) => state.copyWith(mixedPort: state.mixedPort + 1));
await tester.pump();
expect(tip(), findsOneWidget);
await drainTimers(tester);
});
testWidgets('no tip while no service is running', (tester) async {
await pumpVpnManager(tester);
updateVpn((state) => state.copyWith(ipv6: !state.ipv6));
await tester.pump();
expect(tip(), findsNothing);
await drainTimers(tester);
});
testWidgets('no tip for what the service never reads', (tester) async {
await pumpVpnManager(tester);
startService();
updateVpn(
(state) => state.copyWith(
accessControlProps: state.accessControlProps.copyWith(
sort: AccessSortType.name,
isFilterSystemApp: !state.accessControlProps.isFilterSystemApp,
),
),
);
await tester.pump();
expect(tip(), findsNothing);
await drainTimers(tester);
});
testWidgets('changing back to what the service runs asks for nothing', (
tester,
) async {
await pumpVpnManager(tester);
startService();
updateVpn((state) => state.copyWith(ipv6: !state.ipv6));
await tester.pump();
expect(tip(), findsOneWidget);
await outlastTip(tester);
expect(tip(), findsNothing);
updateVpn((state) => state.copyWith(ipv6: !state.ipv6));
await tester.pump();
expect(tip(), findsNothing);
await drainTimers(tester);
});
testWidgets('a restart measures later changes against the new options', (
tester,
) async {
await pumpVpnManager(tester);
startService();
updateVpn((state) => state.copyWith(ipv6: !state.ipv6));
await tester.pump();
await outlastTip(tester);
expect(tip(), findsNothing);
startService();
updateVpn((state) => state.copyWith(ipv6: !state.ipv6));
await tester.pump();
expect(tip(), findsOneWidget);
await drainTimers(tester);
});
}