import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:miaoji_zhang/features/ai_mode/pages/ai_mode_page.dart'; import 'package:miaoji_zhang/features/auth/pages/login_page.dart'; import 'package:miaoji_zhang/features/settings/me_page.dart'; import 'package:miaoji_zhang/shared/api/business_api.dart'; import 'package:miaoji_zhang/shared/theme/app_theme.dart'; import 'package:miaoji_zhang/shared/widgets/ai_access_gate.dart'; import 'package:miaoji_zhang/shared/widgets/app_controls.dart'; import 'package:miaoji_zhang/shared/widgets/async_error_view.dart'; import 'package:miaoji_zhang/shared/widgets/brand_logo.dart'; void main() { testWidgets('错误状态无需真实 API 即可重试', (tester) async { var retries = 0; await tester.pumpWidget( MaterialApp( theme: AppTheme.light, home: Scaffold( body: AsyncErrorView( message: '网络开小差了', onRetry: () async => retries++, ), ), ), ); expect(find.text('网络开小差了'), findsOneWidget); await tester.tap(find.text('重试')); await tester.pump(); expect(retries, 1); }); testWidgets('全 AI 模式预算条展示未设置状态并可进入设置', (tester) async { var taps = 0; final data = BudgetsData.fromJson({'total': null, 'categories': []}); await tester.pumpWidget( MaterialApp( theme: AppTheme.light, home: Scaffold( body: AiBudgetStrip(data: data, onTap: () => taps++), ), ), ); expect(find.text('本月还没设置预算'), findsOneWidget); expect(find.text('去设置'), findsOneWidget); await tester.tap(find.byType(AiBudgetStrip)); expect(taps, 1); }); testWidgets('全 AI 模式预算条明确展示超支金额', (tester) async { final data = BudgetsData.fromJson({ 'total': { 'categoryId': null, 'categoryName': null, 'categoryIcon': null, 'amount': 1000, 'spent': 1250, 'isRecurring': false, }, 'categories': [], }); await tester.pumpWidget( MaterialApp( theme: AppTheme.light, home: Scaffold( body: AiBudgetStrip(data: data, onTap: () {}), ), ), ); expect(find.text('已超 ¥250'), findsOneWidget); expect(find.text('已用 ¥1250'), findsOneWidget); expect(find.text('总额 ¥1000'), findsOneWidget); }); testWidgets('登录与启动页共用的新品牌图标可加载', (tester) async { await tester.pumpWidget( MaterialApp( theme: AppTheme.light, home: const Scaffold(body: Center(child: BrandLogo(size: 64))), ), ); await tester.pumpAndSettle(); expect(find.byType(BrandLogo), findsOneWidget); expect(tester.takeException(), isNull); }); testWidgets('登录页合规入口只展示协议和隐私政策', (tester) async { await tester.pumpWidget( MaterialApp( theme: AppTheme.light, home: const Scaffold(body: LoginLegalLinks()), ), ); expect(find.text('用户协议'), findsOneWidget); expect(find.text('隐私政策'), findsOneWidget); expect(find.text('权限用途'), findsNothing); expect(find.text('第三方 SDK'), findsNothing); }); testWidgets('游客本地状态是信息卡而不是禁用开关', (tester) async { await tester.pumpWidget( MaterialApp( theme: AppTheme.light, home: const Scaffold(body: GuestLocalStatusCard()), ), ); expect(find.text('本机保存中'), findsOneWidget); expect(find.text('游客模式'), findsOneWidget); expect(find.byType(JzSwitchTile), findsNothing); }); testWidgets('游客 AI 页面只展示登录引导', (tester) async { var actions = 0; await tester.pumpWidget( MaterialApp( theme: AppTheme.light, home: Scaffold( body: AiAccessGate( state: AiAccessState.guest, onAction: () async => actions++, ), ), ), ); await tester.pumpAndSettle(); expect(find.text('登录后使用 AI 助手'), findsOneWidget); expect(find.text('登录后使用'), findsOneWidget); await tester.tap(find.text('登录后使用')); await tester.pump(); expect(actions, 1); }); }