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 => {}, 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( 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 = >[]; final visibilityControl = Get.put( TerminalDeviceStatusControl( loadHiddenDevices: () async => {}, saveHiddenDevices: (hiddenDevices) async => saved.add(Set.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.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( 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(), ), ), ), ); }