543 lines
21 KiB
Dart
543 lines
21 KiB
Dart
import 'dart:async';
|
||
|
||
import 'package:dio/dio.dart';
|
||
import 'package:flutter/foundation.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||
import 'package:flutter_test/flutter_test.dart';
|
||
import 'package:fpdart/fpdart.dart';
|
||
import 'package:shared_preferences/shared_preferences.dart';
|
||
import 'package:maibu_satabot_v2/core/app/app_user_cubit.dart';
|
||
import 'package:maibu_satabot_v2/core/di/injection.dart';
|
||
import 'package:maibu_satabot_v2/core/domain/entities/user_entity.dart';
|
||
import 'package:maibu_satabot_v2/core/error/failure.dart';
|
||
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
|
||
import 'package:maibu_satabot_v2/core/logging/i_logger_service.dart';
|
||
import 'package:maibu_satabot_v2/features/devices/data/datasources/device_task_datasource.dart';
|
||
import 'package:maibu_satabot_v2/features/devices/data/repositories/device_task_repository_impl.dart';
|
||
import 'package:maibu_satabot_v2/features/devices/domain/entities/device_task_entity.dart';
|
||
import 'package:maibu_satabot_v2/features/devices/domain/repositories/device_task_repository.dart';
|
||
import 'package:maibu_satabot_v2/features/devices/domain/usecases/get_device_task_pool_usecase.dart';
|
||
import 'package:maibu_satabot_v2/features/devices/domain/usecases/save_device_schedule_plan_usecase.dart';
|
||
import 'package:maibu_satabot_v2/features/devices/presentation/bloc/devices_cubit.dart';
|
||
import 'package:maibu_satabot_v2/features/devices/presentation/bloc/devices_state.dart';
|
||
import 'package:maibu_satabot_v2/features/v2/home/domain/entities/site_entity.dart';
|
||
import 'package:maibu_satabot_v2/features/v2/device_list/presentation/bloc/robot_list_bloc.dart';
|
||
import 'package:maibu_satabot_v2/features/v2/device_list/presentation/pages/robot_autonomous_work_page_v2.dart';
|
||
import 'package:maibu_satabot_v2/features/v2/site/presentation/cubit/site_cubit.dart';
|
||
import 'package:maibu_satabot_v2/features/v2/work/presentation/cubit/work_home_task_cubit.dart';
|
||
import 'package:maibu_satabot_v2/features/v2/work/presentation/cubit/schedule_plan_create_cubit.dart';
|
||
import 'package:maibu_satabot_v2/features/v2/work/presentation/pages/work_plan_create_page_v2.dart';
|
||
import 'package:maibu_satabot_v2/features/v2/work/presentation/pages/work_plan_page_v2.dart';
|
||
import 'package:maibu_satabot_v2/features/v2/work/presentation/pages/work_home_page_v2.dart';
|
||
|
||
class _Tasks implements DeviceTaskRepository {
|
||
final requests = <(String, int, int)>[];
|
||
Future<Either<Failure, List<DeviceTaskEntity>>> Function(int siteId)
|
||
response = (_) async => const Right([]);
|
||
|
||
@override
|
||
Future<Either<Failure, List<DeviceTaskEntity>>> getDeviceTaskPool({
|
||
required String userId,
|
||
required int siteId,
|
||
required int orgId,
|
||
int pageNum = 1,
|
||
int pageSize = 99999999,
|
||
}) {
|
||
requests.add((userId, siteId, orgId));
|
||
return response(siteId);
|
||
}
|
||
|
||
@override
|
||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||
}
|
||
|
||
DeviceTaskEntity task(
|
||
int id,
|
||
String status, {
|
||
String? device,
|
||
int site = 18,
|
||
int org = 6,
|
||
}) => DeviceTaskEntity(
|
||
id: id,
|
||
deviceId: device ?? 'SN$id',
|
||
taskStatus: status,
|
||
taskStatusTranslate: '',
|
||
siteId: site,
|
||
orgId: org,
|
||
routeId: 256,
|
||
);
|
||
|
||
class _Devices extends Cubit<DevicesState> implements DevicesCubit {
|
||
_Devices() : super(const DevicesState());
|
||
@override
|
||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||
}
|
||
|
||
class _Logger implements ILoggerService {
|
||
@override
|
||
void logWithLevel(
|
||
String message, {
|
||
String level = 'INFO',
|
||
Map<String, dynamic>? data,
|
||
bool shouldLog = false,
|
||
}) {}
|
||
@override
|
||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||
}
|
||
|
||
class _LocaleDelegate extends LocalizationsDelegate<AppLocalizations> {
|
||
const _LocaleDelegate(this.value);
|
||
final AppLocalizations value;
|
||
@override
|
||
bool isSupported(Locale locale) => true;
|
||
@override
|
||
Future<AppLocalizations> load(Locale locale) => SynchronousFuture(value);
|
||
@override
|
||
bool shouldReload(_LocaleDelegate old) => old.value != value;
|
||
}
|
||
|
||
void main() {
|
||
TestWidgetsFlutterBinding.ensureInitialized();
|
||
|
||
group('场站任务池状态', () {
|
||
late _Tasks repository;
|
||
late WorkHomeTaskCubit cubit;
|
||
setUp(() {
|
||
repository = _Tasks();
|
||
cubit = WorkHomeTaskCubit(GetDeviceTaskPoolUseCase(repository));
|
||
});
|
||
tearDown(() => cubit.close());
|
||
|
||
test('单次查询包含整个场站设备,排除终态/跨场站/重复记录并按状态排序', () async {
|
||
repository.response = (_) async => Right([
|
||
task(1, 'NEW'),
|
||
task(2, 'EXECUTING'),
|
||
task(3, 'PAUSE'),
|
||
task(4, 'FAILED'),
|
||
task(5, 'CANCELING'),
|
||
task(6, 'FINISH'),
|
||
task(7, 'CANCELED'),
|
||
task(8, 'CANCELLED'),
|
||
task(9, 'EXECUTING', site: 99),
|
||
task(10, 'NEW', org: 99),
|
||
task(2, 'EXECUTING'),
|
||
task(11, ' new '),
|
||
]);
|
||
await cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
expect(repository.requests, [('u1', 18, 6)]);
|
||
expect(cubit.state.status, WorkHomeTaskStatus.ready);
|
||
expect(cubit.state.tasks.map((t) => t.id), [2, 3, 4, 5, 11, 1]);
|
||
expect(cubit.state.runningCount, 1);
|
||
expect(cubit.state.pendingCount, 2);
|
||
});
|
||
|
||
test('切换场站立即清除旧数据,忽略迟到的旧场站响应', () async {
|
||
final oldResponse = Completer<Either<Failure, List<DeviceTaskEntity>>>();
|
||
repository.response = (site) => site == 18
|
||
? oldResponse.future
|
||
: Future.value(Right([task(20, 'NEW', site: 19)]));
|
||
final old = cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
final current = cubit.load(userId: 'u1', siteId: 19, orgId: 6);
|
||
expect(cubit.state.tasks, isEmpty);
|
||
await current;
|
||
oldResponse.complete(Right([task(1, 'EXECUTING')]));
|
||
await old;
|
||
expect(cubit.state.tasks.single.id, 20);
|
||
expect(cubit.state.pendingCount, 1);
|
||
expect(cubit.state.runningCount, 0);
|
||
});
|
||
|
||
test('并发刷新复用同一请求,退出登录后不回填旧任务', () async {
|
||
final response = Completer<Either<Failure, List<DeviceTaskEntity>>>();
|
||
repository.response = (_) => response.future;
|
||
final first = cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
final second = cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
expect(repository.requests, hasLength(1));
|
||
await cubit.load(userId: null, siteId: 18, orgId: 6);
|
||
response.complete(Right([task(1, 'EXECUTING')]));
|
||
await Future.wait([first, second]);
|
||
expect(cubit.state.status, WorkHomeTaskStatus.noUser);
|
||
expect(cubit.state.tasks, isEmpty);
|
||
});
|
||
|
||
test('未选择场站不发送请求,接口失败可重试,空列表才显示真实的零', () async {
|
||
await cubit.load(userId: 'u1', siteId: null, orgId: null);
|
||
expect(repository.requests, isEmpty);
|
||
expect(cubit.state.status, WorkHomeTaskStatus.noSite);
|
||
repository.response = (_) async => Left(Failure('网络失败'));
|
||
await cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
expect(cubit.state.status, WorkHomeTaskStatus.failure);
|
||
repository.response = (_) async => const Right([]);
|
||
await cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
expect(cubit.state.status, WorkHomeTaskStatus.ready);
|
||
expect(cubit.state.runningCount, 0);
|
||
expect(cubit.state.pendingCount, 0);
|
||
});
|
||
|
||
test('同场站刷新保留内容,相同任务的新对象或返回顺序变化均不通知渲染', () async {
|
||
repository.response = (_) async =>
|
||
Right([task(1, 'NEW'), task(2, 'EXECUTING')]);
|
||
await cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
final original = cubit.state;
|
||
final events = <WorkHomeTaskState>[];
|
||
final subscription = cubit.stream.listen(events.add);
|
||
addTearDown(subscription.cancel);
|
||
final response = Completer<Either<Failure, List<DeviceTaskEntity>>>();
|
||
repository.response = (_) => response.future;
|
||
final refresh = cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
expect(identical(cubit.state, original), isTrue);
|
||
response.complete(Right([task(2, 'EXECUTING'), task(1, 'NEW')]));
|
||
await refresh;
|
||
await Future<void>.delayed(Duration.zero);
|
||
expect(identical(cubit.state, original), isTrue);
|
||
expect(events, isEmpty);
|
||
});
|
||
|
||
test('任务内容变化只发布一次 ready,真实空列表也能替换旧任务', () async {
|
||
repository.response = (_) async => Right([task(1, 'NEW')]);
|
||
await cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
final events = <WorkHomeTaskState>[];
|
||
final subscription = cubit.stream.listen(events.add);
|
||
addTearDown(subscription.cancel);
|
||
repository.response = (_) async => Right([task(1, 'EXECUTING')]);
|
||
await cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
await Future<void>.delayed(Duration.zero);
|
||
expect(events.map((s) => s.status), [WorkHomeTaskStatus.ready]);
|
||
expect(cubit.state.runningCount, 1);
|
||
expect(cubit.state.pendingCount, 0);
|
||
repository.response = (_) async => const Right([]);
|
||
await cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
expect(cubit.state.tasks, isEmpty);
|
||
expect(cubit.state.runningCount, 0);
|
||
});
|
||
|
||
test('刷新失败保留上次任务和计数,成功后清除刷新错误', () async {
|
||
repository.response = (_) async => Right([task(1, 'EXECUTING')]);
|
||
await cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
repository.response = (_) async => Left(Failure('临时断网'));
|
||
await cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
expect(cubit.state.status, WorkHomeTaskStatus.ready);
|
||
expect(cubit.state.runningCount, 1);
|
||
expect(cubit.state.tasks.single.id, 1);
|
||
expect(cubit.state.error, '临时断网');
|
||
repository.response = (_) async => Right([task(1, 'EXECUTING')]);
|
||
await cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
expect(cubit.state.error, isNull);
|
||
});
|
||
|
||
test('已有数据时切换账号仍立即清除任务,忽略旧账号刷新结果', () async {
|
||
repository.response = (_) async => Right([task(1, 'EXECUTING')]);
|
||
await cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
final old = Completer<Either<Failure, List<DeviceTaskEntity>>>();
|
||
repository.response = (_) => old.future;
|
||
final refresh = cubit.load(userId: 'u1', siteId: 18, orgId: 6);
|
||
repository.response = (_) async => const Right([]);
|
||
final switched = cubit.load(userId: 'u2', siteId: 18, orgId: 6);
|
||
expect(cubit.state.status, WorkHomeTaskStatus.loading);
|
||
expect(cubit.state.tasks, isEmpty);
|
||
await switched;
|
||
old.complete(Right([task(1, 'EXECUTING')]));
|
||
await refresh;
|
||
expect(cubit.state.status, WorkHomeTaskStatus.ready);
|
||
expect(cubit.state.tasks, isEmpty);
|
||
});
|
||
});
|
||
|
||
group('作业首页真实查询链路', () {
|
||
late Dio dio;
|
||
late SiteCubit sites;
|
||
late AppUserCubit users;
|
||
late _Devices devices;
|
||
late List<RequestOptions> requests;
|
||
late Map<String, dynamic> response;
|
||
|
||
setUp(() async {
|
||
SharedPreferences.setMockInitialValues({});
|
||
sites = SiteCubit(await SharedPreferences.getInstance());
|
||
sites.updateSites(const [
|
||
SiteEntity(id: 18, siteName: '测试场站', orgId: 6, status: 0),
|
||
]);
|
||
users = AppUserCubit()
|
||
..setAuth(
|
||
const UserEntity(
|
||
userId: 'u1',
|
||
username: 'test',
|
||
nickname: '',
|
||
token: 'test',
|
||
orgId: 999,
|
||
),
|
||
);
|
||
devices = _Devices();
|
||
requests = [];
|
||
response = {
|
||
'code': 200,
|
||
'rows': [
|
||
for (final t in [
|
||
task(1, 'EXECUTING'),
|
||
task(2, 'NEW'),
|
||
task(3, 'PAUSE'),
|
||
task(4, 'FAILED'),
|
||
task(5, 'FINISH'),
|
||
])
|
||
{
|
||
'id': t.id,
|
||
'deviceId': t.deviceId,
|
||
'routeId': t.routeId,
|
||
'siteId': 18,
|
||
'orgId': 6,
|
||
if (t.id == 2)
|
||
'taskStatus': t.taskStatus
|
||
else
|
||
'taskStaus': t.taskStatus,
|
||
},
|
||
],
|
||
};
|
||
dio = Dio()
|
||
..interceptors.add(
|
||
InterceptorsWrapper(
|
||
onRequest: (options, handler) {
|
||
requests.add(options);
|
||
handler.resolve(
|
||
Response(
|
||
requestOptions: options,
|
||
statusCode: 200,
|
||
data: options.method == 'GET'
|
||
? {
|
||
'code': 200,
|
||
'rows': [
|
||
{'deviceName': 'SN1', 'deviceId': 'robot-1'},
|
||
],
|
||
}
|
||
: response,
|
||
),
|
||
);
|
||
},
|
||
),
|
||
);
|
||
sl.registerSingleton<SiteCubit>(sites);
|
||
sl.registerSingleton<AppUserCubit>(users);
|
||
sl.registerSingleton<DevicesCubit>(devices);
|
||
sl.registerSingleton<ILoggerService>(_Logger());
|
||
sl.registerFactory<RobotListBloc>(() => RobotListBloc(dio));
|
||
sl.registerFactory<SchedulePlanCreateCubit>(
|
||
() => SchedulePlanCreateCubit(
|
||
SaveDeviceSchedulePlanUseCase(
|
||
DeviceTaskRepositoryImpl(datasource: DeviceTaskDatasourceImpl(dio)),
|
||
),
|
||
),
|
||
);
|
||
sl.registerFactory<WorkHomeTaskCubit>(
|
||
() => WorkHomeTaskCubit(
|
||
GetDeviceTaskPoolUseCase(
|
||
DeviceTaskRepositoryImpl(datasource: DeviceTaskDatasourceImpl(dio)),
|
||
),
|
||
),
|
||
);
|
||
});
|
||
tearDown(() async {
|
||
await sites.close();
|
||
await users.close();
|
||
await devices.close();
|
||
dio.close();
|
||
await sl.reset();
|
||
});
|
||
|
||
Future<void> mount(WidgetTester tester, {bool active = true}) async {
|
||
final l10n = await tester.runAsync(() async {
|
||
final l10n = AppLocalizations(const Locale('zh', 'CN'));
|
||
await l10n.load();
|
||
return l10n;
|
||
});
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
localizationsDelegates: [_LocaleDelegate(l10n!)],
|
||
home: WorkHomePageV2(isActive: active),
|
||
),
|
||
);
|
||
addTearDown(() async {
|
||
await tester.pumpWidget(const SizedBox.shrink());
|
||
await tester.pump();
|
||
});
|
||
await tester.pumpAndSettle();
|
||
}
|
||
|
||
String stat(WidgetTester tester, String label) =>
|
||
tester.widget<Text>(find.byKey(ValueKey('work_stat_$label'))).data!;
|
||
|
||
testWidgets('20秒轮询无变化不重建页面,有任务变化才更新统计', (tester) async {
|
||
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed);
|
||
await mount(tester);
|
||
final original = tester.widget(
|
||
find.byKey(const ValueKey('work_task_SN1_1')),
|
||
);
|
||
await tester.pump(const Duration(seconds: 20));
|
||
await tester.pumpAndSettle();
|
||
expect(requests, hasLength(2));
|
||
expect(
|
||
identical(
|
||
tester.widget(find.byKey(const ValueKey('work_task_SN1_1'))),
|
||
original,
|
||
),
|
||
isTrue,
|
||
);
|
||
expect(find.byType(CircularProgressIndicator), findsNothing);
|
||
response = {'code': 200, 'rows': []};
|
||
await tester.pump(const Duration(seconds: 20));
|
||
await tester.pumpAndSettle();
|
||
expect(requests, hasLength(3));
|
||
expect(stat(tester, '执行中'), '0');
|
||
expect(find.text('暂无作业'), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('轮询失败保留任务与统计,用图标提示错误;恢复后移除提示', (tester) async {
|
||
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed);
|
||
await mount(tester);
|
||
response = {'code': 500, 'msg': '任务池暂时不可用'};
|
||
await tester.pump(const Duration(seconds: 20));
|
||
await tester.pumpAndSettle();
|
||
expect(stat(tester, '执行中'), '1');
|
||
expect(find.text('任务 #1'), findsOneWidget);
|
||
expect(find.byKey(const ValueKey('work_refresh_error')), findsOneWidget);
|
||
expect(find.text('任务加载失败'), findsNothing);
|
||
response = {'code': 200, 'rows': []};
|
||
await tester.pump(const Duration(seconds: 20));
|
||
await tester.pumpAndSettle();
|
||
expect(stat(tester, '执行中'), '0');
|
||
expect(find.byKey(const ValueKey('work_refresh_error')), findsNothing);
|
||
});
|
||
|
||
testWidgets('下发作业计划直接进入新建页,保留原列表页但不经过它', (tester) async {
|
||
await mount(tester);
|
||
await tester.ensureVisible(find.text('下发作业计划'));
|
||
await tester.tap(find.text('下发作业计划'));
|
||
await tester.pumpAndSettle();
|
||
expect(find.byType(WorkPlanCreatePageV2), findsOneWidget);
|
||
expect(find.byType(WorkPlanPageV2), findsNothing);
|
||
expect(tester.takeException(), isNull);
|
||
});
|
||
|
||
testWidgets('按当前用户和场站组织查询,统计和所有任务来自同一返回列表', (tester) async {
|
||
await mount(tester);
|
||
expect(requests, hasLength(1));
|
||
expect(requests.single.method, 'POST');
|
||
expect(requests.single.uri.path, '/iot/deviceTask/deviceTaskPool');
|
||
expect(requests.single.data, {
|
||
'userId': 'u1',
|
||
'siteId': 18,
|
||
'orgId': 6,
|
||
'pageNum': 1,
|
||
'pageSize': 99999999,
|
||
});
|
||
expect(stat(tester, '执行中'), '1');
|
||
expect(stat(tester, '待执行'), '1');
|
||
expect(stat(tester, '今日已完成'), '—');
|
||
expect(find.text('任务 #1'), findsOneWidget);
|
||
expect(find.text('任务 #3'), findsOneWidget);
|
||
expect(find.text('任务 #5'), findsNothing);
|
||
expect(find.text('68%'), findsNothing);
|
||
await tester.ensureVisible(find.text('全部任务'));
|
||
await tester.tap(find.text('全部任务'));
|
||
await tester.pumpAndSettle();
|
||
expect(find.text('执行设备:SN2'), findsOneWidget);
|
||
expect(find.text('任务 #5'), findsNothing);
|
||
expect(requests, hasLength(1));
|
||
expect(tester.takeException(), isNull);
|
||
});
|
||
|
||
testWidgets('点待执行统计只显示 NEW 任务,失败/暂停不混入', (tester) async {
|
||
await mount(tester);
|
||
await tester.tap(find.text('待执行'));
|
||
await tester.pumpAndSettle();
|
||
final sheet = find.byType(BottomSheet);
|
||
expect(
|
||
find.descendant(of: sheet, matching: find.text('任务 #2')),
|
||
findsOneWidget,
|
||
);
|
||
expect(
|
||
find.descendant(of: sheet, matching: find.text('任务 #3')),
|
||
findsNothing,
|
||
);
|
||
expect(tester.takeException(), isNull);
|
||
});
|
||
|
||
testWidgets('任务设备不在场站列表时提示,不误用列表中的第一台设备', (tester) async {
|
||
await mount(tester);
|
||
await tester.tap(find.text('待执行'));
|
||
await tester.pumpAndSettle();
|
||
final card = find.byKey(const ValueKey('work_task_SN2_2'));
|
||
final button = find.descendant(of: card, matching: find.text('查看任务'));
|
||
await tester.ensureVisible(button);
|
||
await tester.tap(button);
|
||
await tester.pumpAndSettle();
|
||
expect(requests.last.method, 'GET');
|
||
expect(requests.last.queryParameters['siteId'], 18);
|
||
expect(find.text('当前场站设备列表中未找到对应设备'), findsOneWidget);
|
||
expect(find.byType(RobotAutonomousWorkPageV2), findsNothing);
|
||
expect(tester.takeException(), isNull);
|
||
await tester.pump(const Duration(seconds: 3));
|
||
});
|
||
|
||
testWidgets('请求失败显示重试,成功空列表显示零和空态', (tester) async {
|
||
response = {'code': 500, 'msg': '任务池不可用'};
|
||
await mount(tester);
|
||
expect(stat(tester, '执行中'), '—');
|
||
expect(find.text('任务加载失败'), findsOneWidget);
|
||
response = {'code': 200, 'rows': []};
|
||
await tester.ensureVisible(find.text('重新加载'));
|
||
await tester.tap(find.text('重新加载'));
|
||
await tester.pumpAndSettle();
|
||
expect(stat(tester, '执行中'), '0');
|
||
expect(stat(tester, '待执行'), '0');
|
||
expect(find.text('暂无作业'), findsOneWidget);
|
||
expect(requests, hasLength(2));
|
||
});
|
||
|
||
testWidgets('切换场站触发新查询,返回列表替换旧任务', (tester) async {
|
||
await mount(tester);
|
||
response = {
|
||
'code': 200,
|
||
'rows': [
|
||
{
|
||
'id': 10,
|
||
'deviceId': 'other',
|
||
'taskStaus': 'NEW',
|
||
'siteId': 19,
|
||
'orgId': 7,
|
||
},
|
||
],
|
||
};
|
||
sites.updateSites(const [
|
||
SiteEntity(id: 19, siteName: '另一场站', orgId: 7, status: 0),
|
||
]);
|
||
await tester.pumpAndSettle();
|
||
expect(requests, hasLength(2));
|
||
expect(requests.last.data['siteId'], 19);
|
||
expect(requests.last.data['orgId'], 7);
|
||
expect(stat(tester, '执行中'), '0');
|
||
expect(find.text('任务 #1'), findsNothing);
|
||
expect(find.text('任务 #10'), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('非当前 tab 不查询,激活后加载;退出登录清空任务', (tester) async {
|
||
await mount(tester, active: false);
|
||
expect(requests, isEmpty);
|
||
final app = tester.widget<MaterialApp>(find.byType(MaterialApp));
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
localizationsDelegates: app.localizationsDelegates,
|
||
home: const WorkHomePageV2(isActive: true),
|
||
),
|
||
);
|
||
await tester.pumpAndSettle();
|
||
expect(requests, hasLength(1));
|
||
users.clearAuth();
|
||
await tester.pumpAndSettle();
|
||
expect(find.text('任务 #1'), findsNothing);
|
||
expect(find.text('请先登录后查看作业任务'), findsOneWidget);
|
||
expect(stat(tester, '执行中'), '—');
|
||
expect(requests, hasLength(1));
|
||
});
|
||
});
|
||
}
|