b839c77712
账户页重排为:账户信息 → 购买套餐/我的订单/兑换码(三行合一) → 邀请好友(新增, gift 图标+t.inviteEntry/inviteEntrySub,接 NavView.invite) → 设备(常显)/ 设置/联系(仅 mobile,桌面侧栏已有同入口,formFactor 门控避免重复) → 退出。 删语言/主题/协议卡及仅供其用的 _LangSwitch/_PangolinSwitch(l10n getter 保留, Settings 页仍用)。_NavRow 加可选 subtitle 用于邀请卡副标题。 新增 InviteScreen(client/lib/screens/invite_page.dart)占位屏:邀请码/链接卡 (可复制,值写死 PANGOLIN-DEMO)+ 奖励规则三条 + 我的奖励占位卡,顶部 TODO(spec-2) 标注接口点(邀请码/链接由后端签发,奖励进度来自 /v1/invite)。 顺带修复 desktop_shell.dart 非穷尽 switch 编译错误(NavView 加 invite 后未接线, 整个 client 目前无法编译);notifications 分支占位回落账户页,留给 Task 6 接线。 test/widget/account_ia_test.dart 新增桌面态 IA 结构断言(邀请入口存在/语言不在/ 兑换在);account_desktop_nav_test.dart 同步去掉桌面态设置/联系两个失效断言 (改走桌面侧栏,非账户卡),加邀请入口断言。desktop/tablet 账户页 golden 重录。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
106 lines
4.2 KiB
Dart
106 lines
4.2 KiB
Dart
// 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<void> saveTokens({required String access, required String refresh}) async {}
|
||
@override
|
||
Future<String?> loadAccessToken() async => null;
|
||
@override
|
||
Future<String?> loadRefreshToken() async => null;
|
||
@override
|
||
Future<void> clear() async {}
|
||
@override
|
||
Future<void> markOnboarded() async {}
|
||
@override
|
||
Future<bool> isOnboarded() async => true;
|
||
@override
|
||
Future<void> saveLastEmail(String email) async {}
|
||
@override
|
||
Future<String?> loadLastEmail() async => null;
|
||
}
|
||
|
||
/// 在桌面态渲染 DesktopShell(起始 account 视图),点账户卡里 [label] 那一行,
|
||
/// 返回点击后的 navViewProvider 值。
|
||
Future<NavView> _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);
|
||
});
|
||
}
|