diff --git a/test/features/settings/settings_account_panel_test.dart b/test/features/settings/settings_account_panel_test.dart index da1cc7bd..dc982404 100644 --- a/test/features/settings/settings_account_panel_test.dart +++ b/test/features/settings/settings_account_panel_test.dart @@ -64,108 +64,126 @@ void main() { expect(loginCount, 1); }); - testWidgets('shows account sync status, resync, and exit in signed-in mode', ( - tester, - ) async { - final controllers = _TestControllers(); - addTearDown(controllers.dispose); + testWidgets( + 'shows account sync status, resync, and exit in signed-in mode', + (tester) async { + final controllers = _TestControllers(); + addTearDown(controllers.dispose); - var syncCount = 0; - var logoutCount = 0; + var syncCount = 0; + var logoutCount = 0; - final settings = SettingsSnapshot.defaults().copyWith( - accountBaseUrl: 'https://accounts.svc.plus', - accountUsername: 'review@svc.plus', - acpBridgeServerModeConfig: AcpBridgeServerModeConfig.defaults() - .copyWith( - cloudSynced: AcpBridgeServerModeConfig.defaults().cloudSynced - .copyWith( - lastSyncAt: DateTime( - 2026, - 4, - 12, - 10, - 0, - ).millisecondsSinceEpoch, - remoteServerSummary: AcpBridgeServerModeConfig.defaults() - .cloudSynced - .remoteServerSummary - .copyWith(endpoint: 'https://bridge.svc.plus'), - ), - ), - ); - - await tester.pumpWidget( - _buildTestApp( - child: SettingsAccountPanel( - settings: settings, - accountSession: const AccountSessionSummary( - userId: 'u-1', - email: 'review@svc.plus', - name: 'Review User', - role: 'operator', - mfaEnabled: true, - totpEnabled: true, - ), - accountState: AccountSyncState.defaults().copyWith( - syncState: 'ready', - syncMessage: 'Bridge access synced', - profileScope: 'bridge', - tokenConfigured: const AccountTokenConfigured( - bridge: true, - vault: false, - apisix: false, + final settings = SettingsSnapshot.defaults().copyWith( + accountBaseUrl: 'https://accounts.svc.plus', + accountUsername: 'review@svc.plus', + acpBridgeServerModeConfig: AcpBridgeServerModeConfig.defaults() + .copyWith( + cloudSynced: AcpBridgeServerModeConfig.defaults().cloudSynced + .copyWith( + lastSyncAt: DateTime( + 2026, + 4, + 12, + 10, + 0, + ).millisecondsSinceEpoch, + remoteServerSummary: AcpBridgeServerModeConfig.defaults() + .cloudSynced + .remoteServerSummary + .copyWith(endpoint: 'https://bridge.svc.plus'), + ), ), + ); + + await tester.pumpWidget( + _buildTestApp( + child: SettingsAccountPanel( + settings: settings, + accountSession: const AccountSessionSummary( + userId: 'u-1', + email: 'review@svc.plus', + name: 'Review User', + role: 'operator', + mfaEnabled: true, + totpEnabled: true, + ), + accountState: AccountSyncState.defaults().copyWith( + syncState: 'ready', + syncMessage: 'Bridge access synced', + profileScope: 'bridge', + tokenConfigured: const AccountTokenConfigured( + bridge: true, + vault: false, + apisix: false, + ), + ), + accountBusy: false, + accountSignedIn: true, + accountMfaRequired: false, + accountBaseUrlController: controllers.baseUrl, + accountIdentifierController: controllers.identifier, + accountPasswordController: controllers.password, + accountMfaCodeController: controllers.mfaCode, + bridgeUrlController: controllers.bridgeUrl, + bridgeTokenController: controllers.bridgeToken, + onSaveAccountProfile: ({required bool isManualBridge}) async {}, + onLogin: () async {}, + onVerifyMfa: () async {}, + onCancelMfa: () async {}, + onSync: () async { + syncCount += 1; + }, + onLogout: () async { + logoutCount += 1; + }, ), - accountBusy: false, - accountSignedIn: true, - accountMfaRequired: false, - accountBaseUrlController: controllers.baseUrl, - accountIdentifierController: controllers.identifier, - accountPasswordController: controllers.password, - accountMfaCodeController: controllers.mfaCode, - bridgeUrlController: controllers.bridgeUrl, - bridgeTokenController: controllers.bridgeToken, - onSaveAccountProfile: ({required bool isManualBridge}) async {}, - onLogin: () async {}, - onVerifyMfa: () async {}, - onCancelMfa: () async {}, - onSync: () async { - syncCount += 1; - }, - onLogout: () async { - logoutCount += 1; - }, ), - ), - ); + ); - expect(find.text('账号登录与同步'), findsOneWidget); - expect(find.text('账号同步'), findsOneWidget); - expect(find.textContaining('账号同步状态'), findsOneWidget); - expect(find.byKey(const ValueKey('settings-account-sync-button')), findsOneWidget); - expect(find.byKey(const ValueKey('settings-account-manual-reset-button')), findsNothing); - expect( - find.byKey(const ValueKey('settings-account-logout-button')), - findsOneWidget, - ); + expect(find.text('账号登录与同步'), findsOneWidget); + expect(find.text('账号同步'), findsOneWidget); + expect(find.textContaining('账号同步状态'), findsOneWidget); + expect( + find.byKey(const ValueKey('settings-account-sync-button')), + findsOneWidget, + ); + expect( + find.byKey(const ValueKey('settings-account-manual-reset-button')), + findsNothing, + ); + expect( + find.byKey(const ValueKey('settings-account-logout-button')), + findsOneWidget, + ); - expect(find.byKey(const ValueKey('settings-account-summary-service-url')), findsNothing); - expect(find.byKey(const ValueKey('settings-account-summary-account-identifier')), findsNothing); - expect(find.byKey(const ValueKey('settings-account-summary-remote-summary')), findsNothing); + expect( + find.byKey(const ValueKey('settings-account-summary-service-url')), + findsNothing, + ); + expect( + find.byKey( + const ValueKey('settings-account-summary-account-identifier'), + ), + findsNothing, + ); + expect( + find.byKey(const ValueKey('settings-account-summary-remote-summary')), + findsNothing, + ); - await tester.tap( - find.byKey(const ValueKey('settings-account-sync-button')), - ); - await tester.pump(); - await tester.tap( - find.byKey(const ValueKey('settings-account-logout-button')), - ); - await tester.pump(); + await tester.tap( + find.byKey(const ValueKey('settings-account-sync-button')), + ); + await tester.pump(); + await tester.tap( + find.byKey(const ValueKey('settings-account-logout-button')), + ); + await tester.pump(); - expect(syncCount, 1); - expect(logoutCount, 1); - }); + expect(syncCount, 1); + expect(logoutCount, 1); + }, + ); testWidgets('keeps details collapsed by default and expands diagnostics', ( tester, @@ -215,8 +233,16 @@ void main() { ), ); - expect(find.byKey(const ValueKey('settings-account-summary-service-url')), findsNothing); - expect(find.byKey(const ValueKey('settings-account-summary-account-identifier')), findsNothing); + expect( + find.byKey(const ValueKey('settings-account-summary-service-url')), + findsNothing, + ); + expect( + find.byKey( + const ValueKey('settings-account-summary-account-identifier'), + ), + findsNothing, + ); expect( find.byKey(const ValueKey('settings-account-summary-expansion')), findsOneWidget, @@ -225,80 +251,120 @@ void main() { await tester.tap(find.byType(ExpansionTile)); await tester.pumpAndSettle(); - expect(find.byKey(const ValueKey('settings-account-summary-service-url')), findsOneWidget); - expect(find.byKey(const ValueKey('settings-account-summary-account-identifier')), findsOneWidget); - expect(find.byKey(const ValueKey('settings-account-summary-remote-summary')), findsOneWidget); - expect(find.byKey(const ValueKey('settings-account-summary-last-sync')), findsOneWidget); - expect(find.byKey(const ValueKey('settings-account-summary-mfa-status')), findsOneWidget); - expect(find.byKey(const ValueKey('settings-account-summary-sync-scope')), findsOneWidget); - expect(find.byKey(const ValueKey('settings-account-summary-token-configured')), findsOneWidget); - }); - - testWidgets('shows manual bridge save status and reset action when not account sync', ( - tester, - ) async { - final controllers = _TestControllers(); - addTearDown(controllers.dispose); - - var saveCount = 0; - var logoutCount = 0; - - await tester.pumpWidget( - _buildTestApp( - child: SettingsAccountPanel( - settings: SettingsSnapshot.defaults().copyWith( - acpBridgeServerModeConfig: AcpBridgeServerModeConfig.defaults().copyWith( - selfHosted: AcpBridgeServerModeConfig.defaults().selfHosted.copyWith( - serverUrl: 'https://xworkmate-bridge.svc.plus', - passwordRef: 'bridge-token-ref', - ), - ), - ), - accountSession: const AccountSessionSummary( - userId: 'u-1', - email: 'review@svc.plus', - name: 'Review User', - role: 'operator', - mfaEnabled: false, - ), - accountState: null, - accountBusy: false, - accountSignedIn: true, - accountMfaRequired: false, - accountBaseUrlController: controllers.baseUrl, - accountIdentifierController: controllers.identifier, - accountPasswordController: controllers.password, - accountMfaCodeController: controllers.mfaCode, - bridgeUrlController: controllers.bridgeUrl, - bridgeTokenController: controllers.bridgeToken, - onSaveAccountProfile: ({required bool isManualBridge}) async { - saveCount += 1; - }, - onLogin: () async {}, - onVerifyMfa: () async {}, - onCancelMfa: () async {}, - onSync: () async {}, - onLogout: () async { - logoutCount += 1; - }, - ), - ), + expect( + find.byKey(const ValueKey('settings-account-summary-service-url')), + findsOneWidget, + ); + expect( + find.byKey( + const ValueKey('settings-account-summary-account-identifier'), + ), + findsOneWidget, + ); + expect( + find.byKey(const ValueKey('settings-account-summary-remote-summary')), + findsOneWidget, + ); + expect( + find.byKey(const ValueKey('settings-account-summary-last-sync')), + findsOneWidget, + ); + expect( + find.byKey(const ValueKey('settings-account-summary-mfa-status')), + findsOneWidget, + ); + expect( + find.byKey(const ValueKey('settings-account-summary-sync-scope')), + findsOneWidget, + ); + expect( + find.byKey(const ValueKey('settings-account-summary-token-configured')), + findsOneWidget, ); - - expect(find.text('手动 Bridge'), findsOneWidget); - expect(find.textContaining('保存状态'), findsOneWidget); - expect(find.byKey(const ValueKey('settings-account-manual-reset-button')), findsOneWidget); - expect(find.byKey(const ValueKey('settings-account-sync-button')), findsNothing); - - await tester.tap(find.byKey(const ValueKey('settings-account-manual-reset-button'))); - await tester.pump(); - await tester.tap(find.byKey(const ValueKey('settings-account-logout-button'))); - await tester.pump(); - - expect(saveCount, 1); - expect(logoutCount, 1); }); + testWidgets( + 'shows manual bridge save status and reset action when not account sync', + (tester) async { + final controllers = _TestControllers(); + addTearDown(controllers.dispose); + + var saveCount = 0; + var logoutCount = 0; + var receivedManualBridge = false; + + await tester.pumpWidget( + _buildTestApp( + child: SettingsAccountPanel( + settings: SettingsSnapshot.defaults().copyWith( + acpBridgeServerModeConfig: AcpBridgeServerModeConfig.defaults() + .copyWith( + selfHosted: AcpBridgeServerModeConfig.defaults() + .selfHosted + .copyWith( + serverUrl: 'https://xworkmate-bridge.svc.plus', + passwordRef: 'bridge-token-ref', + ), + ), + ), + accountSession: const AccountSessionSummary( + userId: 'u-1', + email: 'review@svc.plus', + name: 'Review User', + role: 'operator', + mfaEnabled: false, + ), + accountState: null, + accountBusy: false, + accountSignedIn: true, + accountMfaRequired: false, + accountBaseUrlController: controllers.baseUrl, + accountIdentifierController: controllers.identifier, + accountPasswordController: controllers.password, + accountMfaCodeController: controllers.mfaCode, + bridgeUrlController: controllers.bridgeUrl, + bridgeTokenController: controllers.bridgeToken, + onSaveAccountProfile: ({required bool isManualBridge}) async { + saveCount += 1; + receivedManualBridge = isManualBridge; + }, + onLogin: () async {}, + onVerifyMfa: () async {}, + onCancelMfa: () async {}, + onSync: () async {}, + onLogout: () async { + logoutCount += 1; + }, + ), + ), + ); + + expect(find.text('手动 Bridge'), findsOneWidget); + expect(find.textContaining('保存状态'), findsOneWidget); + expect( + find.byKey(const ValueKey('settings-account-manual-reset-button')), + findsOneWidget, + ); + expect( + find.byKey(const ValueKey('settings-account-sync-button')), + findsNothing, + ); + + await tester.tap( + find.byKey(const ValueKey('settings-account-manual-reset-button')), + ); + await tester.pump(); + await tester.tap( + find.byKey(const ValueKey('settings-account-logout-button')), + ); + await tester.pump(); + + expect(saveCount, 1); + expect(receivedManualBridge, isTrue); + expect(logoutCount, 1); + }, + ); + testWidgets('shows live syncing feedback while resync is running', ( tester, ) async { diff --git a/test/runtime/bridge_runtime_cleanup_test.dart b/test/runtime/bridge_runtime_cleanup_test.dart index a8fbf9de..32211e17 100644 --- a/test/runtime/bridge_runtime_cleanup_test.dart +++ b/test/runtime/bridge_runtime_cleanup_test.dart @@ -134,7 +134,25 @@ void main() { test( 'ignores legacy INTERNAL_SERVICE_TOKEN for managed bridge auth resolution', () async { + final storeRoot = await Directory.systemTemp.createTemp( + 'xworkmate-bridge-auth-resolver-legacy-', + ); + addTearDown(() async { + if (await storeRoot.exists()) { + await storeRoot.delete(recursive: true); + } + }); + + final store = SecureConfigStore( + secretRootPathResolver: () async => '${storeRoot.path}/secrets', + appDataRootPathResolver: () async => '${storeRoot.path}/app-data', + supportRootPathResolver: () async => '${storeRoot.path}/support', + enableSecureStorage: false, + ); + await store.initialize(); + final controller = AppController( + store: store, environmentOverride: const { 'INTERNAL_SERVICE_TOKEN': 'legacy-bridge-token', },