diff --git a/lib/pages/account/account_devices_logic.dart b/lib/pages/account/account_devices_logic.dart index cbc1241..f4776de 100644 --- a/lib/pages/account/account_devices_logic.dart +++ b/lib/pages/account/account_devices_logic.dart @@ -24,9 +24,7 @@ class AccountDevicesLogic extends ChangeNotifier { try { devices = await _repository.devices(); } catch (failure) { - error = failure is ApiException - ? failure.message - : 'accountDevicesLoadFailed'; + error = failure is ApiException ? failure.message : 'networkError'; } finally { loading = false; _notify(); diff --git a/lib/pages/account/account_export_logic.dart b/lib/pages/account/account_export_logic.dart index 90546a0..45864ec 100644 --- a/lib/pages/account/account_export_logic.dart +++ b/lib/pages/account/account_export_logic.dart @@ -25,9 +25,7 @@ class AccountExportLogic extends ChangeNotifier { try { data = await _repository.export(); } catch (failure) { - error = failure is ApiException - ? failure.message - : 'accountExportLoadFailed'; + error = failure is ApiException ? failure.message : 'networkError'; } finally { loading = false; _notify(); diff --git a/lib/pages/account/account_profile_logic.dart b/lib/pages/account/account_profile_logic.dart index 84292cc..53c9018 100644 --- a/lib/pages/account/account_profile_logic.dart +++ b/lib/pages/account/account_profile_logic.dart @@ -30,7 +30,7 @@ class AccountProfileLogic extends ChangeNotifier { try { profile = await _repository.profile(); } catch (failure) { - error = _message(failure) ?? 'accountProfileLoadFailed'; + error = _message(failure); } finally { loading = false; _notify(); @@ -68,7 +68,7 @@ class AccountProfileLogic extends ChangeNotifier { await onProfileUpdated(next); return true; } catch (failure) { - error = _message(failure) ?? 'accountProfileSaveFailed'; + error = _message(failure); return false; } finally { saving = false; @@ -76,8 +76,8 @@ class AccountProfileLogic extends ChangeNotifier { } } - String? _message(Object failure) => - failure is ApiException ? failure.message : null; + String _message(Object failure) => + failure is ApiException ? failure.message : 'networkError'; void _notify() { if (!_disposed) notifyListeners(); diff --git a/test/account/account_pages_test.dart b/test/account/account_pages_test.dart index b023326..90cc7d0 100644 --- a/test/account/account_pages_test.dart +++ b/test/account/account_pages_test.dart @@ -101,6 +101,83 @@ void main() { expect(find.byKey(const Key('account-export-content')), findsOneWidget); }); + + testWidgets('should_show_localized_network_copy_when_profile_load_fails', ( + tester, + ) async { + final repository = FakeAccountRepository()..throwUnexpected = true; + final auth = await _signedInAuth(); + await _pumpPage( + tester, + AccountProfilePage(), + repository: repository, + auth: auth, + locale: const Locale('zh'), + ); + final l10n = await AppLocalizations.delegate.load(const Locale('zh')); + + expect(find.text(l10n.networkError), findsOneWidget); + expect(find.text('accountProfileLoadFailed'), findsNothing); + }); + + testWidgets('should_show_localized_network_copy_when_profile_save_fails', ( + tester, + ) async { + final repository = FakeAccountRepository(); + final auth = await _signedInAuth(); + await _pumpPage( + tester, + AccountProfilePage(), + repository: repository, + auth: auth, + ); + repository.throwUnexpected = true; + await tester.enterText( + find.byKey(const Key('account-nickname')), + 'Nadia Baru', + ); + await tester.tap(find.byKey(const Key('account-profile-save'))); + await tester.pumpAndSettle(); + final l10n = await AppLocalizations.delegate.load(const Locale('en')); + + expect(find.text(l10n.networkError), findsOneWidget); + expect(find.text('accountProfileSaveFailed'), findsNothing); + }); + + testWidgets('should_show_localized_network_copy_when_devices_fail', ( + tester, + ) async { + final repository = FakeAccountRepository()..throwUnexpected = true; + final auth = await _signedInAuth(); + await _pumpPage( + tester, + AccountDevicesPage(), + repository: repository, + auth: auth, + locale: const Locale('id'), + ); + final l10n = await AppLocalizations.delegate.load(const Locale('id')); + + expect(find.text(l10n.networkError), findsOneWidget); + expect(find.text('accountDevicesLoadFailed'), findsNothing); + }); + + testWidgets('should_show_localized_network_copy_when_export_fails', ( + tester, + ) async { + final repository = FakeAccountRepository()..throwUnexpected = true; + final auth = await _signedInAuth(); + await _pumpPage( + tester, + AccountExportPage(), + repository: repository, + auth: auth, + ); + final l10n = await AppLocalizations.delegate.load(const Locale('en')); + + expect(find.text(l10n.networkError), findsOneWidget); + expect(find.text('accountExportLoadFailed'), findsNothing); + }); } Future _signedInAuth() async { @@ -124,6 +201,7 @@ Future _pumpPage( Widget page, { required FakeAccountRepository repository, required AuthController auth, + Locale locale = const Locale('en'), }) async { tester.view.physicalSize = const Size(390, 844); tester.view.devicePixelRatio = 1; @@ -136,7 +214,7 @@ Future _pumpPage( ChangeNotifierProvider.value(value: auth), ], child: MaterialApp( - locale: const Locale('en'), + locale: locale, supportedLocales: AppLocalizations.supportedLocales, localizationsDelegates: AppLocalizations.localizationsDelegates, home: Theme(data: ThemeData.dark(), child: page), diff --git a/test/support/fake_account_repository.dart b/test/support/fake_account_repository.dart index 039e0a3..2135a01 100644 --- a/test/support/fake_account_repository.dart +++ b/test/support/fake_account_repository.dart @@ -68,10 +68,12 @@ class FakeAccountRepository implements AccountRepository { bool failUpdate = false; bool failDeactivate = false; bool failCancel = false; + bool throwUnexpected = false; @override Future profile() async { profileCalls++; + if (throwUnexpected) throw StateError('offline'); if (failProfile) throw const ApiException(500, '资料加载失败'); return _profile; } @@ -79,6 +81,7 @@ class FakeAccountRepository implements AccountRepository { @override Future updateProfile(AccountProfileUpdate update) async { lastUpdate = update; + if (throwUnexpected) throw StateError('offline'); if (failUpdate) throw const ApiException(400, '昵称不可用'); _profile = AccountProfile( uid: _profile.uid, @@ -100,6 +103,7 @@ class FakeAccountRepository implements AccountRepository { @override Future> devices() async { deviceCalls++; + if (throwUnexpected) throw StateError('offline'); if (failDevices) throw const ApiException(500, '设备加载失败'); return [..._devices]; } @@ -107,6 +111,7 @@ class FakeAccountRepository implements AccountRepository { @override Future export() async { exportCalls++; + if (throwUnexpected) throw StateError('offline'); if (failExport) throw const ApiException(500, '导出失败'); return _export; }