Files
biz_xfj_cloud/test/common/terminal_device_status_widget_test.dart
T
2026-08-06 20:55:09 +08:00

228 lines
7.2 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:get/get.dart';
import 'package:pj_supermarket_cloud/common/index.dart';
/// 注册终端设备弹框在多档横屏尺寸和放大主题下的布局回归测试。
void main() {
setUp(AppDeviceStatusTool.resetForTest);
for (final viewportSize in const [
Size(800, 450),
Size(800, 600),
Size(1280, 720),
]) {
testWidgets(
'${viewportSize.width.toInt()}x${viewportSize.height.toInt()}大字号下设备弹框无布局溢出',
(tester) async {
tester.view.devicePixelRatio = 1;
tester.view.physicalSize = viewportSize;
addTearDown(tester.view.reset);
final adminSession = Get.put(TerminalAdminSessionControl());
Get.put(
TerminalDeviceStatusControl(
loadHiddenDevices: () async => <TerminalDeviceType>{},
saveHiddenDevices: (_) async {},
),
);
adminSession.unlock();
await tester.pumpWidget(_terminalDeviceStatusTestApp());
await tester.pump();
expect(
MediaQuery.sizeOf(tester.element(find.byType(Scaffold))),
viewportSize,
);
await tester.tap(
find.byKey(const ValueKey('terminal-device-status-group')),
);
await tester.pumpAndSettle();
expect(
find.byKey(const ValueKey('terminal-device-status-dialog')),
findsOneWidget,
);
expect(
find.byKey(const ValueKey('terminal-device-status-table')),
findsOneWidget,
);
for (final device in TerminalDeviceType.values) {
expect(
find.byKey(
ValueKey('terminal-device-status-visibility-${device.code}'),
),
findsOneWidget,
);
}
expect(
find.byKey(const ValueKey('terminal-device-status-row-打印机')),
findsOneWidget,
);
for (final deviceName in const ['打印机', '电子秤', '读卡器', '副屏', '摄像头']) {
expect(
find.byKey(ValueKey('terminal-device-status-row-$deviceName')),
findsOneWidget,
);
}
final printerBottom = tester
.getBottomLeft(
find.byKey(const ValueKey('terminal-device-status-row-打印机')),
)
.dy;
final scaleTop = tester
.getTopLeft(
find.byKey(const ValueKey('terminal-device-status-row-电子秤')),
)
.dy;
expect(
scaleTop - printerBottom,
inInclusiveRange(5, 9),
reason: '设备行之间应保留适中的 6-8dp 间距,既可分组又不恢复成松散大卡片',
);
final printerRow =
find.byKey(const ValueKey('terminal-device-status-row-打印机'));
final printerRowSize = tester.getSize(printerRow);
expect(
printerRowSize.height,
greaterThanOrEqualTo(68),
reason: '设备行需要提供足够的阅读高度,不能再次压缩成过薄表格',
);
final printerLabel = tester.widget<Text>(
find.descendant(of: printerRow, matching: find.text('打印机')).first,
);
expect(
printerLabel.style?.fontSize,
greaterThanOrEqualTo(16),
reason: '设备名称必须保持实体终端可连续识别的字号',
);
final printerStatusWidth = tester
.getSize(
find.byKey(
const ValueKey('terminal-device-status-label-打印机'),
),
)
.width;
expect(
printerStatusWidth,
lessThan(printerRowSize.width * 0.25),
reason: '运行状态应按图标和文案自然宽度展示,不能铺满整列形成色条',
);
final tableHeight = tester
.getSize(
find.byKey(const ValueKey('terminal-device-status-table')),
)
.height;
expect(
tableHeight,
greaterThanOrEqualTo(400),
reason: '设备表需要恢复可读行高和行距,不能集中挤在弹框顶部',
);
final layoutException = tester.takeException();
await tester.tap(
find.byKey(const ValueKey('terminal-device-status-close-icon')),
);
await tester.pumpAndSettle();
adminSession.lock();
await tester.pumpWidget(const SizedBox.shrink());
await tester.pump();
Get.reset();
expect(layoutException, isNull);
});
}
testWidgets('设备状态弹框开关只隐藏对应顶部设备并保存完整集合', (tester) async {
tester.view.devicePixelRatio = 1;
tester.view.physicalSize = const Size(1280, 720);
addTearDown(tester.view.reset);
final adminSession = Get.put(TerminalAdminSessionControl());
final saved = <Set<TerminalDeviceType>>[];
final visibilityControl = Get.put(
TerminalDeviceStatusControl(
loadHiddenDevices: () async => <TerminalDeviceType>{},
saveHiddenDevices: (hiddenDevices) async =>
saved.add(Set<TerminalDeviceType>.from(hiddenDevices)),
),
);
adminSession.unlock();
await tester.pumpWidget(_terminalDeviceStatusTestApp());
await tester.tap(
find.byKey(const ValueKey('terminal-device-status-group')),
);
await tester.pumpAndSettle();
await tester.tap(
find.byKey(
const ValueKey('terminal-device-status-visibility-printer'),
),
);
await tester.pump();
expect(
visibilityControl.isHeaderDeviceVisible(TerminalDeviceType.printer),
isFalse,
);
expect(
visibilityControl.isHeaderDeviceVisible(TerminalDeviceType.camera),
isTrue,
);
expect(saved, [
<TerminalDeviceType>{TerminalDeviceType.printer}
]);
expect(
find.byKey(const ValueKey('terminal-status-打印机-missing')),
findsNothing,
);
expect(
find.byKey(const ValueKey('terminal-status-摄像头-missing')),
findsOneWidget,
);
expect(
find.byKey(const ValueKey('terminal-device-status-row-打印机')),
findsOneWidget,
reason: '隐藏顶部图标后详情行仍需保留,用户才能在弹框内重新开启',
);
expect(
tester
.widget<FSwitch>(
find.byKey(
const ValueKey('terminal-device-status-visibility-printer'),
),
)
.value,
isFalse,
);
adminSession.lock();
await tester.pumpWidget(const SizedBox.shrink());
await tester.pump();
Get.reset();
});
}
/// 构建与真机问题一致的横屏、大字号主题环境,用于捕获弹框运行时布局溢出。
Widget _terminalDeviceStatusTestApp() {
final baseTheme = FThemes.zinc.light;
final terminalTheme = FThemeData.inherit(
colorScheme: baseTheme.colorScheme,
typography: baseTheme.typography.scale(sizeScalar: 1.4),
style: baseTheme.style,
);
return ScreenUtilInit(
designSize: const Size(1920, 1080),
minTextAdapt: true,
splitScreenMode: true,
builder: (_, __) => MaterialApp(
builder: (_, child) => FTheme(data: terminalTheme, child: child!),
home: const Scaffold(
body: Align(
alignment: Alignment.topRight,
child: TerminalDeviceStatus(),
),
),
),
);
}