Files
jiu/client/test/golden/app_shell_golden_test.dart
T
wangjia 1b8bf596c5 test(client): app 外壳(顶栏/侧栏/状态栏)整壳 golden ×三主题
外壳 chrome 是最显眼的主题面,但各屏 golden 都不含它。本 golden 用
MaterialApp.router + StatefulNavigationShell 渲染整壳(覆盖 auth/shop/license/
update/connectivity/heartbeat,跳过联网首检与心跳避免 Timer 泄漏),锁住
顶栏+侧栏+状态栏随 A/B/C 换色入回归闸。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TSKEiHsvauyxYUW2itzUXX
2026-06-25 14:38:55 +08:00

102 lines
3.6 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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';
/// design-distill 阶段4app 外壳(顶栏 + 侧栏 + 内容区)golden × 三主题。
/// 锁住导航 chrome 随主题换色——这是最显眼的主题面,之前各屏 golden 都不含外壳。
/// 需 MaterialApp.router(外壳依赖 StatefulNavigationShell),故为自定义 golden。
/// 更新基准: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: 'DBZB-001', shopId: 1, role: 'admin'),
);
}
}
class _FakeUpdate extends UpdateNotifier {
@override
Future<AppUpdateInfo?> build() async => null;
}
class _FakeLicense extends LicenseNotifier {
@override
Future<LicenseInfo?> build() async => null;
}
const _shop = ShopInfo(
id: 1, code: 'DBZB-001', name: '鼎昌酒行',
address: '浙江省杭州市', phone: '0571-88886666', managerName: '王经理');
List<Override> _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),
];
GoRouter _router() => GoRouter(
initialLocation: '/inventory',
routes: [
StatefulShellRoute.indexedStack(
builder: (ctx, state, shell) => AppShell(navigationShell: shell),
branches: [
StatefulShellBranch(routes: [
GoRoute(
path: '/inventory',
builder: (_, __) => const SizedBox.expand()),
]),
],
),
],
);
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
SharedPreferences.setMockInitialValues({});
for (final theme in const ['a', 'b', 'c']) {
testWidgets('app shell · theme $theme', (tester) async {
tester.view.physicalSize = const Size(2560, 1600);
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: buildTheme(theme),
routerConfig: _router(),
),
));
await tester.pumpAndSettle();
await expectLater(
find.byType(MaterialApp),
matchesGoldenFile('goldens/app_shell_$theme.png'),
);
});
}
}