122 lines
3.8 KiB
Dart
122 lines
3.8 KiB
Dart
// 功能描述:充值先存后发和未确认订单保留;版本:1.0.0。
|
||
import 'package:flutter_test/flutter_test.dart';
|
||
import 'package:user_app/data/services/recharge_draft_store.dart';
|
||
import 'package:user_app/data/services/recharge_flow.dart';
|
||
import 'package:user_app/data/services/api_client.dart';
|
||
import 'package:user_app/domain/models/recharge.dart';
|
||
import '../support/a1_fixture.dart';
|
||
|
||
class _Store implements RechargeDraftStore {
|
||
PendingRecharge? value;
|
||
bool fail = false;
|
||
@override
|
||
Future<PendingRecharge?> read(String owner) async => value;
|
||
@override
|
||
Future<void> write(String owner, PendingRecharge draft) async {
|
||
if (fail) throw StateError('存储失败');
|
||
value = draft;
|
||
}
|
||
|
||
@override
|
||
Future<void> delete(String owner) async {
|
||
value = null;
|
||
}
|
||
}
|
||
|
||
class _Repo extends A1FixtureRepository {
|
||
_Repo(this.store);
|
||
final _Store store;
|
||
int calls = 0, status = 10;
|
||
int? queryError;
|
||
String owner = 'api#alice';
|
||
bool changeOwnerOnQuery = false;
|
||
@override
|
||
Future<String> rechargeDraftOwner() async => owner;
|
||
@override
|
||
Future<Map<String, Object?>> createRecharge({
|
||
required String request,
|
||
required int amount,
|
||
required String channel,
|
||
required String payType,
|
||
}) async {
|
||
expect(store.value?.request, request);
|
||
calls++;
|
||
throw StateError('响应丢失');
|
||
}
|
||
|
||
@override
|
||
Future<RechargeRecord> rechargeResult(String request) async {
|
||
if (changeOwnerOnQuery) owner = 'api#bob';
|
||
if (queryError != null) throw ApiException(queryError!, '查询失败');
|
||
return RechargeRecord(
|
||
identity: 'order',
|
||
number: request,
|
||
amount: 100,
|
||
status: status,
|
||
channel: 'alipay',
|
||
createdAt: DateTime(2026),
|
||
);
|
||
}
|
||
}
|
||
|
||
void main() {
|
||
test('明确不存在可原号重发,网络错误和账号切换不能发单', () async {
|
||
const draft = PendingRecharge(
|
||
request: 'request-1',
|
||
amount: 100,
|
||
channel: 'alipay',
|
||
payType: 'wap',
|
||
);
|
||
for (final code in [1112, 500]) {
|
||
final store = _Store()..value = draft;
|
||
final repo = _Repo(store)..queryError = code;
|
||
final flow = RechargeFlow(repo, store);
|
||
await expectLater(
|
||
flow.create(draft),
|
||
code == 1112
|
||
? throwsStateError
|
||
: throwsA(isA<ApiException>().having((e) => e.code, '错误码', 500)),
|
||
);
|
||
expect(repo.calls, code == 1112 ? 1 : 0);
|
||
expect(store.value?.request, draft.request);
|
||
}
|
||
final store = _Store()..value = draft;
|
||
final repo = _Repo(store)..changeOwnerOnQuery = true;
|
||
await expectLater(RechargeFlow(repo, store).create(draft), throwsStateError);
|
||
expect(repo.calls, 0);
|
||
expect(store.value, isNotNull);
|
||
});
|
||
test('存储失败不发单,响应丢失保留原请求,到账后才清除', () async {
|
||
final store = _Store()..fail = true;
|
||
final repo = _Repo(store);
|
||
final flow = RechargeFlow(repo, store);
|
||
const draft = PendingRecharge(
|
||
request: 'request-1',
|
||
amount: 100,
|
||
channel: 'alipay',
|
||
payType: 'wap',
|
||
);
|
||
await expectLater(flow.create(draft), throwsStateError);
|
||
expect(repo.calls, 0);
|
||
store.fail = false;
|
||
await expectLater(flow.create(draft), throwsStateError);
|
||
expect(repo.calls, 1);
|
||
expect(store.value?.request, 'request-1');
|
||
await expectLater(
|
||
flow.create(
|
||
const PendingRecharge(request: 'request-2', amount: 100, channel: 'alipay', payType: 'wap'),
|
||
),
|
||
throwsStateError,
|
||
);
|
||
expect(repo.calls, 1);
|
||
expect((await flow.recover())?.credited, isFalse);
|
||
expect(store.value, isNotNull);
|
||
repo.status = 23;
|
||
expect(await flow.create(draft), {'recharge_status': 23});
|
||
expect(repo.calls, 1);
|
||
expect(store.value, isNotNull);
|
||
expect((await flow.recover())?.credited, isTrue);
|
||
expect(store.value, isNull);
|
||
});
|
||
}
|