// 功能描述:验证报修分步校验、地址返回、显式提交与未知结果重试。 // 版本: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 = []; int uploads = 0; @override Future uploadTicketPhoto(Uint8List bytes, String filename) async { uploads++; return '/uploads/ticket-photos/owned/test.png'; } @override Future submitRepair({ required String requestNo, required String description, required String faultType, required String addressIdentity, DateTime? appointment, List> 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(); }); }