first
This commit is contained in:
613
tests/patient/data-management.test.js
Normal file
613
tests/patient/data-management.test.js
Normal file
@@ -0,0 +1,613 @@
|
||||
/**
|
||||
* @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);
|
||||
});
|
||||
});
|
||||
});
|
495
tests/patient/portal-authentication.test.js
Normal file
495
tests/patient/portal-authentication.test.js
Normal file
@@ -0,0 +1,495 @@
|
||||
/**
|
||||
* @fileoverview Tests for patient portal and authentication MCP tools
|
||||
* Tests patient login, portal access, and patient-specific authentication
|
||||
*/
|
||||
|
||||
import { describe, test, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import { mockFactory } from '../mocks/mockFactory.js';
|
||||
|
||||
describe('Patient Portal and Authentication 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_create_patientlogin', () => {
|
||||
test('should successfully login patient', async () => {
|
||||
// Setup
|
||||
const toolName = 'patient_create_patientlogin';
|
||||
const parameters = {
|
||||
email: 'patient@test.com',
|
||||
password: 'patientpassword'
|
||||
};
|
||||
|
||||
// Mock successful patient login
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/patient/login', {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
token: 'patient_token_456',
|
||||
user: {
|
||||
id: 'patient_456',
|
||||
email: 'patient@test.com',
|
||||
role: 'patient',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
portalAccess: true
|
||||
},
|
||||
permissions: ['read:own_data', 'write:own_data'],
|
||||
message: 'Patient login successful'
|
||||
}
|
||||
});
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.user.role).toBe('patient');
|
||||
expect(result.data.user.portalAccess).toBe(true);
|
||||
expect(result.data.permissions).toContain('read:own_data');
|
||||
});
|
||||
|
||||
test('should handle invalid patient credentials', async () => {
|
||||
const toolName = 'patient_create_patientlogin';
|
||||
const parameters = {
|
||||
email: 'patient@test.com',
|
||||
password: 'wrongpassword'
|
||||
};
|
||||
|
||||
// Mock authentication failure
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/patient/login', null, true, {
|
||||
response: {
|
||||
status: 401,
|
||||
data: { error: 'Invalid patient credentials' }
|
||||
}
|
||||
});
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, parameters))
|
||||
.rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should handle disabled portal access', async () => {
|
||||
const toolName = 'patient_create_patientlogin';
|
||||
const parameters = {
|
||||
email: 'disabled@test.com',
|
||||
password: 'password'
|
||||
};
|
||||
|
||||
// Mock disabled portal access
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/patient/login', null, true, {
|
||||
response: {
|
||||
status: 403,
|
||||
data: { error: 'Portal access is disabled for this patient' }
|
||||
}
|
||||
});
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, parameters))
|
||||
.rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('patient_create_patientLoginApi', () => {
|
||||
test('should successfully login via API', async () => {
|
||||
// Setup
|
||||
const toolName = 'patient_create_patientLoginApi';
|
||||
const parameters = {
|
||||
email: 'patient@test.com',
|
||||
password: 'patientpassword'
|
||||
};
|
||||
|
||||
// Mock successful API login
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/patient-login-api', {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
token: 'patient_api_token_789',
|
||||
user: {
|
||||
id: 'patient_789',
|
||||
email: 'patient@test.com',
|
||||
role: 'patient'
|
||||
},
|
||||
apiAccess: true,
|
||||
tokenExpiry: new Date(Date.now() + 3600000).toISOString()
|
||||
}
|
||||
});
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.apiAccess).toBe(true);
|
||||
expect(result.data.tokenExpiry).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('patient_create_loginPatient', () => {
|
||||
test('should successfully login patient with alternative endpoint', async () => {
|
||||
// Setup
|
||||
const toolName = 'patient_create_loginPatient';
|
||||
const parameters = {
|
||||
email: 'patient@test.com',
|
||||
password: 'patientpassword'
|
||||
};
|
||||
|
||||
// Mock successful login
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/login-patient', {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
token: 'patient_login_token_101',
|
||||
patient: {
|
||||
id: 'patient_101',
|
||||
email: 'patient@test.com',
|
||||
firstName: 'Jane',
|
||||
lastName: 'Smith',
|
||||
dateOfBirth: '1985-03-15',
|
||||
portalEnabled: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.patient.portalEnabled).toBe(true);
|
||||
expect(result.data.patient.firstName).toBe('Jane');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Patient Authentication Security Tests', () => {
|
||||
test('should validate email format for patient login', async () => {
|
||||
const toolName = 'patient_create_patientlogin';
|
||||
const parameters = {
|
||||
email: 'invalid-email-format',
|
||||
password: 'password'
|
||||
};
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, parameters))
|
||||
.rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should handle account lockout after failed attempts', async () => {
|
||||
const toolName = 'patient_create_patientlogin';
|
||||
const parameters = {
|
||||
email: 'locked@test.com',
|
||||
password: 'password'
|
||||
};
|
||||
|
||||
// Mock account lockout
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/patient/login', null, true, {
|
||||
response: {
|
||||
status: 423,
|
||||
data: {
|
||||
error: 'Account temporarily locked due to multiple failed login attempts',
|
||||
lockoutExpiry: new Date(Date.now() + 900000).toISOString() // 15 minutes
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, parameters))
|
||||
.rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should enforce password complexity for patient accounts', async () => {
|
||||
const toolName = 'patient_create_patientlogin';
|
||||
const parameters = {
|
||||
email: 'patient@test.com',
|
||||
password: '123' // Weak password
|
||||
};
|
||||
|
||||
// Mock weak password rejection
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/patient/login', null, true, {
|
||||
response: {
|
||||
status: 400,
|
||||
data: { error: 'Password does not meet security requirements' }
|
||||
}
|
||||
});
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, parameters))
|
||||
.rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should audit patient login activities for HIPAA compliance', async () => {
|
||||
const toolName = 'patient_create_patientlogin';
|
||||
const parameters = {
|
||||
email: 'patient@test.com',
|
||||
password: 'validpassword'
|
||||
};
|
||||
|
||||
// Mock login with audit trail
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/patient/login', {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
token: 'patient_token_audit',
|
||||
user: {
|
||||
id: 'patient_audit',
|
||||
email: 'patient@test.com',
|
||||
role: 'patient'
|
||||
},
|
||||
auditTrail: {
|
||||
loginTime: new Date().toISOString(),
|
||||
ipAddress: '127.0.0.1',
|
||||
userAgent: 'Jest Test Suite',
|
||||
sessionId: 'session_123',
|
||||
hipaaCompliant: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
expect(result.data.auditTrail).toBeDefined();
|
||||
expect(result.data.auditTrail.hipaaCompliant).toBe(true);
|
||||
expect(result.data.auditTrail.sessionId).toBeDefined();
|
||||
});
|
||||
|
||||
test('should handle concurrent login sessions', async () => {
|
||||
const toolName = 'patient_create_patientlogin';
|
||||
const parameters = {
|
||||
email: 'patient@test.com',
|
||||
password: 'password'
|
||||
};
|
||||
|
||||
// Mock concurrent session handling
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/patient/login', {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
token: 'new_session_token',
|
||||
user: {
|
||||
id: 'patient_concurrent',
|
||||
email: 'patient@test.com',
|
||||
role: 'patient'
|
||||
},
|
||||
sessionInfo: {
|
||||
currentSessions: 2,
|
||||
maxAllowedSessions: 3,
|
||||
previousSessionTerminated: false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
expect(result.data.sessionInfo.currentSessions).toBe(2);
|
||||
expect(result.data.sessionInfo.maxAllowedSessions).toBe(3);
|
||||
});
|
||||
|
||||
test('should validate patient portal access permissions', async () => {
|
||||
const toolName = 'patient_create_patientlogin';
|
||||
const parameters = {
|
||||
email: 'restricted@test.com',
|
||||
password: 'password'
|
||||
};
|
||||
|
||||
// Mock restricted portal access
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/patient/login', {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
token: 'restricted_token',
|
||||
user: {
|
||||
id: 'patient_restricted',
|
||||
email: 'restricted@test.com',
|
||||
role: 'patient',
|
||||
portalAccess: false
|
||||
},
|
||||
restrictions: {
|
||||
reason: 'Account under review',
|
||||
contactSupport: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
expect(result.data.user.portalAccess).toBe(false);
|
||||
expect(result.data.restrictions.reason).toBe('Account under review');
|
||||
});
|
||||
|
||||
test('should handle two-factor authentication for patient accounts', async () => {
|
||||
const toolName = 'patient_create_patientlogin';
|
||||
const parameters = {
|
||||
email: 'patient2fa@test.com',
|
||||
password: 'password',
|
||||
twoFactorCode: '123456'
|
||||
};
|
||||
|
||||
// Mock 2FA verification
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/patient/login', {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
token: 'patient_2fa_token',
|
||||
user: {
|
||||
id: 'patient_2fa',
|
||||
email: 'patient2fa@test.com',
|
||||
role: 'patient',
|
||||
twoFactorEnabled: true
|
||||
},
|
||||
twoFactorVerified: true
|
||||
}
|
||||
});
|
||||
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
expect(result.data.user.twoFactorEnabled).toBe(true);
|
||||
expect(result.data.twoFactorVerified).toBe(true);
|
||||
});
|
||||
|
||||
test('should handle expired patient accounts', async () => {
|
||||
const toolName = 'patient_create_patientlogin';
|
||||
const parameters = {
|
||||
email: 'expired@test.com',
|
||||
password: 'password'
|
||||
};
|
||||
|
||||
// Mock expired account
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/patient/login', null, true, {
|
||||
response: {
|
||||
status: 403,
|
||||
data: {
|
||||
error: 'Patient account has expired',
|
||||
expirationDate: '2024-12-31',
|
||||
renewalRequired: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, parameters))
|
||||
.rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should validate patient data access scope', async () => {
|
||||
const toolName = 'patient_create_patientlogin';
|
||||
const parameters = {
|
||||
email: 'patient@test.com',
|
||||
password: 'password'
|
||||
};
|
||||
|
||||
// Mock login with data access scope
|
||||
const mockPatient = mockFactory.healthcareMocks.createHIPAACompliantData('patient', 'patient');
|
||||
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/patient/login', {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
token: 'patient_scope_token',
|
||||
user: mockPatient,
|
||||
dataAccessScope: {
|
||||
ownDataOnly: true,
|
||||
medicalRecords: true,
|
||||
prescriptions: true,
|
||||
appointments: true,
|
||||
billing: false // Limited billing access
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
expect(result.data.dataAccessScope.ownDataOnly).toBe(true);
|
||||
expect(result.data.dataAccessScope.medicalRecords).toBe(true);
|
||||
expect(result.data.dataAccessScope.billing).toBe(false);
|
||||
});
|
||||
|
||||
test('should handle patient consent verification', async () => {
|
||||
const toolName = 'patient_create_patientlogin';
|
||||
const parameters = {
|
||||
email: 'patient@test.com',
|
||||
password: 'password'
|
||||
};
|
||||
|
||||
// Mock login with consent verification
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/patient/login', {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
token: 'patient_consent_token',
|
||||
user: {
|
||||
id: 'patient_consent',
|
||||
email: 'patient@test.com',
|
||||
role: 'patient'
|
||||
},
|
||||
consentStatus: {
|
||||
hipaaConsent: true,
|
||||
dataProcessingConsent: true,
|
||||
marketingConsent: false,
|
||||
lastUpdated: '2025-01-01'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
expect(result.data.consentStatus.hipaaConsent).toBe(true);
|
||||
expect(result.data.consentStatus.dataProcessingConsent).toBe(true);
|
||||
expect(result.data.consentStatus.marketingConsent).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Patient Portal Feature Access Tests', () => {
|
||||
test('should validate patient portal feature availability', async () => {
|
||||
const toolName = 'patient_create_patientlogin';
|
||||
const parameters = {
|
||||
email: 'patient@test.com',
|
||||
password: 'password'
|
||||
};
|
||||
|
||||
// Mock login with feature access
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/patient/login', {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
token: 'patient_features_token',
|
||||
user: {
|
||||
id: 'patient_features',
|
||||
email: 'patient@test.com',
|
||||
role: 'patient'
|
||||
},
|
||||
portalFeatures: {
|
||||
viewMedicalRecords: true,
|
||||
scheduleAppointments: true,
|
||||
viewPrescriptions: true,
|
||||
messaging: true,
|
||||
billing: false,
|
||||
labResults: true,
|
||||
telehealth: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
expect(result.data.portalFeatures.viewMedicalRecords).toBe(true);
|
||||
expect(result.data.portalFeatures.scheduleAppointments).toBe(true);
|
||||
expect(result.data.portalFeatures.billing).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user