已完成用户APP首期功能开发

交付用户端首期页面、配套接口、后台资源及测试文档。用户APP构建、静态分析和三个管理后台构建通过;完整测试仍有2项失败,后端模型注释检查未通过,详见交付记录。
This commit is contained in:
czl231
2026-09-13 00:57:32 +08:00
parent a0a4bb1218
commit 3ef33b531d
793 changed files with 40959 additions and 1204 deletions

View File

@@ -0,0 +1,126 @@
// 功能描述:验证地址新增、失败重试、删除确认和默认地址刷新。
// 版本1.0.0。
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:user_app/data/services/api_client.dart';
import 'package:user_app/domain/models/shipping_address.dart';
import 'package:user_app/ui/core/app_theme.dart';
import 'package:user_app/ui/features/address/addresses_page.dart';
import '../support/a1_fixture.dart';
class AddressFixture extends A1FixtureRepository {
List<ShippingAddress> values = [];
final requests = <String>[];
int deletes = 0;
@override
Future<List<ShippingAddress>> shippingAddresses() async => values;
@override
Future<void> saveShippingAddress(ShippingAddress address, {required String requestNo}) async {
requests.add(requestNo);
if (this.fail) throw const ApiException(500, '保存失败,请重试');
values = [
ShippingAddress(
identity: 'saved',
address: address.address,
contactName: address.contactName,
contactPhone: address.contactPhone,
isDefault: address.isDefault,
),
];
}
@override
Future<void> setDefaultAddress(String identity) async {
if (this.fail) throw const ApiException(500, '设置失败');
final a = values.single;
values = [
ShippingAddress(
identity: a.identity,
address: a.address,
contactName: a.contactName,
contactPhone: a.contactPhone,
isDefault: true,
),
];
}
@override
Future<void> deleteAddress(String identity) async {
deletes++;
values = [];
}
}
void main() {
testWidgets('新增校验,失败保留输入与请求号,成功刷新列表', (tester) async {
final repo = AddressFixture()..fail = true;
await tester.pumpWidget(
MaterialApp(
theme: AppTheme.light(),
home: AddressesPage(repository: repo),
),
);
await tester.pumpAndSettle();
await tester.tap(find.text('新增收货地址'));
await tester.pumpAndSettle();
await tester.tap(find.text('保存地址'));
await tester.pumpAndSettle();
expect(repo.requests, isEmpty);
final fields = find.byType(TextFormField);
await tester.enterText(fields.at(0), '收货人');
await tester.enterText(fields.at(1), '13800000001');
await tester.enterText(fields.at(2), '广东省广州市测试路 1 号');
await tester.tap(find.text('保存地址'));
await tester.pumpAndSettle();
expect(find.text('保存失败,请重试'), findsOneWidget);
repo.fail = false;
await tester.tap(find.text('保存地址'));
await tester.pumpAndSettle();
expect(repo.requests.length, 2);
expect(repo.requests.first, repo.requests.last);
expect(find.text('收货人'), findsOneWidget);
expect(find.text('138****0001'), findsOneWidget);
expect(find.text('地址管理'), findsOneWidget);
});
testWidgets('默认切换失败不假更新,成功刷新,删除需要确认', (tester) async {
final repo = AddressFixture()
..values = [
const ShippingAddress(
identity: 'owned',
address: '测试地址',
contactName: '收货人',
contactPhone: '13800000001',
),
];
await tester.pumpWidget(
MaterialApp(
theme: AppTheme.light(),
home: AddressesPage(repository: repo),
),
);
await tester.pumpAndSettle();
repo.fail = true;
await tester.tap(find.text('设为默认'));
await tester.pumpAndSettle();
expect(repo.values.single.isDefault, false);
repo.fail = false;
await tester.tap(find.text('设为默认'));
await tester.pumpAndSettle();
expect(repo.values.single.isDefault, true);
await tester.tap(find.text('编辑'));
await tester.pumpAndSettle();
await tester.ensureVisible(find.text('删除地址'));
await tester.tap(find.text('删除地址'));
await tester.pumpAndSettle();
await tester.tap(find.text('取消'));
await tester.pumpAndSettle();
expect(repo.deletes, 0);
await tester.tap(find.text('删除地址'));
await tester.pumpAndSettle();
await tester.tap(find.text('删除'));
await tester.pumpAndSettle();
expect(repo.deletes, 1);
expect(find.text('暂无收货地址'), findsOneWidget);
});
}