fix(client): dispose 不再静默取消支付订单,redirect launchUrl 加失败兜底

- PaymentFlowController 新增 stopPolling():只停轮询 Timer,不发远程 cancel、
  不改 state;PaymentScreen.dispose() 改调它,不再复用 cancel()——离开支付页
  (切左导航 tab)不再等同于放弃订单,cancel() 只留给「取消订单」按钮的显式路径。
- redirect 分支 launchUrl 前加 canLaunchUrl 判定 + try-catch,失败时用
  showPangolinToast 给可见提示(新增 l10n openAlipayFailed,zh/en 均补)。
- purchase_page.dart::_choose 下单后严格判 phase == awaitingPayment 才跳转
  支付页,建单失败(failed)不再误跳。
- 回归测试:payment_pages_test.dart 补两条用例区分 dispose(不触发 cancel、
  state 不归 idle)与「取消订单」按钮(远程 cancel + state 归 idle);
  payment_flow_test.dart 补 stopPolling() 单元测试。
This commit is contained in:
wangjia
2026-07-11 00:06:03 +08:00
parent a5fff28134
commit 262773a9de
8 changed files with 104 additions and 16 deletions
+20
View File
@@ -64,6 +64,26 @@ void main() {
expect(c.read(paymentFlowProvider).phase, PaymentPhase.succeeded);
});
test('stopPolling() 只停 Timer,不远程 cancel、不重置 state', () async {
final api = _FakePaymentApi();
final c = _container(api);
final ctl = c.read(paymentFlowProvider.notifier);
await ctl.start(item, 'crypto');
expect(c.read(paymentFlowProvider).phase, PaymentPhase.awaitingPayment);
ctl.stopPolling();
expect(api.cancelCalls, 0);
expect(c.read(paymentFlowProvider).phase, PaymentPhase.awaitingPayment);
expect(c.read(paymentFlowProvider).order?.orderNo, 'pay1');
// Timer 已停:再等一拍轮询周期,statusCalls 不应继续增长(pollOnce 只由
// Timer 或测试显式调用驱动,这里断言的是"没有 Timer 在背后继续触发")。
final callsAfterStop = api.statusCalls;
await Future<void>.delayed(const Duration(milliseconds: 10));
expect(api.statusCalls, callsAfterStop);
});
test('switchMethod 遇 CURRENCY_MISMATCH → cancel 旧单 + 新 method 重新下单', () async {
final api = _FakePaymentApi();
final c = _container(api);