import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:hidalyx_drluiscastro/core/widgets/medical_modal.dart'; import 'package:hidalyx_drluiscastro/features/dashboard/data/models/patient_summary_model.dart'; import 'package:hidalyx_drluiscastro/features/dashboard/data/services/dashboard_service.dart'; import 'package:hidalyx_drluiscastro/features/dashboard/presentation/views/appointments_modal_view.dart'; import 'package:hidalyx_drluiscastro/features/dashboard/presentation/widgets/today_appointments_card.dart'; class MockDashboardService extends DashboardService { final Map> appointmentsByDate; MockDashboardService({Map>? data}) : appointmentsByDate = data ?? {}; String _formatKey(DateTime d) { final day = d.day.toString().padLeft(2, '0'); final month = d.month.toString().padLeft(2, '0'); final year = d.year.toString(); return '$day/$month/$year'; } @override Future> getAppointmentsByDate(DateTime date, {int limit = 100}) async { final key = _formatKey(date); return appointmentsByDate[key] ?? []; } @override Future> getTodayAppointments({int limit = 5}) async { return getAppointmentsByDate(DateTime.now(), limit: limit); } } void main() { group('AppointmentsModalView Tests', () { final now = DateTime.now(); final todayDay = now.day.toString().padLeft(2, '0'); final todayMonth = now.month.toString().padLeft(2, '0'); final todayKey = '$todayDay/$todayMonth/${now.year}'; final List mockTodayPatients = [ const PatientSummaryModel( id: 101, nombre: 'CARLOS', apellido: 'MARTINEZ', cedula: '001-9999999-1', telefono: '809-555-1122', fecReg: '20/09/2026', fecProxCita: '20/09/2026', seguro: 'Sí', motCons: 'Seguimiento postquirúrgico', ), const PatientSummaryModel( id: 102, nombre: 'ANA', apellido: 'PERDOMO', cedula: '402-8888888-2', telefono: '809-555-3344', fecReg: '20/09/2026', fecProxCita: '20/09/2026', seguro: 'No', motCons: 'Chequeo urológico anual', ), ]; final otherDate = DateTime(2026, 10, 25); const otherDateKey = '25/10/2026'; final List mockOtherPatients = [ const PatientSummaryModel( id: 201, nombre: 'RAMON', apellido: 'VALDEZ', cedula: '001-7777777-3', telefono: '809-555-5566', fecReg: '25/10/2026', fecProxCita: '25/10/2026', seguro: 'Sí', motCons: 'Control de litiasis renal', ), ]; late MockDashboardService mockService; setUp(() { mockService = MockDashboardService(data: { todayKey: mockTodayPatients, otherDateKey: mockOtherPatients, }); }); testWidgets('renders modal header, footer, and active filter indicator as "Hoy"', (tester) async { tester.view.physicalSize = const Size(1280, 900); tester.view.devicePixelRatio = 1.0; addTearDown(() => tester.view.resetPhysicalSize()); await tester.pumpWidget( MaterialApp( home: Scaffold( body: AppointmentsModalView( service: mockService, initialDate: now, ), ), ), ); await tester.pumpAndSettle(); // Check titles & subtitles expect(find.text('Agenda de Citas Médicas'), findsOneWidget); expect(find.text('Consulte y gestione los pacientes citados por fecha de consulta'), findsOneWidget); // Verify that when filtered by today, it displays "Hoy (DD/MM/YYYY)" expect(find.textContaining('Hoy ($todayKey)'), findsOneWidget); // Verify patient records for today are rendered expect(find.text('CARLOS MARTINEZ'), findsOneWidget); expect(find.text('ANA PERDOMO'), findsOneWidget); expect(find.text('Seguimiento postquirúrgico'), findsOneWidget); expect(find.text('Chequeo urológico anual'), findsOneWidget); // Verify footer buttons & chip expect(find.text('ESC para salir'), findsOneWidget); expect(find.text('Cerrar'), findsOneWidget); }); testWidgets('displays specific date filter when viewing date other than today', (tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( body: AppointmentsModalView( service: mockService, initialDate: otherDate, ), ), ), ); await tester.pumpAndSettle(); // Should show the specific date without "Hoy" in the filter badge expect(find.textContaining('Filtro: 25/10/2026'), findsOneWidget); expect(find.textContaining('Hoy'), findsWidgets); // The "Hoy" quick button is present, but the filter text is 25/10/2026 // Verify patient for that specific date expect(find.text('RAMON VALDEZ'), findsOneWidget); expect(find.text('Control de litiasis renal'), findsOneWidget); expect(find.text('CARLOS MARTINEZ'), findsNothing); }); testWidgets('navigation buttons change date and "Hoy" button resets to current day', (tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( body: AppointmentsModalView( service: mockService, initialDate: otherDate, ), ), ), ); await tester.pumpAndSettle(); expect(find.textContaining('Filtro: 25/10/2026'), findsOneWidget); // Tap Día siguiente chevron await tester.tap(find.byTooltip('Día siguiente')); await tester.pumpAndSettle(); expect(find.textContaining('Filtro: 26/10/2026'), findsOneWidget); expect(find.text('No hay citas registradas para el 26/10/2026'), findsOneWidget); // Tap Día anterior chevron twice await tester.tap(find.byTooltip('Día anterior')); await tester.pumpAndSettle(); expect(find.textContaining('Filtro: 25/10/2026'), findsOneWidget); // Tap "Hoy" button to return to today await tester.tap(find.text('Hoy')); await tester.pumpAndSettle(); // Must now show "Hoy (DD/MM/YYYY)" again expect(find.textContaining('Filtro: Hoy ($todayKey)'), findsOneWidget); expect(find.text('CARLOS MARTINEZ'), findsOneWidget); }); testWidgets('footer container adheres to institutional padding (horizontal: 20, vertical: 12)', (tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( body: AppointmentsModalView( service: mockService, initialDate: now, ), ), ), ); await tester.pumpAndSettle(); final footerFinder = find.ancestor( of: find.text('Cerrar'), matching: find.byType(Container), ); expect(footerFinder, findsWidgets); final footerContainer = tester.widget(footerFinder.first); expect(footerContainer.padding, equals(const EdgeInsets.symmetric(horizontal: 20, vertical: 12))); }); testWidgets('closes modal with Cerrar button and with ESC key', (tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( body: Builder( builder: (ctx) => ElevatedButton( onPressed: () => showMedicalModal( context: ctx, builder: (_) => AppointmentsModalView( service: mockService, initialDate: now, ), ), child: const Text('Abrir Citas'), ), ), ), ), ); // 1. Open modal and close via Cerrar button await tester.tap(find.text('Abrir Citas')); await tester.pumpAndSettle(); expect(find.text('Agenda de Citas Médicas'), findsOneWidget); await tester.tap(find.text('Cerrar')); await tester.pumpAndSettle(); expect(find.text('Agenda de Citas Médicas'), findsNothing); // 2. Open modal and close via ESC key await tester.tap(find.text('Abrir Citas')); await tester.pumpAndSettle(); expect(find.text('Agenda de Citas Médicas'), findsOneWidget); await tester.sendKeyEvent(LogicalKeyboardKey.escape); await tester.pumpAndSettle(); expect(find.text('Agenda de Citas Médicas'), findsNothing); }); testWidgets('TodayAppointmentsCard item tap invokes onPatientTap callback', (tester) async { PatientSummaryModel? tappedPatient; await tester.pumpWidget( MaterialApp( home: Scaffold( body: TodayAppointmentsCard( appointments: mockTodayPatients, onPatientTap: (p) => tappedPatient = p, ), ), ), ); await tester.pumpAndSettle(); expect(find.text('CARLOS MARTINEZ'), findsOneWidget); await tester.tap(find.text('CARLOS MARTINEZ')); await tester.pumpAndSettle(); expect(tappedPatient, isNotNull); expect(tappedPatient!.id, equals(101)); expect(tappedPatient!.nombre, equals('CARLOS')); }); }); }