Files
pangolin/client/test/widget/orders_page_test.dart
T
wangjia 272eca04ce feat(client): pay v2 支付渠道 switch + 订单列表/详情端到端
购买/支付(Phase B):
- 新 SegSwitch 段控 widget(镜像 .segswitch 原子)
- 购买页重构:顶部支付渠道 switch(默认 USDT→加密货币 / 人民币→支付宝),套餐价随渠道分币种显示,删底部弹窗选方式;点购买直达支付页
- 支付页加订单信息卡(套餐/渠道/金额按币种)
- models:PayChannel + PayCatalogItem.priceUsdtMicro/priceLabel(ch)/perMonthLabel(ch)

订单(P0,全新):
- payment_api.listOrders() + orders_provider(列表 + 详情 family)
- OrdersScreen 列表→详情(状态 pill / 可复制订单号 / 继续支付·重新购买)
- 导航:NavView.orders + desktop_shell 分支 + account 入口

配套:
- l10n +19 getter(支付渠道 4 + 订单 15)×6 语言,l10n 闸绿
- 图标单源迁移 lucide_icons_flutter + pangolin_icons.dart(codegen)
- 联系渠道订正(Telegram/邮件 support@yanmeiai.com/官网) + 前端去广告&时长
- 测试:购买 switch 分币种 + 订单列表/空态/详情 + 假 API listOrders;golden 重录
- flutter analyze 0 error,flutter test 226 全绿

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-12 00:07:15 +08:00

86 lines
3.6 KiB
Dart

// orders_page_test.dart — 订单列表/详情页行为测试(不打网络,provider 注入)。
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pangolin_vpn/l10n/strings_zh.dart';
import 'package:pangolin_vpn/models/payment.dart';
import 'package:pangolin_vpn/screens/orders_page.dart';
import 'package:pangolin_vpn/state/orders_provider.dart';
import 'package:pangolin_vpn/widgets/status_pill.dart';
import '../helpers/harness.dart';
final t = StringsZh();
final _orders = <PayOrderSummary>[
PayOrderSummary(
orderNo: 'o-year', sku: 'pro_year', plan: 'pro', days: 366, method: 'crypto',
status: 'paid', amountMinor: 34990000, currency: 'USDT',
createdAt: DateTime.utc(2026, 7, 10), paidAt: DateTime.utc(2026, 7, 10)),
PayOrderSummary(
orderNo: 'o-month', sku: 'pro_month', plan: 'pro', days: 31, method: 'alipay',
status: 'created', amountMinor: 2999, currency: 'CNY',
createdAt: DateTime.utc(2026, 7, 11)),
PayOrderSummary(
orderNo: 'o-q', sku: 'pro_quarter', plan: 'pro', days: 92, method: 'nezha',
status: 'canceled', amountMinor: 6888, currency: 'CNY',
createdAt: DateTime.utc(2026, 7, 9)),
];
void main() {
setUpAll(disableGoogleFontsFetching);
testWidgets('订单列表:三单渲染 + 结算币种金额 + 状态 pill', (tester) async {
tester.view.physicalSize = const Size(800, 2400);
tester.view.devicePixelRatio = 1.0;
addTearDown(tester.view.reset);
await tester.pumpWidget(wrapThemed(
OrdersScreen(t: t, embedded: true),
overrides: [ordersProvider.overrideWith((ref) async => _orders)],
));
await tester.pumpAndSettle();
// 套餐名(逐档)
expect(find.text(t.proYearly), findsOneWidget);
expect(find.text(t.proMonthly), findsOneWidget);
expect(find.text(t.proQuarterly), findsOneWidget);
// 金额按结算币种(USDT $ / CNY ¥),在「金额 · 日期」子行里
expect(find.textContaining(r'$34.99'), findsOneWidget);
expect(find.textContaining('¥29.99'), findsOneWidget);
// 状态 pill(created→等待付款 / paid→已开通 / canceled→已取消)
expect(find.byType(StatusPill), findsNWidgets(3));
expect(find.text(t.awaitingPayment), findsOneWidget);
expect(find.text(t.orderStatusPaid), findsOneWidget);
expect(find.text(t.orderStatusCanceled), findsOneWidget);
});
testWidgets('订单空态', (tester) async {
await tester.pumpWidget(wrapThemed(
OrdersScreen(t: t, embedded: true),
overrides: [ordersProvider.overrideWith((ref) async => const <PayOrderSummary>[])],
));
await tester.pumpAndSettle();
expect(find.text(t.ordersEmpty), findsOneWidget);
});
testWidgets('点 created 单进详情:显订单号 + 继续支付', (tester) async {
tester.view.physicalSize = const Size(800, 2400);
tester.view.devicePixelRatio = 1.0;
addTearDown(tester.view.reset);
await tester.pumpWidget(wrapThemed(
OrdersScreen(t: t, embedded: true),
overrides: [
ordersProvider.overrideWith((ref) async => _orders),
orderDetailProvider('o-month').overrideWith((ref) async => PayOrderStatus(
orderNo: 'o-month', payStatus: 'pending', activated: false, summary: _orders[1])),
],
));
await tester.pumpAndSettle();
// 点 created 那单(月付)进详情
await tester.tap(find.text(t.proMonthly));
await tester.pumpAndSettle();
// 详情字段行 + created 态动作「继续支付」
expect(find.text(t.orderNoLabel), findsOneWidget);
expect(find.text(t.orderContinuePay), findsWidgets);
});
}