Files
mcp-tool/tests/patient/data-management.test.js
nasir@endelospay.com 8c74b0e23f first
2025-07-11 20:22:12 +05:00

614 lines
19 KiB
JavaScript

/**
* @fileoverview Tests for patient data management and portal operations MCP tools
* Tests patient profile updates, medical record access, and portal-specific operations
*/
import { describe, test, expect, beforeEach, afterEach } from '@jest/globals';
import { mockFactory } from '../mocks/mockFactory.js';
describe('Patient Data Management and Portal Operations Tools', () => {
let mockEnv;
let toolGenerator;
let mockToken;
beforeEach(() => {
mockEnv = mockFactory.createMockEnvironment({
authTypes: ['patient'],
enableHttpMocks: true,
enableAuthMocks: true,
enableHealthcareMocks: true
});
toolGenerator = mockEnv.toolGenerator;
// Setup patient authentication
mockToken = 'patient_token_123';
mockFactory.authMocks.setMockCredentials('patient', {
username: 'test_patient',
password: 'test_password'
});
});
afterEach(() => {
mockFactory.resetAllMocks();
});
describe('patient_get_patientProfile', () => {
test('should successfully retrieve patient profile', async () => {
// Setup
const toolName = 'patient_get_patientProfile';
const parameters = {
patient_id: 'patient_123'
};
// Mock patient profile response
const mockPatient = mockFactory.healthcareMocks.createHIPAACompliantData('patient', 'patient', {
id: 'patient_123',
firstName: 'John',
lastName: 'Doe',
email: 'john.doe@test.com',
dateOfBirth: '1990-01-01',
phone: '555-0123',
address: '123 Main St',
city: 'Test City',
state: 'TS',
zipcode: '12345'
});
mockFactory.httpMocks.mockRequest('GET', '/api/patient/profile/patient_123', {
status: 200,
data: {
success: true,
patient: mockPatient,
lastUpdated: new Date().toISOString()
}
});
// Execute
const result = await toolGenerator.executeTool(toolName, parameters);
// Assert
expect(result.success).toBe(true);
expect(result.data.patient.id).toBe('patient_123');
expect(result.data.patient.firstName).toBe('John');
expect(result.data.patient.hipaaMetadata).toBeDefined();
});
test('should handle unauthorized access to other patient profiles', async () => {
const toolName = 'patient_get_patientProfile';
const parameters = {
patient_id: 'other_patient_456' // Different patient
};
// Mock unauthorized access
mockFactory.httpMocks.mockRequest('GET', '/api/patient/profile/other_patient_456', null, true, {
response: {
status: 403,
data: { error: 'Unauthorized access to patient profile' }
}
});
await expect(toolGenerator.executeTool(toolName, parameters))
.rejects.toThrow();
});
});
describe('patient_put_updatePatientProfile', () => {
test('should successfully update patient profile', async () => {
// Setup
const toolName = 'patient_put_updatePatientProfile';
const parameters = {
patient_id: 'patient_123',
firstName: 'John',
lastName: 'Smith', // Changed last name
email: 'john.smith@test.com',
phone: '555-0124',
address: '456 New St',
city: 'New City',
state: 'NC',
zipcode: '54321',
emergencyContact: {
name: 'Jane Smith',
relationship: 'Spouse',
phone: '555-0125'
}
};
// Mock successful profile update
mockFactory.httpMocks.mockRequest('PUT', '/api/patient/profile/patient_123', {
status: 200,
data: {
success: true,
patient: {
id: 'patient_123',
firstName: 'John',
lastName: 'Smith',
email: 'john.smith@test.com',
phone: '555-0124',
address: '456 New St',
updatedAt: new Date().toISOString()
},
message: 'Patient profile updated successfully'
}
});
// Execute
const result = await toolGenerator.executeTool(toolName, parameters);
// Assert
expect(result.success).toBe(true);
expect(result.data.patient.lastName).toBe('Smith');
expect(result.data.patient.email).toBe('john.smith@test.com');
});
test('should validate patient profile update data', async () => {
const toolName = 'patient_put_updatePatientProfile';
// Test invalid email format
const invalidEmailParams = {
patient_id: 'patient_123',
email: 'invalid-email-format'
};
await expect(toolGenerator.executeTool(toolName, invalidEmailParams))
.rejects.toThrow();
// Test invalid phone format
const invalidPhoneParams = {
patient_id: 'patient_123',
phone: 'invalid-phone'
};
await expect(toolGenerator.executeTool(toolName, invalidPhoneParams))
.rejects.toThrow();
});
test('should handle concurrent profile updates', async () => {
const toolName = 'patient_put_updatePatientProfile';
const parameters = {
patient_id: 'patient_123',
firstName: 'John',
lastName: 'Updated'
};
// Mock concurrent update conflict
mockFactory.httpMocks.mockRequest('PUT', '/api/patient/profile/patient_123', null, true, {
response: {
status: 409,
data: {
error: 'Profile was updated by another session',
lastModified: new Date().toISOString()
}
}
});
await expect(toolGenerator.executeTool(toolName, parameters))
.rejects.toThrow();
});
});
describe('patient_get_medicalRecords', () => {
test('should successfully retrieve patient medical records', async () => {
// Setup
const toolName = 'patient_get_medicalRecords';
const parameters = {
patient_id: 'patient_123',
limit: 10,
offset: 0
};
// Mock medical records response
const mockRecords = [
mockFactory.healthcareMocks.generateMockMedicalRecord({
patientId: 'patient_123',
type: 'progress_note',
date: '2025-07-01'
}),
mockFactory.healthcareMocks.generateMockMedicalRecord({
patientId: 'patient_123',
type: 'lab_result',
date: '2025-06-15'
})
];
mockFactory.httpMocks.mockRequest('GET', '/api/patient/medical-records/patient_123', {
status: 200,
data: {
success: true,
medical_records: mockRecords,
total_count: 2,
page: 1,
per_page: 10
}
});
// Execute
const result = await toolGenerator.executeTool(toolName, parameters);
// Assert
expect(result.success).toBe(true);
expect(result.data.medical_records).toHaveLength(2);
expect(result.data.medical_records[0].patientId).toBe('patient_123');
expect(result.data.total_count).toBe(2);
});
test('should filter medical records by date range', async () => {
const toolName = 'patient_get_medicalRecords';
const parameters = {
patient_id: 'patient_123',
start_date: '2025-06-01',
end_date: '2025-06-30'
};
// Mock filtered records
mockFactory.httpMocks.mockRequest('GET', '/api/patient/medical-records/patient_123', {
status: 200,
data: {
success: true,
medical_records: [
mockFactory.healthcareMocks.generateMockMedicalRecord({
patientId: 'patient_123',
date: '2025-06-15'
})
],
filters_applied: {
start_date: '2025-06-01',
end_date: '2025-06-30'
}
}
});
const result = await toolGenerator.executeTool(toolName, parameters);
expect(result.data.filters_applied.start_date).toBe('2025-06-01');
expect(result.data.filters_applied.end_date).toBe('2025-06-30');
});
});
describe('patient_get_prescriptions', () => {
test('should successfully retrieve patient prescriptions', async () => {
// Setup
const toolName = 'patient_get_prescriptions';
const parameters = {
patient_id: 'patient_123'
};
// Mock prescriptions response
const mockPrescriptions = [
mockFactory.healthcareMocks.generateMockPrescription({
patientId: 'patient_123',
medication: { name: 'Lisinopril', strength: '10mg' },
status: 'active'
}),
mockFactory.healthcareMocks.generateMockPrescription({
patientId: 'patient_123',
medication: { name: 'Metformin', strength: '500mg' },
status: 'active'
})
];
mockFactory.httpMocks.mockRequest('GET', '/api/patient/prescriptions/patient_123', {
status: 200,
data: {
success: true,
prescriptions: mockPrescriptions,
active_count: 2,
total_count: 2
}
});
// Execute
const result = await toolGenerator.executeTool(toolName, parameters);
// Assert
expect(result.success).toBe(true);
expect(result.data.prescriptions).toHaveLength(2);
expect(result.data.active_count).toBe(2);
expect(result.data.prescriptions[0].medication.name).toBe('Lisinopril');
});
test('should filter prescriptions by status', async () => {
const toolName = 'patient_get_prescriptions';
const parameters = {
patient_id: 'patient_123',
status: 'active'
};
// Mock filtered prescriptions
mockFactory.httpMocks.mockRequest('GET', '/api/patient/prescriptions/patient_123', {
status: 200,
data: {
success: true,
prescriptions: [
mockFactory.healthcareMocks.generateMockPrescription({
status: 'active'
})
],
filter: { status: 'active' }
}
});
const result = await toolGenerator.executeTool(toolName, parameters);
expect(result.data.filter.status).toBe('active');
});
});
describe('patient_get_appointments', () => {
test('should successfully retrieve patient appointments', async () => {
// Setup
const toolName = 'patient_get_appointments';
const parameters = {
patient_id: 'patient_123'
};
// Mock appointments response
const mockAppointments = [
mockFactory.healthcareMocks.generateMockAppointment({
patientId: 'patient_123',
date: '2025-07-15',
time: '10:00',
status: 'scheduled'
}),
mockFactory.healthcareMocks.generateMockAppointment({
patientId: 'patient_123',
date: '2025-07-20',
time: '14:00',
status: 'scheduled'
})
];
mockFactory.httpMocks.mockRequest('GET', '/api/patient/appointments/patient_123', {
status: 200,
data: {
success: true,
appointments: mockAppointments,
upcoming_count: 2,
total_count: 2
}
});
// Execute
const result = await toolGenerator.executeTool(toolName, parameters);
// Assert
expect(result.success).toBe(true);
expect(result.data.appointments).toHaveLength(2);
expect(result.data.upcoming_count).toBe(2);
expect(result.data.appointments[0].status).toBe('scheduled');
});
});
describe('patient_post_scheduleAppointment', () => {
test('should successfully schedule new appointment', async () => {
// Setup
const toolName = 'patient_post_scheduleAppointment';
const parameters = {
patient_id: 'patient_123',
provider_id: 'provider_456',
appointment_date: '2025-07-25',
appointment_time: '11:00',
reason: 'Follow-up consultation',
notes: 'Patient requested follow-up'
};
// Mock successful appointment scheduling
const mockAppointment = mockFactory.healthcareMocks.generateMockAppointment({
patientId: 'patient_123',
providerId: 'provider_456',
date: '2025-07-25',
time: '11:00',
reason: 'Follow-up consultation'
});
mockFactory.httpMocks.mockRequest('POST', '/api/patient/schedule-appointment', {
status: 201,
data: {
success: true,
appointment: mockAppointment,
confirmation_number: 'CONF123456',
message: 'Appointment scheduled successfully'
}
});
// Execute
const result = await toolGenerator.executeTool(toolName, parameters);
// Assert
expect(result.success).toBe(true);
expect(result.data.appointment.patientId).toBe('patient_123');
expect(result.data.confirmation_number).toBe('CONF123456');
});
test('should handle scheduling conflicts', async () => {
const toolName = 'patient_post_scheduleAppointment';
const parameters = {
patient_id: 'patient_123',
provider_id: 'provider_456',
appointment_date: '2025-07-25',
appointment_time: '11:00'
};
// Mock scheduling conflict
mockFactory.httpMocks.mockRequest('POST', '/api/patient/schedule-appointment', null, true, {
response: {
status: 409,
data: {
error: 'Time slot is no longer available',
alternative_slots: [
{ date: '2025-07-25', time: '12:00' },
{ date: '2025-07-26', time: '11:00' }
]
}
}
});
await expect(toolGenerator.executeTool(toolName, parameters))
.rejects.toThrow();
});
});
describe('patient_put_cancelAppointment', () => {
test('should successfully cancel appointment', async () => {
// Setup
const toolName = 'patient_put_cancelAppointment';
const parameters = {
appointment_id: 'appointment_123',
cancellation_reason: 'Schedule conflict'
};
// Mock successful cancellation
mockFactory.httpMocks.mockRequest('PUT', '/api/patient/cancel-appointment/appointment_123', {
status: 200,
data: {
success: true,
appointment: {
id: 'appointment_123',
status: 'cancelled',
cancellation_reason: 'Schedule conflict',
cancelled_at: new Date().toISOString(),
cancelled_by: 'patient_123'
},
message: 'Appointment cancelled successfully'
}
});
// Execute
const result = await toolGenerator.executeTool(toolName, parameters);
// Assert
expect(result.success).toBe(true);
expect(result.data.appointment.status).toBe('cancelled');
expect(result.data.appointment.cancellation_reason).toBe('Schedule conflict');
});
test('should handle cancellation policy violations', async () => {
const toolName = 'patient_put_cancelAppointment';
const parameters = {
appointment_id: 'appointment_123'
};
// Mock cancellation policy violation
mockFactory.httpMocks.mockRequest('PUT', '/api/patient/cancel-appointment/appointment_123', null, true, {
response: {
status: 400,
data: {
error: 'Cancellation not allowed within 24 hours of appointment',
policy: {
minimum_notice_hours: 24,
appointment_time: '2025-07-10 10:00:00'
}
}
}
});
await expect(toolGenerator.executeTool(toolName, parameters))
.rejects.toThrow();
});
});
describe('Patient Data Security and Privacy Tests', () => {
test('should enforce patient data access restrictions', async () => {
const toolName = 'patient_get_medicalRecords';
const parameters = {
patient_id: 'other_patient_456' // Trying to access another patient's records
};
// Mock unauthorized access
mockFactory.httpMocks.mockRequest('GET', '/api/patient/medical-records/other_patient_456', null, true, {
response: {
status: 403,
data: { error: 'Access denied: Can only view own medical records' }
}
});
await expect(toolGenerator.executeTool(toolName, parameters))
.rejects.toThrow();
});
test('should audit patient data access for HIPAA compliance', async () => {
const toolName = 'patient_get_medicalRecords';
const parameters = {
patient_id: 'patient_123'
};
// Mock response with audit trail
mockFactory.httpMocks.mockRequest('GET', '/api/patient/medical-records/patient_123', {
status: 200,
data: {
success: true,
medical_records: [mockFactory.healthcareMocks.generateMockMedicalRecord()],
auditTrail: {
accessedBy: 'patient_123',
accessTime: new Date().toISOString(),
accessType: 'patient_portal',
ipAddress: '127.0.0.1',
sessionId: 'session_123'
}
}
});
const result = await toolGenerator.executeTool(toolName, parameters);
expect(result.data.auditTrail).toBeDefined();
expect(result.data.auditTrail.accessType).toBe('patient_portal');
expect(result.data.auditTrail.accessedBy).toBe('patient_123');
});
test('should validate patient consent for data access', async () => {
const toolName = 'patient_get_prescriptions';
const parameters = {
patient_id: 'patient_123'
};
// Mock consent verification
mockFactory.httpMocks.mockRequest('GET', '/api/patient/prescriptions/patient_123', {
status: 200,
data: {
success: true,
prescriptions: [mockFactory.healthcareMocks.generateMockPrescription()],
consentVerified: true,
consentDetails: {
dataAccessConsent: true,
lastConsentUpdate: '2025-01-01',
consentVersion: '2.0'
}
}
});
const result = await toolGenerator.executeTool(toolName, parameters);
expect(result.data.consentVerified).toBe(true);
expect(result.data.consentDetails.dataAccessConsent).toBe(true);
});
test('should handle data retention policies', async () => {
const toolName = 'patient_get_medicalRecords';
const parameters = {
patient_id: 'patient_123',
include_archived: false
};
// Mock data retention filtering
mockFactory.httpMocks.mockRequest('GET', '/api/patient/medical-records/patient_123', {
status: 200,
data: {
success: true,
medical_records: [mockFactory.healthcareMocks.generateMockMedicalRecord()],
retention_info: {
active_records: 5,
archived_records: 2,
retention_period_years: 7,
next_archive_date: '2026-01-01'
}
}
});
const result = await toolGenerator.executeTool(toolName, parameters);
expect(result.data.retention_info.retention_period_years).toBe(7);
expect(result.data.retention_info.active_records).toBe(5);
});
});
});