286 lines
10 KiB
Dart
286 lines
10 KiB
Dart
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:forui/forui.dart';
|
|
|
|
import 'package:pj_supermarket_cloud/common/index.dart';
|
|
import 'package:pj_supermarket_cloud/pages/terminal/menu_query/controller.dart';
|
|
import 'package:pj_supermarket_cloud/pages/terminal/menu_query/widgets/query_method_panel.dart';
|
|
|
|
void main() {
|
|
testWidgets('手动模式保留开始按钮,自动模式改为饭卡等待状态且仍可切换方式', (tester) async {
|
|
await tester.binding.setSurfaceSize(const Size(1920, 1080));
|
|
addTearDown(() => tester.binding.setSurfaceSize(null));
|
|
var startCalls = 0;
|
|
ReservationRecognitionMethod? selectedMethod;
|
|
final mealSlotController = FRadioSelectGroupController<String>(value: '1');
|
|
addTearDown(mealSlotController.dispose);
|
|
|
|
await tester.pumpWidget(
|
|
_testApp(
|
|
QueryMethodPanel(
|
|
methods: ReservationRecognitionMethod.values,
|
|
selected: ReservationRecognitionMethod.card,
|
|
status: ReservationMenuQueryStatus.idle,
|
|
mealSlotController: mealSlotController,
|
|
autoRecognitionEnabled: false,
|
|
continuousRecognitionEnabled: false,
|
|
quickVerificationEnabled: false,
|
|
allowManualMealPeriodChange: true,
|
|
onSelect: (method) => selectedMethod = method,
|
|
onStart: () => startCalls++,
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.text('开始识别'), findsOneWidget);
|
|
await tester.tap(find.text('开始识别'));
|
|
await tester.pump(const Duration(milliseconds: 250));
|
|
expect(startCalls, 1);
|
|
|
|
await tester.pumpWidget(
|
|
_testApp(
|
|
QueryMethodPanel(
|
|
methods: ReservationRecognitionMethod.values,
|
|
selected: ReservationRecognitionMethod.card,
|
|
status: ReservationMenuQueryStatus.recognizing,
|
|
mealSlotController: mealSlotController,
|
|
autoRecognitionEnabled: true,
|
|
continuousRecognitionEnabled: true,
|
|
quickVerificationEnabled: false,
|
|
allowManualMealPeriodChange: true,
|
|
onSelect: (method) => selectedMethod = method,
|
|
onStart: () => startCalls++,
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.text('开始识别'), findsNothing);
|
|
expect(find.text('持续等待饭卡'), findsOneWidget);
|
|
await tester.tap(find.text('人脸查询'));
|
|
await tester.pump(const Duration(milliseconds: 250));
|
|
expect(selectedMethod, ReservationRecognitionMethod.face);
|
|
expect(startCalls, 1);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('餐段只由快速核销开关控制,不受持续自动识别影响', (tester) async {
|
|
await tester.binding.setSurfaceSize(const Size(1920, 1080));
|
|
addTearDown(() => tester.binding.setSurfaceSize(null));
|
|
final mealSlotController = FRadioSelectGroupController<String>(value: '2');
|
|
addTearDown(mealSlotController.dispose);
|
|
|
|
await tester.pumpWidget(
|
|
_testApp(
|
|
QueryMethodPanel(
|
|
methods: ReservationRecognitionMethod.values,
|
|
selected: ReservationRecognitionMethod.card,
|
|
status: ReservationMenuQueryStatus.recognizing,
|
|
mealSlotController: mealSlotController,
|
|
autoRecognitionEnabled: true,
|
|
continuousRecognitionEnabled: true,
|
|
quickVerificationEnabled: false,
|
|
allowManualMealPeriodChange: true,
|
|
onSelect: (_) {},
|
|
onStart: () {},
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(
|
|
find.byKey(const ValueKey('reservation-meal-slot-trigger')),
|
|
findsNothing,
|
|
);
|
|
expect(find.text('餐段'), findsNothing);
|
|
|
|
await tester.pumpWidget(
|
|
_testApp(
|
|
QueryMethodPanel(
|
|
methods: ReservationRecognitionMethod.values,
|
|
selected: ReservationRecognitionMethod.card,
|
|
status: ReservationMenuQueryStatus.recognizing,
|
|
mealSlotController: mealSlotController,
|
|
autoRecognitionEnabled: true,
|
|
continuousRecognitionEnabled: false,
|
|
quickVerificationEnabled: true,
|
|
allowManualMealPeriodChange: true,
|
|
onSelect: (_) {},
|
|
onStart: () {},
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(
|
|
find.byKey(const ValueKey('reservation-meal-slot-trigger')),
|
|
findsOneWidget,
|
|
);
|
|
expect(find.text('餐段'), findsOneWidget);
|
|
expect(find.text('中餐'), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('餐段默认仅显示当前值,点开后可选择且查询中禁用', (tester) async {
|
|
await tester.binding.setSurfaceSize(const Size(1920, 1080));
|
|
addTearDown(() => tester.binding.setSurfaceSize(null));
|
|
var selectedMealSlot = ReservationMealSlot.morning;
|
|
var status = ReservationMenuQueryStatus.idle;
|
|
final mealSlotController = FRadioSelectGroupController<String>(value: '1');
|
|
mealSlotController.addValueListener((selectedCodes) {
|
|
final selectedCode = selectedCodes.firstOrNull;
|
|
selectedMealSlot = ReservationMealSlot.querySelectableValues.firstWhere(
|
|
(mealSlot) => mealSlot.code == selectedCode,
|
|
);
|
|
});
|
|
addTearDown(mealSlotController.dispose);
|
|
|
|
await tester.pumpWidget(
|
|
_testApp(
|
|
QueryMethodPanel(
|
|
methods: ReservationRecognitionMethod.values,
|
|
selected: ReservationRecognitionMethod.card,
|
|
status: status,
|
|
mealSlotController: mealSlotController,
|
|
autoRecognitionEnabled: false,
|
|
continuousRecognitionEnabled: true,
|
|
quickVerificationEnabled: true,
|
|
allowManualMealPeriodChange: true,
|
|
onSelect: (_) {},
|
|
onStart: () {},
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.byType(FSelectMenuTile<String>), findsOneWidget);
|
|
expect(find.text('餐段'), findsOneWidget);
|
|
expect(find.text('早餐'), findsOneWidget);
|
|
expect(find.text('中餐'), findsNothing);
|
|
expect(find.text('晚餐'), findsNothing);
|
|
final trigger = find.byKey(
|
|
const ValueKey('reservation-meal-slot-trigger'),
|
|
);
|
|
expect(tester.getSize(trigger).height, greaterThanOrEqualTo(48));
|
|
expect(tester.widget<FSelectMenuTile<String>>(trigger).enabled, isTrue);
|
|
|
|
await tester.tap(trigger);
|
|
await tester.pumpAndSettle();
|
|
final noonOption = find.byKey(
|
|
const ValueKey('meal-slot-option-2'),
|
|
);
|
|
expect(tester.getSize(noonOption).height, greaterThanOrEqualTo(48));
|
|
|
|
await tester.tap(noonOption);
|
|
await tester.pumpAndSettle();
|
|
expect(selectedMealSlot, ReservationMealSlot.noon);
|
|
expect(find.text('早餐'), findsNothing);
|
|
expect(find.text('中餐'), findsOneWidget);
|
|
|
|
status = ReservationMenuQueryStatus.recognizing;
|
|
await tester.pumpWidget(
|
|
_testApp(
|
|
QueryMethodPanel(
|
|
methods: ReservationRecognitionMethod.values,
|
|
selected: ReservationRecognitionMethod.card,
|
|
status: status,
|
|
mealSlotController: mealSlotController,
|
|
autoRecognitionEnabled: false,
|
|
continuousRecognitionEnabled: true,
|
|
quickVerificationEnabled: true,
|
|
allowManualMealPeriodChange: true,
|
|
onSelect: (_) {},
|
|
onStart: () {},
|
|
),
|
|
),
|
|
);
|
|
await tester.tap(trigger);
|
|
await tester.pumpAndSettle();
|
|
final nightOption = find.byKey(
|
|
const ValueKey('meal-slot-option-3'),
|
|
);
|
|
await tester.tap(nightOption);
|
|
await tester.pumpAndSettle();
|
|
expect(selectedMealSlot, ReservationMealSlot.night);
|
|
|
|
status = ReservationMenuQueryStatus.querying;
|
|
await tester.pumpWidget(
|
|
_testApp(
|
|
QueryMethodPanel(
|
|
methods: ReservationRecognitionMethod.values,
|
|
selected: ReservationRecognitionMethod.card,
|
|
status: status,
|
|
mealSlotController: mealSlotController,
|
|
autoRecognitionEnabled: false,
|
|
continuousRecognitionEnabled: true,
|
|
quickVerificationEnabled: true,
|
|
allowManualMealPeriodChange: true,
|
|
onSelect: (_) {},
|
|
onStart: () {},
|
|
),
|
|
),
|
|
);
|
|
final disabledTrigger = find.byKey(
|
|
const ValueKey('reservation-meal-slot-trigger'),
|
|
);
|
|
expect(
|
|
tester.widget<FSelectMenuTile<String>>(disabledTrigger).enabled,
|
|
isFalse,
|
|
);
|
|
await tester.tap(disabledTrigger);
|
|
await tester.pump();
|
|
expect(selectedMealSlot, ReservationMealSlot.night);
|
|
expect(
|
|
find.byKey(const ValueKey('meal-slot-option-1')),
|
|
findsNothing,
|
|
);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('禁止主动修改餐段时选择器禁用且无法打开餐段菜单', (tester) async {
|
|
await tester.binding.setSurfaceSize(const Size(1920, 1080));
|
|
addTearDown(() => tester.binding.setSurfaceSize(null));
|
|
final mealSlotController = FRadioSelectGroupController<String>(value: '1');
|
|
addTearDown(mealSlotController.dispose);
|
|
|
|
await tester.pumpWidget(
|
|
_testApp(
|
|
QueryMethodPanel(
|
|
methods: ReservationRecognitionMethod.values,
|
|
selected: ReservationRecognitionMethod.card,
|
|
status: ReservationMenuQueryStatus.idle,
|
|
mealSlotController: mealSlotController,
|
|
autoRecognitionEnabled: false,
|
|
continuousRecognitionEnabled: true,
|
|
quickVerificationEnabled: true,
|
|
allowManualMealPeriodChange: false,
|
|
onSelect: (_) {},
|
|
onStart: () {},
|
|
),
|
|
),
|
|
);
|
|
|
|
final trigger = find.byKey(
|
|
const ValueKey('reservation-meal-slot-trigger'),
|
|
);
|
|
expect(find.text('早餐'), findsOneWidget);
|
|
expect(tester.widget<FSelectMenuTile<String>>(trigger).enabled, isFalse);
|
|
|
|
await tester.tap(trigger);
|
|
await tester.pumpAndSettle();
|
|
expect(find.byKey(const ValueKey('meal-slot-option-2')), findsNothing);
|
|
expect(mealSlotController.value, {'1'});
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
}
|
|
|
|
/// 构建与终端设计基准一致的主题和尺寸环境,只验证本组件的可见状态与点击链路。
|
|
Widget _testApp(Widget child) {
|
|
return ScreenUtilInit(
|
|
designSize: const Size(1920, 1080),
|
|
builder: (_, __) => MaterialApp(
|
|
home: FTheme(
|
|
data: FThemes.zinc.light,
|
|
child: Scaffold(body: child),
|
|
),
|
|
),
|
|
);
|
|
}
|