156 lines
5.8 KiB
Dart
156 lines
5.8 KiB
Dart
|
|
// 功能描述:验证报修分步校验、地址返回、显式提交与未知结果重试。
|
|||
|
|
// 版本:1.0.0。
|
|||
|
|
import 'package:flutter/material.dart';
|
|||
|
|
import 'dart:convert';
|
|||
|
|
import 'dart:typed_data';
|
|||
|
|
import 'package:image_picker/image_picker.dart';
|
|||
|
|
import 'package:flutter_test/flutter_test.dart';
|
|||
|
|
import 'package:go_router/go_router.dart';
|
|||
|
|
import 'package:user_app/data/repositories/client_repository.dart';
|
|||
|
|
import 'package:user_app/data/services/api_client.dart';
|
|||
|
|
import 'package:user_app/domain/models/shipping_address.dart';
|
|||
|
|
import 'package:user_app/ui/features/tickets/repair_page.dart';
|
|||
|
|
|
|||
|
|
class _RepairRepository extends ClientRepository {
|
|||
|
|
_RepairRepository() : super(ApiClient(() => '', baseUrl: 'https://api.example.com'));
|
|||
|
|
final requests = <String>[];
|
|||
|
|
int uploads = 0;
|
|||
|
|
@override
|
|||
|
|
Future<String> uploadTicketPhoto(Uint8List bytes, String filename) async {
|
|||
|
|
uploads++;
|
|||
|
|
return '/uploads/ticket-photos/owned/test.png';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
Future<String> submitRepair({
|
|||
|
|
required String requestNo,
|
|||
|
|
required String description,
|
|||
|
|
required String faultType,
|
|||
|
|
required String addressIdentity,
|
|||
|
|
DateTime? appointment,
|
|||
|
|
List<Map<String, Object?>> photos = const [],
|
|||
|
|
}) async {
|
|||
|
|
expect(description, '阀门异响');
|
|||
|
|
expect(addressIdentity, 'address-1');
|
|||
|
|
expect(faultType, 'valve');
|
|||
|
|
requests.add(requestNo);
|
|||
|
|
expect(photos.length, 1);
|
|||
|
|
expect(photos.first['uri'], '/uploads/ticket-photos/owned/test.png');
|
|||
|
|
if (requests.length == 1) throw const ApiException(500, '结果待确认');
|
|||
|
|
return 'ticket-1';
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void main() {
|
|||
|
|
testWidgets('紧急电话只在用户点击后调用系统拨号入口', (tester) async {
|
|||
|
|
tester.view.physicalSize = const Size(390, 844);
|
|||
|
|
tester.view.devicePixelRatio = 1;
|
|||
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|||
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|||
|
|
Uri? opened;
|
|||
|
|
final repository = _RepairRepository();
|
|||
|
|
await tester.pumpWidget(
|
|||
|
|
MaterialApp(
|
|||
|
|
home: RepairPage(
|
|||
|
|
repository: repository,
|
|||
|
|
launchEmergency: (uri) async {
|
|||
|
|
opened = uri;
|
|||
|
|
return true;
|
|||
|
|
},
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
await tester.pumpAndSettle();
|
|||
|
|
await tester.drag(find.byType(ListView), const Offset(0, -500));
|
|||
|
|
await tester.pumpAndSettle();
|
|||
|
|
expect(opened, isNull);
|
|||
|
|
await tester.tap(find.widgetWithText(TextButton, '紧急电话'));
|
|||
|
|
await tester.pumpAndSettle();
|
|||
|
|
expect(opened, Uri(scheme: 'tel', path: '119'));
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
testWidgets('分步校验,失败冻结原请求,重试不重新生成请求号', (tester) async {
|
|||
|
|
tester.view.physicalSize = const Size(390, 844);
|
|||
|
|
tester.view.devicePixelRatio = 1;
|
|||
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|||
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|||
|
|
final repository = _RepairRepository();
|
|||
|
|
final router = GoRouter(
|
|||
|
|
initialLocation: '/repair',
|
|||
|
|
routes: [
|
|||
|
|
GoRoute(
|
|||
|
|
path: '/repair',
|
|||
|
|
builder: (_, state) => RepairPage(
|
|||
|
|
repository: repository,
|
|||
|
|
pickPhoto: (_) async => XFile.fromData(
|
|||
|
|
base64Decode(
|
|||
|
|
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+aX1cAAAAASUVORK5CYII=',
|
|||
|
|
),
|
|||
|
|
name: 'test.png',
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
GoRoute(
|
|||
|
|
path: '/addresses',
|
|||
|
|
builder: (context, state) => Scaffold(
|
|||
|
|
body: TextButton(
|
|||
|
|
onPressed: () => context.pop(
|
|||
|
|
const ShippingAddress(
|
|||
|
|
identity: 'address-1',
|
|||
|
|
address: '测试路88号',
|
|||
|
|
contactName: '联系人',
|
|||
|
|
contactPhone: '13800000001',
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
child: const Text('选这个地址'),
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
),
|
|||
|
|
GoRoute(
|
|||
|
|
path: '/tickets/:identity',
|
|||
|
|
builder: (_, state) => const Scaffold(body: Text('已打开工单详情')),
|
|||
|
|
),
|
|||
|
|
],
|
|||
|
|
);
|
|||
|
|
await tester.pumpWidget(MaterialApp.router(routerConfig: router));
|
|||
|
|
await tester.pumpAndSettle();
|
|||
|
|
await tester.ensureVisible(find.text('下一步'));
|
|||
|
|
await tester.tap(find.text('下一步'));
|
|||
|
|
await tester.pumpAndSettle();
|
|||
|
|
expect(find.text('请描述故障现象'), findsWidgets);
|
|||
|
|
await tester.enterText(find.byType(TextField), '阀门异响');
|
|||
|
|
expect(find.text('添加照片'), findsNWidgets(3));
|
|||
|
|
await tester.ensureVisible(find.text('添加照片').first);
|
|||
|
|
await tester.tap(find.text('添加照片').first);
|
|||
|
|
await tester.pumpAndSettle();
|
|||
|
|
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(find.text('请选择并补齐联系人、电话和地址'), findsOneWidget);
|
|||
|
|
await tester.tap(find.text('选择报修地址'));
|
|||
|
|
await tester.pumpAndSettle();
|
|||
|
|
await tester.tap(find.text('选这个地址'));
|
|||
|
|
await tester.pumpAndSettle();
|
|||
|
|
await tester.tap(find.text('下一步'));
|
|||
|
|
await tester.pumpAndSettle();
|
|||
|
|
expect(repository.requests, isEmpty);
|
|||
|
|
await tester.ensureVisible(find.widgetWithText(FilledButton, '确认提交'));
|
|||
|
|
await tester.tap(find.widgetWithText(FilledButton, '确认提交'));
|
|||
|
|
await tester.pumpAndSettle();
|
|||
|
|
expect(find.text('结果待确认'), findsOneWidget);
|
|||
|
|
await tester.ensureVisible(find.text('重试提交'));
|
|||
|
|
await tester.tap(find.text('重试提交'));
|
|||
|
|
await tester.pumpAndSettle();
|
|||
|
|
expect(repository.requests.length, 2);
|
|||
|
|
expect(repository.uploads, 1);
|
|||
|
|
expect(repository.requests[0], repository.requests[1]);
|
|||
|
|
expect(find.text('已打开工单详情'), findsOneWidget);
|
|||
|
|
await tester.pumpWidget(const SizedBox());
|
|||
|
|
router.dispose();
|
|||
|
|
});
|
|||
|
|
}
|