2026-09-05 19:51:36 +08:00
|
|
|
|
// 功能描述:验证作业前检查页面失败重试不会向 setState 返回异步任务。
|
|
|
|
|
|
// 版本:1.0.0
|
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
|
|
import 'package:service_app/app/dependencies.dart';
|
|
|
|
|
|
import 'package:service_app/data/repositories/service_repository.dart';
|
|
|
|
|
|
import 'package:service_app/data/services/api_client.dart';
|
|
|
|
|
|
import 'package:service_app/data/services/location_service.dart';
|
|
|
|
|
|
import 'package:service_app/data/services/secure_session_store.dart';
|
|
|
|
|
|
import 'package:service_app/domain/models/service_models.dart';
|
|
|
|
|
|
import 'package:service_app/ui/features/preflight/preflight_page.dart';
|
|
|
|
|
|
|
|
|
|
|
|
/// 提供无需平台插件的空会话存储。
|
|
|
|
|
|
class _EmptySessionStore implements SessionStore {
|
|
|
|
|
|
@override
|
|
|
|
|
|
Future<void> delete(String key) async {}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
Future<String?> read(String key) async => null;
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
Future<void> write(String key, String value) async {}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 提供不会在重试测试中访问系统定位的占位实现。
|
|
|
|
|
|
class _UnusedLocationService implements LocationService {
|
|
|
|
|
|
@override
|
|
|
|
|
|
Future<LocationPoint> current() => throw UnimplementedError();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 首次加载失败、第二次成功,用于验证真实重试路径。
|
|
|
|
|
|
class _FailOnceRepository extends ServiceRepository {
|
|
|
|
|
|
_FailOnceRepository()
|
|
|
|
|
|
: super(
|
|
|
|
|
|
ApiClient(() => '', baseUrl: 'https://api.example.com'),
|
|
|
|
|
|
_UnusedLocationService(),
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
int calls = 0;
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
Future<PreflightResult> preflight() async {
|
|
|
|
|
|
calls += 1;
|
|
|
|
|
|
if (calls == 1) throw StateError('temporary failure');
|
|
|
|
|
|
return const PreflightResult(
|
|
|
|
|
|
roleCode: 'delivery',
|
|
|
|
|
|
workStatus: 'off_duty',
|
|
|
|
|
|
canWork: false,
|
|
|
|
|
|
checks: {},
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-05 20:17:07 +08:00
|
|
|
|
/// 返回包含一个真实阻断项和一个暂不检查项的固定预检结果。
|
|
|
|
|
|
class _BlockedRepository extends ServiceRepository {
|
|
|
|
|
|
_BlockedRepository()
|
|
|
|
|
|
: super(
|
|
|
|
|
|
ApiClient(() => '', baseUrl: 'https://api.example.com'),
|
|
|
|
|
|
_UnusedLocationService(),
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
Future<PreflightResult> preflight() async => const PreflightResult(
|
|
|
|
|
|
roleCode: 'delivery',
|
|
|
|
|
|
workStatus: 'on_duty',
|
|
|
|
|
|
canWork: false,
|
|
|
|
|
|
checks: {
|
|
|
|
|
|
'credential': {'status': 'blocked', 'reason': 'missing'},
|
|
|
|
|
|
'daily_training': {'status': 'not_configured'},
|
|
|
|
|
|
},
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-05 19:51:36 +08:00
|
|
|
|
/// 点击重新加载后应成功刷新,且测试过程不得出现 Flutter 断言。
|
|
|
|
|
|
void main() {
|
|
|
|
|
|
testWidgets('作业检查失败后可重新加载', (tester) async {
|
|
|
|
|
|
final repository = _FailOnceRepository();
|
|
|
|
|
|
final session = StaffSession(_EmptySessionStore());
|
|
|
|
|
|
await tester.pumpWidget(
|
|
|
|
|
|
MaterialApp(
|
|
|
|
|
|
home: PreflightPage(session: session, repository: repository),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
|
|
|
|
|
|
expect(find.text('作业检查加载失败'), findsOneWidget);
|
|
|
|
|
|
expect(repository.calls, 1);
|
|
|
|
|
|
|
|
|
|
|
|
await tester.tap(find.text('重新加载'));
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
|
|
|
|
|
|
expect(find.text('作业检查加载失败'), findsNothing);
|
|
|
|
|
|
expect(find.text('仍有前置条件未完成'), findsOneWidget);
|
|
|
|
|
|
expect(repository.calls, 2);
|
|
|
|
|
|
expect(tester.takeException(), isNull);
|
|
|
|
|
|
});
|
2026-09-05 20:17:07 +08:00
|
|
|
|
|
|
|
|
|
|
testWidgets('仅统计阻断项并显示资质处理指引', (tester) async {
|
|
|
|
|
|
await tester.pumpWidget(
|
|
|
|
|
|
MaterialApp(
|
|
|
|
|
|
home: PreflightPage(
|
|
|
|
|
|
session: StaffSession(_EmptySessionStore()),
|
|
|
|
|
|
repository: _BlockedRepository(),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
|
|
|
|
|
|
expect(find.text('完成 1 项阻断后可进入'), findsOneWidget);
|
|
|
|
|
|
expect(find.text('暂不检查'), findsOneWidget);
|
|
|
|
|
|
expect(find.text('尚未配置有效资质,请联系所属组织管理员补充或审核'), findsOneWidget);
|
|
|
|
|
|
expect(find.text('下班打卡'), findsOneWidget);
|
|
|
|
|
|
});
|
2026-09-05 19:51:36 +08:00
|
|
|
|
}
|