import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; import 'package:jiu_client/screens/auth/login_screen.dart'; /// Wrap the screen in the minimum required providers. Widget _buildTestApp() { final router = GoRouter( initialLocation: '/login', routes: [ GoRoute( path: '/login', builder: (_, __) => const LoginScreen(), ), GoRoute( path: '/stock-in', builder: (_, __) => const Scaffold(body: Text('stock-in')), ), ], ); return ProviderScope( child: MaterialApp.router(routerConfig: router), ); } void main() { group('LoginScreen UI', () { testWidgets('renders all three input fields and login button', (tester) async { tester.view.physicalSize = const Size(1280, 800); tester.view.devicePixelRatio = 1.0; addTearDown(tester.view.resetPhysicalSize); await tester.pumpWidget(_buildTestApp()); await tester.pump(); expect(find.byType(TextFormField), findsNWidgets(3)); expect(find.text('门店编号'), findsOneWidget); expect(find.text('用户名'), findsOneWidget); expect(find.text('密码'), findsOneWidget); expect(find.text('登 录'), findsOneWidget); }); testWidgets('shows validation errors when submitting empty form', (tester) async { // Use a desktop-sized surface to avoid overflow tester.view.physicalSize = const Size(1280, 800); tester.view.devicePixelRatio = 1.0; addTearDown(tester.view.resetPhysicalSize); await tester.pumpWidget(_buildTestApp()); await tester.pump(); await tester.tap(find.text('登 录')); await tester.pump(); // Hint text and validator error share the same string, so both appear expect(find.text('请输入门店编号'), findsAtLeastNWidgets(1)); expect(find.text('请输入用户名'), findsAtLeastNWidgets(1)); expect(find.text('请输入密码'), findsAtLeastNWidgets(1)); }); testWidgets('password toggle changes obscure state', (tester) async { tester.view.physicalSize = const Size(1280, 800); tester.view.devicePixelRatio = 1.0; addTearDown(tester.view.resetPhysicalSize); await tester.pumpWidget(_buildTestApp()); await tester.pump(); // Initially password is obscured — visibility_off icon shown expect(find.byIcon(Icons.visibility_off), findsOneWidget); await tester.tap(find.byIcon(Icons.visibility_off)); await tester.pump(); // After tap — visibility icon shown expect(find.byIcon(Icons.visibility), findsOneWidget); }); testWidgets('button is present and tappable with filled form', (tester) async { tester.view.physicalSize = const Size(1280, 800); tester.view.devicePixelRatio = 1.0; addTearDown(tester.view.resetPhysicalSize); await tester.pumpWidget(_buildTestApp()); await tester.pump(); await tester.enterText( find.widgetWithText(TextFormField, '请输入门店编号'), 'H001'); await tester.enterText( find.widgetWithText(TextFormField, '请输入用户名'), 'admin'); await tester.enterText( find.widgetWithText(TextFormField, '请输入密码'), 'password123'); // Button exists and is enabled final btn = tester.widget(find.byType(ElevatedButton)); expect(btn.onPressed, isNotNull); }); }); }