first
This commit is contained in:
580
tests/provider/appointment-scheduling.test.js
Normal file
580
tests/provider/appointment-scheduling.test.js
Normal file
@@ -0,0 +1,580 @@
|
||||
/**
|
||||
* @fileoverview Tests for provider appointment and scheduling management MCP tools
|
||||
* Tests appointment creation, scheduling, cancellation, and availability management
|
||||
*/
|
||||
|
||||
import { describe, test, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import { mockFactory } from '../mocks/mockFactory.js';
|
||||
|
||||
describe('Provider Appointment and Scheduling Management Tools', () => {
|
||||
let mockEnv;
|
||||
let toolGenerator;
|
||||
let mockToken;
|
||||
|
||||
beforeEach(() => {
|
||||
mockEnv = mockFactory.createMockEnvironment({
|
||||
authTypes: ['provider'],
|
||||
enableHttpMocks: true,
|
||||
enableAuthMocks: true,
|
||||
enableHealthcareMocks: true
|
||||
});
|
||||
|
||||
toolGenerator = mockEnv.toolGenerator;
|
||||
|
||||
// Setup provider authentication
|
||||
mockToken = 'provider_token_123';
|
||||
mockFactory.authMocks.setMockCredentials('provider', {
|
||||
username: 'test_provider',
|
||||
password: 'test_password'
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFactory.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('provider_create_emrcreateAppointment', () => {
|
||||
test('should successfully create appointment with complete scheduling data', async () => {
|
||||
// Setup
|
||||
const toolName = 'provider_create_emrcreateAppointment';
|
||||
const parameters = {
|
||||
patient_id: 'patient_123',
|
||||
practitioner_id: 'provider_456',
|
||||
appointment_date: '2025-07-15',
|
||||
appointment_time: '10:00',
|
||||
duration: 30,
|
||||
appointment_type: 'consultation',
|
||||
reason: 'Annual physical examination',
|
||||
notes: 'Patient reports feeling well',
|
||||
location_id: 'location_789',
|
||||
status: 'scheduled'
|
||||
};
|
||||
|
||||
// Mock successful appointment creation
|
||||
const mockAppointment = mockFactory.healthcareMocks.generateMockAppointment({
|
||||
patientId: 'patient_123',
|
||||
providerId: 'provider_456',
|
||||
date: '2025-07-15',
|
||||
time: '10:00',
|
||||
type: 'consultation',
|
||||
status: 'scheduled'
|
||||
});
|
||||
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/emr/create-appointment', {
|
||||
status: 201,
|
||||
data: {
|
||||
success: true,
|
||||
appointment: mockAppointment,
|
||||
message: 'Appointment created 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.appointment.providerId).toBe('provider_456');
|
||||
expect(result.data.appointment.date).toBe('2025-07-15');
|
||||
expect(result.data.appointment.time).toBe('10:00');
|
||||
expect(result.data.appointment.status).toBe('scheduled');
|
||||
});
|
||||
|
||||
test('should validate required appointment fields', async () => {
|
||||
const toolName = 'provider_create_emrcreateAppointment';
|
||||
|
||||
// Test missing required fields
|
||||
const requiredFields = ['patient_id', 'practitioner_id', 'appointment_date', 'appointment_time'];
|
||||
|
||||
for (const field of requiredFields) {
|
||||
const incompleteParams = {
|
||||
patient_id: 'patient_123',
|
||||
practitioner_id: 'provider_456',
|
||||
appointment_date: '2025-07-15',
|
||||
appointment_time: '10:00'
|
||||
};
|
||||
delete incompleteParams[field];
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, incompleteParams))
|
||||
.rejects.toThrow();
|
||||
}
|
||||
});
|
||||
|
||||
test('should handle scheduling conflicts', async () => {
|
||||
const toolName = 'provider_create_emrcreateAppointment';
|
||||
const parameters = {
|
||||
patient_id: 'patient_123',
|
||||
practitioner_id: 'provider_456',
|
||||
appointment_date: '2025-07-15',
|
||||
appointment_time: '10:00' // Conflicting time slot
|
||||
};
|
||||
|
||||
// Mock scheduling conflict
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/emr/create-appointment', null, true, {
|
||||
response: {
|
||||
status: 409,
|
||||
data: {
|
||||
error: 'Scheduling conflict detected',
|
||||
conflicting_appointment: {
|
||||
id: 'appointment_existing',
|
||||
time: '10:00',
|
||||
patient: 'Another Patient'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, parameters))
|
||||
.rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should validate appointment date and time', async () => {
|
||||
const toolName = 'provider_create_emrcreateAppointment';
|
||||
|
||||
// Test past date
|
||||
const pastDateParams = {
|
||||
patient_id: 'patient_123',
|
||||
practitioner_id: 'provider_456',
|
||||
appointment_date: '2020-01-01', // Past date
|
||||
appointment_time: '10:00'
|
||||
};
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, pastDateParams))
|
||||
.rejects.toThrow();
|
||||
|
||||
// Test invalid time format
|
||||
const invalidTimeParams = {
|
||||
patient_id: 'patient_123',
|
||||
practitioner_id: 'provider_456',
|
||||
appointment_date: '2025-07-15',
|
||||
appointment_time: '25:00' // Invalid time
|
||||
};
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, invalidTimeParams))
|
||||
.rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('provider_create_bookAppointment', () => {
|
||||
test('should successfully book appointment', async () => {
|
||||
// Setup
|
||||
const toolName = 'provider_create_bookAppointment';
|
||||
const parameters = {
|
||||
telemed_pros_id: 123,
|
||||
patient_id: 456,
|
||||
doctor_id: 789,
|
||||
appointment_id: 101,
|
||||
appointment_time: '2025-07-15 10:00:00'
|
||||
};
|
||||
|
||||
// Mock successful booking
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/book-appointment', {
|
||||
status: 201,
|
||||
data: {
|
||||
success: true,
|
||||
appointment: {
|
||||
id: 101,
|
||||
patientId: 456,
|
||||
doctorId: 789,
|
||||
appointmentTime: '2025-07-15 10:00:00',
|
||||
status: 'booked',
|
||||
telemedProsId: 123
|
||||
},
|
||||
message: 'Appointment booked successfully'
|
||||
}
|
||||
});
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.appointment.status).toBe('booked');
|
||||
expect(result.data.appointment.patientId).toBe(456);
|
||||
});
|
||||
});
|
||||
|
||||
describe('provider_create_appointmentcancel', () => {
|
||||
test('should successfully cancel appointment', async () => {
|
||||
// Setup
|
||||
const toolName = 'provider_create_appointmentcancel';
|
||||
const parameters = {
|
||||
id: 123
|
||||
};
|
||||
|
||||
// Mock successful cancellation
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/emr/appointment/123/cancel', {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
appointment: {
|
||||
id: 123,
|
||||
status: 'cancelled',
|
||||
cancelledAt: new Date().toISOString(),
|
||||
cancelledBy: 'provider_456'
|
||||
},
|
||||
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.cancelledBy).toBe('provider_456');
|
||||
});
|
||||
|
||||
test('should handle cancellation of non-existent appointment', async () => {
|
||||
const toolName = 'provider_create_appointmentcancel';
|
||||
const parameters = {
|
||||
id: 999 // Non-existent appointment
|
||||
};
|
||||
|
||||
// Mock appointment not found
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/emr/appointment/999/cancel', null, true, {
|
||||
response: {
|
||||
status: 404,
|
||||
data: { error: 'Appointment not found' }
|
||||
}
|
||||
});
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, parameters))
|
||||
.rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should handle cancellation of already cancelled appointment', async () => {
|
||||
const toolName = 'provider_create_appointmentcancel';
|
||||
const parameters = {
|
||||
id: 123
|
||||
};
|
||||
|
||||
// Mock already cancelled appointment
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/emr/appointment/123/cancel', null, true, {
|
||||
response: {
|
||||
status: 400,
|
||||
data: { error: 'Appointment is already cancelled' }
|
||||
}
|
||||
});
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, parameters))
|
||||
.rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('provider_create_appointmentqueue', () => {
|
||||
test('should successfully add patient to appointment queue', async () => {
|
||||
// Setup
|
||||
const toolName = 'provider_create_appointmentqueue';
|
||||
const parameters = {
|
||||
patientId: 123
|
||||
};
|
||||
|
||||
// Mock successful queue addition
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/emr/appointment/queue/123', {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
queue_position: 3,
|
||||
estimated_wait_time: '15 minutes',
|
||||
patient: {
|
||||
id: 123,
|
||||
name: 'John Doe',
|
||||
queuedAt: new Date().toISOString()
|
||||
},
|
||||
message: 'Patient added to queue successfully'
|
||||
}
|
||||
});
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.queue_position).toBe(3);
|
||||
expect(result.data.estimated_wait_time).toBe('15 minutes');
|
||||
});
|
||||
});
|
||||
|
||||
describe('provider_create_availableSlot', () => {
|
||||
test('should successfully get available appointment slots', async () => {
|
||||
// Setup
|
||||
const toolName = 'provider_create_availableSlot';
|
||||
const parameters = {
|
||||
date: '2025-07-15'
|
||||
};
|
||||
|
||||
// Mock available slots response
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/available-slots/2025-07-15', {
|
||||
status: 200,
|
||||
data: {
|
||||
date: '2025-07-15',
|
||||
available_slots: [
|
||||
{
|
||||
time: '09:00',
|
||||
duration: 30,
|
||||
provider_id: 'provider_456',
|
||||
provider_name: 'Dr. Smith',
|
||||
location: 'Room 101'
|
||||
},
|
||||
{
|
||||
time: '10:30',
|
||||
duration: 30,
|
||||
provider_id: 'provider_456',
|
||||
provider_name: 'Dr. Smith',
|
||||
location: 'Room 101'
|
||||
},
|
||||
{
|
||||
time: '14:00',
|
||||
duration: 60,
|
||||
provider_id: 'provider_789',
|
||||
provider_name: 'Dr. Johnson',
|
||||
location: 'Room 102'
|
||||
}
|
||||
],
|
||||
total_slots: 3
|
||||
}
|
||||
});
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.available_slots).toHaveLength(3);
|
||||
expect(result.data.date).toBe('2025-07-15');
|
||||
expect(result.data.available_slots[0].time).toBe('09:00');
|
||||
});
|
||||
|
||||
test('should handle no available slots', async () => {
|
||||
const toolName = 'provider_create_availableSlot';
|
||||
const parameters = {
|
||||
date: '2025-12-25' // Holiday - no slots
|
||||
};
|
||||
|
||||
// Mock no slots response
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/available-slots/2025-12-25', {
|
||||
status: 200,
|
||||
data: {
|
||||
date: '2025-12-25',
|
||||
available_slots: [],
|
||||
total_slots: 0,
|
||||
message: 'No available slots for this date'
|
||||
}
|
||||
});
|
||||
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.available_slots).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('provider_create_providerAddAvailability', () => {
|
||||
test('should successfully store provider availability', async () => {
|
||||
// Setup
|
||||
const toolName = 'provider_create_providerAddAvailability';
|
||||
const parameters = {
|
||||
title: 'Morning Clinic Hours',
|
||||
start: '2025-07-15 09:00:00',
|
||||
end: '2025-07-15 12:00:00',
|
||||
type: 'available',
|
||||
comment: 'Regular morning clinic hours',
|
||||
practitioner_id: 456
|
||||
};
|
||||
|
||||
// Mock successful availability storage
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/provider-add-availability', {
|
||||
status: 201,
|
||||
data: {
|
||||
success: true,
|
||||
availability: {
|
||||
id: 'availability_123',
|
||||
title: 'Morning Clinic Hours',
|
||||
start: '2025-07-15 09:00:00',
|
||||
end: '2025-07-15 12:00:00',
|
||||
type: 'available',
|
||||
practitionerId: 456,
|
||||
createdAt: new Date().toISOString()
|
||||
},
|
||||
message: 'Provider availability stored successfully'
|
||||
}
|
||||
});
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.availability.title).toBe('Morning Clinic Hours');
|
||||
expect(result.data.availability.type).toBe('available');
|
||||
expect(result.data.availability.practitionerId).toBe(456);
|
||||
});
|
||||
|
||||
test('should validate availability time ranges', async () => {
|
||||
const toolName = 'provider_create_providerAddAvailability';
|
||||
|
||||
// Test end time before start time
|
||||
const invalidTimeParams = {
|
||||
title: 'Invalid Time Range',
|
||||
start: '2025-07-15 12:00:00',
|
||||
end: '2025-07-15 09:00:00', // End before start
|
||||
type: 'available'
|
||||
};
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, invalidTimeParams))
|
||||
.rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('provider_create_getAppointmentList', () => {
|
||||
test('should successfully get appointments list', async () => {
|
||||
// Setup
|
||||
const toolName = 'provider_create_getAppointmentList';
|
||||
const parameters = {};
|
||||
|
||||
// Mock appointments list response
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/get-appointment-list', {
|
||||
status: 200,
|
||||
data: {
|
||||
appointments: [
|
||||
mockFactory.healthcareMocks.generateMockAppointment({
|
||||
id: 'appointment_1',
|
||||
date: '2025-07-15',
|
||||
time: '09:00'
|
||||
}),
|
||||
mockFactory.healthcareMocks.generateMockAppointment({
|
||||
id: 'appointment_2',
|
||||
date: '2025-07-15',
|
||||
time: '10:30'
|
||||
})
|
||||
],
|
||||
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.appointments).toHaveLength(2);
|
||||
expect(result.data.total_count).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('provider_create_getAppointmentListDate', () => {
|
||||
test('should successfully get appointments by date', async () => {
|
||||
// Setup
|
||||
const toolName = 'provider_create_getAppointmentListDate';
|
||||
const parameters = {
|
||||
date: '2025-07-15',
|
||||
practitioner_id: 456
|
||||
};
|
||||
|
||||
// Mock date-filtered appointments
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/get-appointment-list-date', {
|
||||
status: 200,
|
||||
data: {
|
||||
date: '2025-07-15',
|
||||
practitioner_id: 456,
|
||||
appointments: [
|
||||
mockFactory.healthcareMocks.generateMockAppointment({
|
||||
date: '2025-07-15',
|
||||
providerId: 'provider_456'
|
||||
})
|
||||
],
|
||||
total_count: 1
|
||||
}
|
||||
});
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.date).toBe('2025-07-15');
|
||||
expect(result.data.appointments).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Appointment Security and Compliance Tests', () => {
|
||||
test('should require provider authentication for appointment operations', async () => {
|
||||
// Clear authentication
|
||||
mockFactory.authMocks.reset();
|
||||
|
||||
const toolName = 'provider_create_emrcreateAppointment';
|
||||
const parameters = {
|
||||
patient_id: 'patient_123',
|
||||
practitioner_id: 'provider_456',
|
||||
appointment_date: '2025-07-15',
|
||||
appointment_time: '10:00'
|
||||
};
|
||||
|
||||
// Mock authentication failure
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/emr/create-appointment', null, true, {
|
||||
response: {
|
||||
status: 401,
|
||||
data: { error: 'Provider authentication required' }
|
||||
}
|
||||
});
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, parameters))
|
||||
.rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should validate provider permissions for appointment management', async () => {
|
||||
const toolName = 'provider_create_appointmentcancel';
|
||||
const parameters = {
|
||||
id: 123
|
||||
};
|
||||
|
||||
// Mock insufficient permissions
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/emr/appointment/123/cancel', null, true, {
|
||||
response: {
|
||||
status: 403,
|
||||
data: { error: 'Insufficient permissions to cancel this appointment' }
|
||||
}
|
||||
});
|
||||
|
||||
await expect(toolGenerator.executeTool(toolName, parameters))
|
||||
.rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should audit appointment activities for compliance', async () => {
|
||||
const toolName = 'provider_create_emrcreateAppointment';
|
||||
const parameters = {
|
||||
patient_id: 'patient_123',
|
||||
practitioner_id: 'provider_456',
|
||||
appointment_date: '2025-07-15',
|
||||
appointment_time: '10:00'
|
||||
};
|
||||
|
||||
// Mock response with audit trail
|
||||
mockFactory.httpMocks.mockRequest('POST', '/api/emr/create-appointment', {
|
||||
status: 201,
|
||||
data: {
|
||||
success: true,
|
||||
appointment: mockFactory.healthcareMocks.generateMockAppointment(),
|
||||
auditTrail: {
|
||||
createdBy: 'provider_456',
|
||||
createdAt: new Date().toISOString(),
|
||||
action: 'appointment_created',
|
||||
patientId: 'patient_123',
|
||||
ipAddress: '127.0.0.1'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
expect(result.data.auditTrail).toBeDefined();
|
||||
expect(result.data.auditTrail.action).toBe('appointment_created');
|
||||
expect(result.data.auditTrail.createdBy).toBe('provider_456');
|
||||
});
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user