import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:jiu_client/core/auth/auth_state.dart'; import 'package:jiu_client/core/theme/themes.dart'; import 'package:jiu_client/models/shop.dart'; import 'package:jiu_client/providers/shop_provider.dart'; import 'package:jiu_client/providers/license_provider.dart'; import 'package:jiu_client/providers/update_provider.dart'; import 'package:jiu_client/providers/connectivity_provider.dart'; import 'package:jiu_client/providers/session_heartbeat.dart'; import 'package:jiu_client/screens/shell/app_shell.dart'; import 'package:jiu_client/widgets/app_status_bar.dart'; import '../support/golden_harness.dart'; /// design-distill 阶段4:app 外壳(顶栏两级品牌 + 主题器 + 通知铃 + 分组侧栏 + 状态栏) /// golden × 三主题。照原型 shell.js/statusbar.js 重建后的回归基准 + 与原型保真比对基准。 /// 与原型对齐:门店=鼎晟酒行/DSJH-001、用户=王经理(管理员)、版本 v1.0.72、库存页激活。 /// 更新基准:flutter test --update-goldens test/golden/app_shell_golden_test.dart class _FakeAuth extends AuthNotifier { _FakeAuth() { state = const AuthState( user: AuthUser( accessToken: 't', refreshToken: 'r', id: 1, username: 'wang', realName: '王经理', shopNo: 'DSJH-001', shopId: 1, role: 'admin'), ); } } class _FakeUpdate extends UpdateNotifier { @override Future build() async => null; } class _FakeLicense extends LicenseNotifier { @override Future build() async => null; } const _shop = ShopInfo( id: 1, code: 'DSJH-001', name: '鼎晟酒行', address: '浙江省杭州市', phone: '0571-88886666', managerName: '王经理'); List _overrides() => [ authStateProvider.overrideWith((ref) => _FakeAuth()), shopInfoProvider.overrideWith((ref) => _shop), licenseProvider.overrideWith(() => _FakeLicense()), updateProvider.overrideWith(() => _FakeUpdate()), // 跳过联网首检 / 不启动心跳,避免后台 Timer 泄漏 connectivityProvider .overrideWith((ref) => ConnectivityNotifier(skipInit: true)), sessionHeartbeatProvider.overrideWith((ref) => SessionHeartbeat(ref)), appVersionProvider.overrideWith((ref) => 'v1.0.72'), isReadonlyProvider.overrideWithValue(false), ]; // 外壳 nav 引用 9 个分支序号(入/出库·库存·财务·往来·基础数据·设备·设置·关于)。 // 全部空白内容,仅供外壳渲染;初始定位库存(index 2)以匹配原型激活态。 StatefulShellBranch _branch(String path) => StatefulShellBranch(routes: [ GoRoute(path: path, builder: (_, __) => const SizedBox.expand()), ]); GoRouter _router() => GoRouter( initialLocation: '/inventory', routes: [ StatefulShellRoute.indexedStack( builder: (ctx, state, shell) => AppShell(navigationShell: shell), branches: [ _branch('/stock-in'), _branch('/stock-out'), _branch('/inventory'), _branch('/finance'), _branch('/partners'), _branch('/products'), _branch('/devices'), _branch('/settings'), _branch('/about'), ], ), ], ); void main() { TestWidgetsFlutterBinding.ensureInitialized(); SharedPreferences.setMockInitialValues({}); // 冻结状态栏时钟,确定化 golden(关走字,避免像素抖动 / pending timer)。 AppStatusBar.clock = () => DateTime(2026, 7, 13, 9, 30, 15); AppStatusBar.ticking = false; for (final theme in const ['a', 'b', 'c']) { testWidgets('app shell · theme $theme', (tester) async { await ensureGoldenFonts(); tester.view.physicalSize = const Size(2560, 1800); // 1280×900 @2x tester.view.devicePixelRatio = 2.0; addTearDown(tester.view.resetPhysicalSize); addTearDown(tester.view.resetDevicePixelRatio); await tester.pumpWidget(ProviderScope( overrides: _overrides(), child: MaterialApp.router( debugShowCheckedModeBanner: false, theme: withGoldenFont(buildTheme(theme)), routerConfig: _router(), ), )); await tester.pumpAndSettle(); await expectLater( find.byType(MaterialApp), matchesGoldenFile('goldens/app_shell_$theme.png'), ); }); } }