feat(client): 购买模型/仓库切 pay v2 契约(render_type 多态 + 分金额 + 订单列表)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:http_mock_adapter/http_mock_adapter.dart';
|
||||
import 'package:jiu_client/core/api/api_client.dart';
|
||||
import 'package:jiu_client/core/exceptions.dart';
|
||||
import 'package:jiu_client/repositories/license_repository.dart';
|
||||
|
||||
const _baseUrl = 'http://localhost:8080/api/v1';
|
||||
|
||||
class _TestApiClient extends ApiClient {
|
||||
final Dio _testDio;
|
||||
_TestApiClient(this._testDio) : super(token: 'test-token');
|
||||
|
||||
@override
|
||||
Future<Response> get(String path, {Map<String, dynamic>? params}) =>
|
||||
_testDio.get(path, queryParameters: params);
|
||||
|
||||
@override
|
||||
Future<Response> post(String path, {dynamic data}) =>
|
||||
_testDio.post(path, data: data);
|
||||
}
|
||||
|
||||
void main() {
|
||||
late Dio dio;
|
||||
late DioAdapter adapter;
|
||||
late LicenseRepository repo;
|
||||
|
||||
setUp(() {
|
||||
dio = Dio(BaseOptions(baseUrl: _baseUrl));
|
||||
adapter = DioAdapter(dio: dio, matcher: const FullHttpRequestMatcher());
|
||||
repo = LicenseRepository(_TestApiClient(dio));
|
||||
});
|
||||
|
||||
group('LicenseRepository.cancelPurchase()', () {
|
||||
test('200 canceled=true → 返回 true', () async {
|
||||
adapter.onPost(
|
||||
'/license/purchase/pay-abc123/cancel',
|
||||
(server) => server.reply(200, {
|
||||
'data': {'canceled': true}
|
||||
}),
|
||||
);
|
||||
|
||||
final ok = await repo.cancelPurchase('pay-abc123');
|
||||
expect(ok, isTrue);
|
||||
});
|
||||
|
||||
test('404 订单不存在 → 返回 false(不抛异常)', () async {
|
||||
adapter.onPost(
|
||||
'/license/purchase/pay-missing/cancel',
|
||||
(server) => server.reply(404, {'error': '订单不存在'}),
|
||||
);
|
||||
|
||||
final ok = await repo.cancelPurchase('pay-missing');
|
||||
expect(ok, isFalse);
|
||||
});
|
||||
|
||||
test('409 已支付不可取消 → 返回 false(不抛异常)', () async {
|
||||
adapter.onPost(
|
||||
'/license/purchase/pay-paid1/cancel',
|
||||
(server) => server.reply(409, {'error': '订单已支付,无法取消'}),
|
||||
);
|
||||
|
||||
final ok = await repo.cancelPurchase('pay-paid1');
|
||||
expect(ok, isFalse);
|
||||
});
|
||||
|
||||
test('其它错误(如 5xx)→ 抛 AppException', () async {
|
||||
adapter.onPost(
|
||||
'/license/purchase/pay-err/cancel',
|
||||
(server) => server.reply(502, {'error': '取消失败,请稍后重试'}),
|
||||
);
|
||||
|
||||
await expectLater(
|
||||
repo.cancelPurchase('pay-err'),
|
||||
throwsA(isA<AppException>()),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('LicenseRepository.listPurchases()', () {
|
||||
test('返回订单列表 + 汇总', () async {
|
||||
adapter.onGet(
|
||||
'/license/purchases',
|
||||
(server) => server.reply(200, {
|
||||
'data': {
|
||||
'items': [
|
||||
{
|
||||
'out_trade_no': 'pay-1',
|
||||
'product_biz_code': 'annual',
|
||||
'amount_minor': 299900,
|
||||
'currency': 'CNY',
|
||||
'amount': '2999.00',
|
||||
'status': 'paid',
|
||||
'pay_url': '',
|
||||
'user_name': '张三',
|
||||
'created_at': '2026-07-01T10:00:00Z',
|
||||
'paid_at': '2026-07-01T10:05:00Z',
|
||||
},
|
||||
],
|
||||
'total': 1,
|
||||
'summary': {
|
||||
'paid_total_minor': 299900,
|
||||
'paid_count': 1,
|
||||
'pending_count': 0,
|
||||
'total_count': 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
queryParameters: {'page': 1, 'page_size': 20},
|
||||
);
|
||||
|
||||
final result = await repo.listPurchases();
|
||||
expect(result.total, 1);
|
||||
expect(result.items.single.outTradeNo, 'pay-1');
|
||||
expect(result.summary.paidCount, 1);
|
||||
});
|
||||
|
||||
test('status 筛选透传查询参数', () async {
|
||||
adapter.onGet(
|
||||
'/license/purchases',
|
||||
(server) => server.reply(200, {
|
||||
'data': {'items': [], 'total': 0},
|
||||
}),
|
||||
queryParameters: {'page': 1, 'page_size': 20, 'status': 'pending'},
|
||||
);
|
||||
|
||||
final result = await repo.listPurchases(status: 'pending');
|
||||
expect(result.items, isEmpty);
|
||||
});
|
||||
|
||||
test('失败 → 抛 AppException', () async {
|
||||
adapter.onGet(
|
||||
'/license/purchases',
|
||||
(server) => server.reply(500, {'error': '获取订单列表失败'}),
|
||||
queryParameters: {'page': 1, 'page_size': 20},
|
||||
);
|
||||
|
||||
await expectLater(
|
||||
repo.listPurchases(),
|
||||
throwsA(isA<AppException>()),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user