# Conflicts: # lib/app/app_controller_web.dart # test/features/ai_gateway_page_test.dart # test/features/assistant_page_test.dart # test/features/mobile/ios_mobile_shell_test.dart # test/features/settings_ai_gateway_persistence_test.dart # test/features/settings_page_test.dart # test/runtime/app_controller_navigation_favorites_test.dart
273 lines
7.7 KiB
Dart
273 lines
7.7 KiB
Dart
@TestOn('vm')
|
|
library;
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:xworkmate/app/ui_feature_manifest.dart';
|
|
import 'package:xworkmate/features/settings/settings_page.dart';
|
|
import 'package:xworkmate/models/app_models.dart';
|
|
import 'package:xworkmate/runtime/desktop_platform_service.dart';
|
|
import 'package:xworkmate/runtime/runtime_models.dart';
|
|
|
|
import '../test_support.dart';
|
|
|
|
class _DesktopServiceStub implements DesktopPlatformService {
|
|
@override
|
|
DesktopIntegrationState get state =>
|
|
DesktopIntegrationState.fromJson(const <String, dynamic>{
|
|
'isSupported': true,
|
|
'environment': 'kde',
|
|
'mode': 'proxy',
|
|
'trayAvailable': true,
|
|
'trayEnabled': true,
|
|
'autostartEnabled': false,
|
|
'networkManagerAvailable': true,
|
|
'systemProxy': {
|
|
'enabled': true,
|
|
'host': '127.0.0.1',
|
|
'port': 7890,
|
|
'backend': 'kioslaverc',
|
|
'lastAppliedMode': 'proxy',
|
|
},
|
|
'tunnel': {
|
|
'available': true,
|
|
'connected': false,
|
|
'connectionName': 'XWorkmate Tunnel',
|
|
'backend': 'nmcli',
|
|
'lastError': '',
|
|
},
|
|
'statusMessage': '',
|
|
});
|
|
|
|
@override
|
|
bool get isSupported => state.isSupported;
|
|
|
|
@override
|
|
Future<void> initialize(LinuxDesktopConfig config) async {}
|
|
|
|
@override
|
|
Future<void> syncConfig(LinuxDesktopConfig config) async {}
|
|
|
|
@override
|
|
Future<void> refresh() async {}
|
|
|
|
@override
|
|
Future<void> setMode(VpnMode mode) async {}
|
|
|
|
@override
|
|
Future<void> connectTunnel() async {}
|
|
|
|
@override
|
|
Future<void> disconnectTunnel() async {}
|
|
|
|
@override
|
|
Future<void> setLaunchAtLogin(bool enabled) async {}
|
|
|
|
@override
|
|
void dispose() {}
|
|
}
|
|
|
|
void main() {
|
|
testWidgets('SettingsPage theme chips update controller theme mode', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final controller = await createTestController(tester);
|
|
|
|
await pumpPage(
|
|
tester,
|
|
child: SettingsPage(controller: controller),
|
|
platform: TargetPlatform.macOS,
|
|
);
|
|
|
|
await tester.tap(find.text('外观'));
|
|
await tester.pumpAndSettle();
|
|
await tester.tap(find.text('深色'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(controller.themeMode, ThemeMode.dark);
|
|
|
|
await tester.tap(find.text('浅色'));
|
|
await tester.pumpAndSettle();
|
|
expect(controller.themeMode, ThemeMode.light);
|
|
});
|
|
|
|
testWidgets('SettingsPage gateway tab exposes device pairing controls', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final controller = await createTestController(tester);
|
|
|
|
await pumpPage(
|
|
tester,
|
|
child: SettingsPage(controller: controller),
|
|
platform: TargetPlatform.macOS,
|
|
);
|
|
|
|
await tester.tap(find.text('集成'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('打开连接面板'), findsOneWidget);
|
|
expect(
|
|
find.byKey(const ValueKey('gateway-device-security-card')),
|
|
findsOneWidget,
|
|
);
|
|
});
|
|
|
|
testWidgets('SettingsPage shows Linux desktop integration controls', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final controller = await createTestController(
|
|
tester,
|
|
desktopPlatformService: _DesktopServiceStub(),
|
|
);
|
|
|
|
await pumpPage(
|
|
tester,
|
|
child: SettingsPage(controller: controller),
|
|
platform: TargetPlatform.macOS,
|
|
);
|
|
|
|
expect(
|
|
find.byKey(const ValueKey('linux-desktop-integration-card')),
|
|
findsOneWidget,
|
|
);
|
|
expect(find.text('Linux 桌面集成'), findsOneWidget);
|
|
expect(find.text('切换到代理'), findsOneWidget);
|
|
expect(find.text('连接隧道'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('SettingsPage multi-agent tab keeps header readable', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final controller = await createTestController(tester);
|
|
|
|
await pumpPage(
|
|
tester,
|
|
child: const SizedBox(width: 1100, height: 900, child: Placeholder()),
|
|
);
|
|
await pumpPage(
|
|
tester,
|
|
child: SizedBox(
|
|
width: 1100,
|
|
height: 900,
|
|
child: SettingsPage(controller: controller),
|
|
),
|
|
);
|
|
|
|
await tester.tap(find.text('多 Agent'));
|
|
await tester.pumpAndSettle();
|
|
|
|
final titleFinder = find.text('多 Agent 协作');
|
|
expect(titleFinder, findsOneWidget);
|
|
expect(tester.getSize(titleFinder).width, greaterThan(80));
|
|
expect(find.text('启用协作模式'), findsOneWidget);
|
|
expect(find.text('协作框架'), findsOneWidget);
|
|
expect(find.textContaining('Lead Engineer'), findsWidgets);
|
|
expect(find.textContaining('ollama launch codex'), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('SettingsPage diagnostics tab filters and clears runtime logs', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final controller = await createTestController(tester);
|
|
controller.runtime.addRuntimeLogForTest(
|
|
level: 'info',
|
|
category: 'connect',
|
|
message: 'connected remote gateway',
|
|
);
|
|
controller.runtime.addRuntimeLogForTest(
|
|
level: 'warn',
|
|
category: 'pairing',
|
|
message: 'pairing required',
|
|
);
|
|
|
|
await pumpPage(tester, child: SettingsPage(controller: controller));
|
|
|
|
await tester.tap(find.text('诊断'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.byKey(const ValueKey('runtime-log-card')), findsOneWidget);
|
|
expect(find.textContaining('connected remote gateway'), findsOneWidget);
|
|
expect(find.textContaining('pairing required'), findsOneWidget);
|
|
|
|
await tester.enterText(
|
|
find.byKey(const ValueKey('runtime-log-filter')),
|
|
'pairing',
|
|
);
|
|
await tester.pump(const Duration(milliseconds: 200));
|
|
|
|
expect(find.textContaining('connected remote gateway'), findsNothing);
|
|
expect(find.textContaining('pairing required'), findsOneWidget);
|
|
|
|
await tester.tap(find.text('清空'));
|
|
await tester.pump(const Duration(milliseconds: 200));
|
|
|
|
expect(controller.runtimeLogs, isEmpty);
|
|
});
|
|
|
|
testWidgets('SettingsPage hides tabs disabled by feature manifest', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final manifest = UiFeatureManifest.fallback()
|
|
.copyWithFeature(
|
|
platform: UiFeaturePlatform.desktop,
|
|
module: 'settings',
|
|
feature: 'diagnostics',
|
|
enabled: false,
|
|
)
|
|
.copyWithFeature(
|
|
platform: UiFeaturePlatform.desktop,
|
|
module: 'settings',
|
|
feature: 'experimental',
|
|
enabled: false,
|
|
);
|
|
final controller = await createTestController(
|
|
tester,
|
|
uiFeatureManifest: manifest,
|
|
);
|
|
|
|
await pumpPage(
|
|
tester,
|
|
child: SettingsPage(controller: controller),
|
|
platform: TargetPlatform.macOS,
|
|
);
|
|
|
|
expect(find.text('诊断'), findsNothing);
|
|
expect(find.text('实验特性'), findsNothing);
|
|
});
|
|
|
|
testWidgets('SettingsPage detail mode returns to overview', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final controller = await createTestController(tester);
|
|
controller.openSettings(
|
|
detail: SettingsDetailPage.gatewayConnection,
|
|
navigationContext: SettingsNavigationContext(
|
|
rootLabel: '模块',
|
|
destination: WorkspaceDestination.nodes,
|
|
sectionLabel: ModulesTab.gateway.label,
|
|
modulesTab: ModulesTab.gateway,
|
|
),
|
|
);
|
|
|
|
await pumpPage(
|
|
tester,
|
|
child: SettingsPage(
|
|
controller: controller,
|
|
initialTab: controller.settingsTab,
|
|
initialDetail: controller.settingsDetail,
|
|
navigationContext: controller.settingsNavigationContext,
|
|
),
|
|
);
|
|
|
|
expect(find.text('Gateway 连接参数'), findsWidgets);
|
|
expect(find.text('返回概览'), findsOneWidget);
|
|
|
|
await tester.tap(find.text('返回概览'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(controller.settingsDetail, isNull);
|
|
expect(find.text('搜索设置'), findsOneWidget);
|
|
});
|
|
}
|