// Author: fruit.com.cn import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:fruitshorts/core/data/models/auth_session.dart'; import 'package:fruitshorts/core/data/repositories/account_repository.dart'; import 'package:fruitshorts/core/data/remote/api_client.dart'; import 'package:fruitshorts/core/data/remote/auth_api.dart'; import 'package:fruitshorts/core/data/services/auth_controller.dart'; import 'package:fruitshorts/core/data/services/auth_session_store.dart'; import 'package:fruitshorts/l10n/app_localizations.dart'; import 'package:fruitshorts/pages/account/account_deactivate_page.dart'; import 'package:fruitshorts/pages/account/account_devices_page.dart'; import 'package:fruitshorts/pages/account/account_export_page.dart'; import 'package:fruitshorts/pages/account/account_profile_page.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart'; import '../support/fake_account_repository.dart'; void main() { testWidgets('should_fill_profile_and_save_nickname', (tester) async { final repository = FakeAccountRepository(); final auth = await _signedInAuth(); await _pumpPage( tester, AccountProfilePage(), repository: repository, auth: auth, locale: const Locale('zh'), ); final nickname = find.byKey(const Key('account-nickname')); expect(find.byKey(const Key('account-birthday')), findsNothing); expect(find.text('保存'), findsOneWidget); expect(tester.widget(nickname).controller?.text, 'Nadia'); await tester.enterText(nickname, 'Nadia Baru'); await tester.tap(find.byKey(const Key('account-profile-save'))); await tester.pumpAndSettle(); expect(repository.lastUpdate?.nickname, 'Nadia Baru'); expect(repository.lastUpdate?.birthday, isNull); }); testWidgets('should_show_device_empty_state_when_list_is_empty', ( tester, ) async { final repository = FakeAccountRepository(); final auth = await _signedInAuth(); await _pumpPage( tester, AccountDevicesPage(), repository: repository, auth: auth, ); expect(find.byKey(const Key('account-devices-empty')), findsOneWidget); }); testWidgets('should_confirm_before_deactivation_and_show_schedule', ( tester, ) async { final repository = FakeAccountRepository(); final auth = await _signedInAuth(); await _pumpPage( tester, AccountDeactivatePage(), repository: repository, auth: auth, ); final l10n = await AppLocalizations.delegate.load(const Locale('en')); expect(find.text(l10n.accountDeactivateReason), findsOneWidget); await tester.enterText( find.byKey(const Key('account-deactivate-reason')), '不再使用', ); await tester.tap(find.byKey(const Key('account-deactivate-submit'))); await tester.pumpAndSettle(); expect(find.byKey(const Key('account-deactivate-confirm')), findsOneWidget); await tester.tap(find.byKey(const Key('account-deactivate-confirm'))); await tester.pumpAndSettle(); expect(repository.lastDeactivateReason, '不再使用'); expect( find.byKey(const Key('account-deactivate-scheduled')), findsOneWidget, ); expect(auth.isSignedIn, isFalse); }); testWidgets('should_retry_export_after_failure', (tester) async { final repository = FakeAccountRepository()..failExport = true; final auth = await _signedInAuth(); await _pumpPage( tester, AccountExportPage(), repository: repository, auth: auth, ); expect(find.byKey(const Key('account-export-error')), findsOneWidget); repository.failExport = false; await tester.tap(find.byKey(const Key('account-export-retry'))); await tester.pumpAndSettle(); 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 { SharedPreferencesAsyncPlatform.instance = InMemorySharedPreferencesAsync.empty(); await AuthSessionStore().save( const AuthSession( accessToken: 'access', refreshToken: 'refresh', user: AuthUser(uid: 'U-K19', nickname: 'Nadia'), ), ); final client = ApiClient(baseUrl: 'http://127.0.0.1:8081'); final auth = AuthController(AuthApi(client), AuthSessionStore()); await auth.load(); return auth; } Future _pumpPage( WidgetTester tester, 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; addTearDown(tester.view.resetPhysicalSize); addTearDown(tester.view.resetDevicePixelRatio); await tester.pumpWidget( MultiProvider( providers: [ Provider.value(value: repository), ChangeNotifierProvider.value(value: auth), ], child: MaterialApp( locale: locale, supportedLocales: AppLocalizations.supportedLocales, localizationsDelegates: AppLocalizations.localizationsDelegates, home: Theme(data: ThemeData.dark(), child: page), ), ), ); await tester.pumpAndSettle(); }