// account_desktop_nav_test.dart — 复现 Windows/桌面账户页子导航点击是否切 navView。 // // 用 debugDefaultTargetPlatformOverride=windows + 宽 surface 让 context.formFactor==desktop, // 渲染 DesktopShell 账户页,点每个 _NavRow,断言 navViewProvider 切到对应子视图。 import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pangolin_vpn/bridge/vpn_bridge_mock.dart'; import 'package:pangolin_vpn/bridge/vpn_bridge_provider.dart'; import 'package:pangolin_vpn/l10n/app_text.dart'; import 'package:pangolin_vpn/l10n/strings_zh.dart'; import 'package:pangolin_vpn/pangolin_theme.dart'; import 'package:pangolin_vpn/screens/account_page.dart'; import 'package:pangolin_vpn/services/token_store.dart'; import 'package:pangolin_vpn/shell/desktop_shell.dart'; import 'package:pangolin_vpn/shell/home_shell.dart'; import 'package:pangolin_vpn/state/app_providers.dart'; import 'package:pangolin_vpn/state/auth_provider.dart'; import 'package:pangolin_vpn/state/navigation_provider.dart'; import '../helpers/harness.dart'; final AppText t = StringsZh(); class _NullTokenStore implements TokenStore { const _NullTokenStore(); @override Future saveTokens({required String access, required String refresh}) async {} @override Future loadAccessToken() async => null; @override Future loadRefreshToken() async => null; @override Future clear() async {} @override Future markOnboarded() async {} @override Future isOnboarded() async => true; @override Future saveLastEmail(String email) async {} @override Future loadLastEmail() async => null; } /// 在桌面态渲染 DesktopShell(起始 account 视图),点账户卡里 [label] 那一行, /// 返回点击后的 navViewProvider 值。 Future _tapRow(WidgetTester tester, String label) async { debugDefaultTargetPlatformOverride = TargetPlatform.windows; tester.view.physicalSize = const Size(920, 1400); tester.view.devicePixelRatio = 1.0; addTearDown(tester.view.resetPhysicalSize); addTearDown(tester.view.resetDevicePixelRatio); try { await tester.pumpWidget(ProviderScope( overrides: [ tokenStoreProvider.overrideWithValue(const _NullTokenStore()), vpnBridgeProvider.overrideWithValue(VpnBridgeMock()), appTextProvider.overrideWithValue(t), navViewProvider.overrideWith((ref) => NavView.account), ], child: MaterialApp( debugShowCheckedModeBanner: false, theme: PangolinTheme.light, home: const HomeShell(), ), )); await tester.pumpAndSettle(); expect(find.byType(DesktopShell), findsOneWidget); expect(find.byType(AccountPage), findsOneWidget); // 侧栏与账户卡可能共享同一文案(设置/联系我们),故限定在 AccountPage 内。 final row = find.descendant(of: find.byType(AccountPage), matching: find.text(label)); expect(row, findsOneWidget, reason: '账户卡里应有且仅有一行「$label」'); final container = ProviderScope.containerOf(tester.element(find.byType(HomeShell))); expect(container.read(navViewProvider), NavView.account); await tester.tap(row); await tester.pump(); return container.read(navViewProvider); } finally { debugDefaultTargetPlatformOverride = null; } } void main() { setUpAll(disableGoogleFontsFetching); // 注:设置/联系已从桌面态账户卡移除(IA 重构后仅 mobile/tablet 在账户页下钻, // 桌面走侧栏 NavSidebar 的 t.settingsTitle/t.contactTitle 入口,非本文件覆盖范围)。 testWidgets('desktop account -> redeem', (tester) async { expect(await _tapRow(tester, t.redeemEntry), NavView.redeem); }); testWidgets('desktop account -> orders', (tester) async { expect(await _tapRow(tester, t.ordersTitle), NavView.orders); }); testWidgets('desktop account -> devices', (tester) async { expect(await _tapRow(tester, t.myDevices), NavView.devices); }); testWidgets('desktop account -> invite', (tester) async { expect(await _tapRow(tester, t.inviteEntry), NavView.invite); }); }