269 lines
8.3 KiB
Dart
269 lines
8.3 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter/rendering.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:forui/forui.dart';
|
|
|
|
import 'package:pj_supermarket_cloud/common/models/page/reservation_menu_page_models.dart';
|
|
import 'package:pj_supermarket_cloud/common/widgets/app/reservation_schedule_card.dart';
|
|
import 'package:pj_supermarket_cloud/sub_screen/common/models/reservation_query_display_models.dart';
|
|
import 'package:pj_supermarket_cloud/sub_screen/common/utils/reservation_query_coordinator.dart';
|
|
import 'package:pj_supermarket_cloud/sub_screen/page/reservation_query_display.dart';
|
|
|
|
void main() {
|
|
testWidgets('午餐预约卡只补齐基础三餐,不生成夜间餐占位', (tester) async {
|
|
ReservationMenuMealData? verifiedMeal;
|
|
const day = ReservationMenuDayData(
|
|
date: '2026-07-24',
|
|
meals: [
|
|
ReservationMenuMealData(
|
|
hourType: 'NOONING',
|
|
title: '午餐',
|
|
items: ['香菇滑鸡'],
|
|
orderIds: [1001],
|
|
),
|
|
],
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: FTheme(
|
|
data: FThemes.zinc.light,
|
|
child: Center(
|
|
child: SizedBox(
|
|
width: 420,
|
|
height: 420,
|
|
child: ReservationScheduleCard(
|
|
day: day,
|
|
verificationEnabled: true,
|
|
onVerify: (meal) => verifiedMeal = meal,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
for (final title in const ['早餐', '午餐', '晚餐']) {
|
|
expect(find.text(title), findsOneWidget);
|
|
}
|
|
expect(find.text('夜间餐'), findsNothing);
|
|
expect(find.text('未预定'), findsNWidgets(2));
|
|
expect(find.text('核销'), findsOneWidget);
|
|
|
|
final verificationVisual = tester.getSize(
|
|
find.byKey(const ValueKey('reservation-verification-visual-2')),
|
|
);
|
|
final verificationTarget = tester.getSize(
|
|
find.byKey(const ValueKey('reservation-verification-target-2')),
|
|
);
|
|
expect(verificationVisual.height, 36);
|
|
expect(verificationTarget.height, 48);
|
|
expect(verificationTarget.width, greaterThan(verificationVisual.width));
|
|
|
|
await tester.tap(find.text('核销'));
|
|
expect(verifiedMeal?.title, '午餐');
|
|
});
|
|
|
|
testWidgets('后端返回夜间餐时正常追加展示', (tester) async {
|
|
const day = ReservationMenuDayData(
|
|
date: '2026-07-24',
|
|
meals: [
|
|
ReservationMenuMealData(
|
|
hourType: 'LATE_NIGHT',
|
|
title: '夜间餐',
|
|
items: ['牛肉面'],
|
|
),
|
|
],
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: FTheme(
|
|
data: FThemes.zinc.light,
|
|
child: const Center(
|
|
child: SizedBox(
|
|
width: 420,
|
|
height: 420,
|
|
child: ReservationScheduleCard(day: day),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.text('夜间餐'), findsOneWidget);
|
|
expect(find.text('牛肉面'), findsOneWidget);
|
|
|
|
final lateNightText = tester.renderObject<RenderParagraph>(
|
|
find.byKey(const ValueKey('reservation-meal-title-4')),
|
|
);
|
|
expect(lateNightText.maxLines, 1);
|
|
expect(lateNightText.didExceedMaxLines, isFalse);
|
|
});
|
|
|
|
testWidgets('关闭核销配置时预约餐段仍显示查询详情入口', (tester) async {
|
|
ReservationMenuMealData? selectedMeal;
|
|
const day = ReservationMenuDayData(
|
|
date: '2026-07-24',
|
|
meals: [
|
|
ReservationMenuMealData(
|
|
hourType: '2',
|
|
title: '午餐',
|
|
items: ['小青菜'],
|
|
orderIds: [1001],
|
|
),
|
|
],
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: FTheme(
|
|
data: FThemes.zinc.light,
|
|
child: Center(
|
|
child: SizedBox(
|
|
width: 420,
|
|
height: 420,
|
|
child: ReservationScheduleCard(
|
|
day: day,
|
|
onVerify: (meal) => selectedMeal = meal,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.text('核销'), findsNothing);
|
|
expect(find.text('查询详情'), findsOneWidget);
|
|
await tester.tap(find.text('查询详情'));
|
|
expect(selectedMeal?.title, '午餐');
|
|
});
|
|
|
|
testWidgets('窄卡片中的查询详情保持紧凑且菜名不再逐字换行', (tester) async {
|
|
const day = ReservationMenuDayData(
|
|
date: '2026-07-24',
|
|
meals: [
|
|
ReservationMenuMealData(
|
|
hourType: '2',
|
|
title: '午餐',
|
|
items: ['小青菜'],
|
|
orderIds: [1001],
|
|
),
|
|
],
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: FTheme(
|
|
data: FThemes.zinc.light,
|
|
child: const Center(
|
|
child: SizedBox(
|
|
width: 220,
|
|
height: 420,
|
|
child: ReservationScheduleCard(
|
|
day: day,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(tester.takeException(), isNull);
|
|
final itemText = tester.renderObject<RenderParagraph>(
|
|
find.text('小青菜'),
|
|
);
|
|
final detailVisual = tester.getSize(
|
|
find.byKey(const ValueKey('reservation-verification-visual-2')),
|
|
);
|
|
expect(itemText.maxLines, 1);
|
|
expect(itemText.didExceedMaxLines, isFalse);
|
|
expect(itemText.size.height, lessThan(24));
|
|
expect(detailVisual.width, lessThanOrEqualTo(70));
|
|
expect(detailVisual.height, 30);
|
|
});
|
|
|
|
for (final size in [const Size(1920, 1080), const Size(1280, 720)]) {
|
|
testWidgets('${size.width.toInt()}x${size.height.toInt()} 七种预约状态无布局异常',
|
|
(tester) async {
|
|
tester.view.physicalSize = size;
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
|
|
for (final scenario in ReservationQueryDisplayScenario.values) {
|
|
final coordinator = ReservationQueryCoordinator(
|
|
initialState: ReservationQueryDisplayState.demo(
|
|
scenario,
|
|
now: DateTime(2026, 7, 24, 8),
|
|
),
|
|
);
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
debugShowCheckedModeBanner: false,
|
|
home: FTheme(
|
|
data: FThemes.zinc.light,
|
|
child: ReservationQueryDisplayPage(coordinator: coordinator),
|
|
),
|
|
),
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(
|
|
find.byKey(ValueKey('reservation-scenario-${scenario.name}')),
|
|
findsOneWidget,
|
|
);
|
|
expect(tester.takeException(), isNull);
|
|
if (scenario == ReservationQueryDisplayScenario.success) {
|
|
expect(find.byType(ReservationScheduleCard), findsNWidgets(10));
|
|
expect(find.text('张*明 · 三年级二班'), findsOneWidget);
|
|
expect(find.text('张小明'), findsNothing);
|
|
expect(find.byKey(const ValueKey('reservation-page-indicator')),
|
|
findsOneWidget);
|
|
}
|
|
|
|
await tester.pumpWidget(const SizedBox.shrink());
|
|
coordinator.dispose();
|
|
}
|
|
});
|
|
}
|
|
|
|
testWidgets('持续人脸副屏同时保留实时预览、预约菜单和十秒倒计时', (tester) async {
|
|
tester.view.physicalSize = const Size(1920, 1080);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
final state = ReservationQueryDisplayState.demo(
|
|
ReservationQueryDisplayScenario.success,
|
|
now: DateTime(2026, 8, 7, 10),
|
|
).copyWith(
|
|
remainingSeconds: 10,
|
|
continuousFaceRecognition: true,
|
|
);
|
|
final coordinator = ReservationQueryCoordinator(initialState: state);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
debugShowCheckedModeBanner: false,
|
|
home: FTheme(
|
|
data: FThemes.zinc.light,
|
|
child: ReservationQueryDisplayPage(coordinator: coordinator),
|
|
),
|
|
),
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(
|
|
find.byKey(const ValueKey('sub-reservation-live-face-preview')),
|
|
findsOneWidget,
|
|
);
|
|
expect(find.byType(ReservationScheduleCard), findsNWidgets(10));
|
|
expect(find.text('预约结果展示中'), findsOneWidget);
|
|
expect(find.textContaining('10 秒后识别下一位'), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
|
|
await tester.pumpWidget(const SizedBox.shrink());
|
|
coordinator.dispose();
|
|
});
|
|
}
|