Files
hidalyx-drluiscastro/test/features/appointments_modal_test.dart
2026-09-21 16:33:51 -04:00

273 lines
9.2 KiB
Dart

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<String, List<PatientSummaryModel>> appointmentsByDate;
MockDashboardService({Map<String, List<PatientSummaryModel>>? 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<List<PatientSummaryModel>> getAppointmentsByDate(DateTime date, {int limit = 100}) async {
final key = _formatKey(date);
return appointmentsByDate[key] ?? [];
}
@override
Future<List<PatientSummaryModel>> 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<PatientSummaryModel> 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<PatientSummaryModel> 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<Container>(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'));
});
});
}