import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; import 'package:http/testing.dart'; import 'package:pangolin_vpn/services/api_client.dart'; import 'package:pangolin_vpn/services/auth_api.dart'; import 'package:pangolin_vpn/services/payment_api.dart'; ApiClient _client(MockClient mock) => ApiClient( baseUrl: 'http://x', getToken: () => 'tok1', refresh: () async => false, client: mock, ); void main() { test('catalog 解析三档', () async { final api = PaymentApi(_client(MockClient((req) async { expect(req.url.path, '/v1/pay/catalog'); return http.Response( '{"items":[{"sku":"pro_month","plan":"pro","days":31,"price_minor":2999,"currency":"CNY"},' '{"sku":"pro_quarter","plan":"pro","days":92,"price_minor":6888,"currency":"CNY"},' '{"sku":"pro_year","plan":"pro","days":366,"price_minor":19999,"currency":"CNY"}]}', 200); }))); final items = await api.catalog(); expect(items.length, 3); expect(items.first.sku, 'pro_month'); expect(items.first.priceLabel(), '¥29.99'); }); test('createOrder 只传 sku+method+metadata,解析 session', () async { final api = PaymentApi(_client(MockClient((req) async { expect(req.url.path, '/v1/pay/orders'); expect(req.body.contains('"amount'), isFalse, reason: '客户端绝不传金额'); return http.Response( '{"order_no":"pay1","session":{"render_type":"crypto_address",' '"payload":{"address":"Txx","amount":"4.201234","amount_minor":4201234,' '"currency":"USDT","network":"TRC20"},"expires_at":"2026-07-10T12:00:00Z"}}', 200); }))); final order = await api.createOrder(sku: 'pro_month', method: 'crypto'); expect(order.orderNo, 'pay1'); expect(order.session.renderType, 'crypto_address'); expect(order.session.payload['address'], 'Txx'); expect(order.session.expiresAt, isNotNull); }); test('orderStatus 解析 activated/expires_at', () async { final api = PaymentApi(_client(MockClient((req) async => http.Response( '{"order_no":"pay1","pay_status":"succeeded","activated":true,' '"expires_at":"2026-08-10T12:00:00Z"}', 200)))); final st = await api.orderStatus('pay1'); expect(st.activated, isTrue); expect(st.payStatus, 'succeeded'); expect(st.expiresAt, isNotNull); }); test('retry 409 CURRENCY_MISMATCH 抛带 code 的异常', () async { final api = PaymentApi(_client(MockClient((req) async => http.Response( '{"code":"CURRENCY_MISMATCH","message_zh":"该支付方式结算币种与订单不符,请重新下单",' '"message_en":"mismatch"}', 409, headers: {'content-type': 'application/json; charset=utf-8'})))); try { await api.retry('pay1', method: 'alipay'); fail('应抛异常'); } on AuthApiException catch (e) { expect(e.statusCode, 409); expect(e.code, 'CURRENCY_MISMATCH'); } }); }