first
This commit is contained in:
310
tests/mocks/authMocks.js
Normal file
310
tests/mocks/authMocks.js
Normal file
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* @fileoverview Authentication mocking utilities for Laravel Healthcare MCP Server tests
|
||||
* Provides comprehensive mocking for authentication tokens and Sanctum authentication
|
||||
*/
|
||||
|
||||
import { jest } from "@jest/globals";
|
||||
|
||||
/**
|
||||
* Authentication Mock Manager for handling authentication-related mocks
|
||||
*/
|
||||
export class AuthMockManager {
|
||||
constructor() {
|
||||
this.tokens = new Map();
|
||||
this.credentials = new Map();
|
||||
this.authHistory = [];
|
||||
this.authenticationCleared = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mock AuthManager instance
|
||||
* @returns {Object} Mock AuthManager instance
|
||||
*/
|
||||
createMockAuthManager() {
|
||||
const mockAuthManager = {
|
||||
authenticate: jest.fn(),
|
||||
getToken: jest.fn(),
|
||||
validateToken: jest.fn(),
|
||||
refreshToken: jest.fn(),
|
||||
logout: jest.fn(),
|
||||
validateAllCredentials: jest.fn(),
|
||||
getCacheStats: jest.fn(),
|
||||
credentials: {},
|
||||
tokenCache: new Map(),
|
||||
};
|
||||
|
||||
// Setup method implementations
|
||||
mockAuthManager.authenticate.mockImplementation(
|
||||
async (authType, credentials) => {
|
||||
this.authHistory.push({
|
||||
action: "authenticate",
|
||||
authType,
|
||||
credentials: { ...credentials, password: "[REDACTED]" },
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
|
||||
if (this.shouldAuthenticationSucceed(authType, credentials)) {
|
||||
const token = this.generateMockToken(authType);
|
||||
this.tokens.set(authType, token);
|
||||
return { success: true, token };
|
||||
} else {
|
||||
throw new Error(`Authentication failed for ${authType}`);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
mockAuthManager.getToken.mockImplementation((authType) => {
|
||||
return this.tokens.get(authType) || null;
|
||||
});
|
||||
|
||||
mockAuthManager.validateToken.mockImplementation(
|
||||
async (token, authType) => {
|
||||
const storedToken = this.tokens.get(authType);
|
||||
return storedToken === token;
|
||||
}
|
||||
);
|
||||
|
||||
mockAuthManager.refreshToken.mockImplementation(async (authType) => {
|
||||
if (this.tokens.has(authType)) {
|
||||
const newToken = this.generateMockToken(authType);
|
||||
this.tokens.set(authType, newToken);
|
||||
return { success: true, token: newToken };
|
||||
}
|
||||
throw new Error(`No token found for ${authType}`);
|
||||
});
|
||||
|
||||
mockAuthManager.logout.mockImplementation(async (authType) => {
|
||||
this.tokens.delete(authType);
|
||||
this.authHistory.push({
|
||||
action: "logout",
|
||||
authType,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
return { success: true };
|
||||
});
|
||||
|
||||
mockAuthManager.validateAllCredentials.mockImplementation(async () => {
|
||||
const results = {};
|
||||
for (const authType of Object.values(global.testConstants.AUTH_TYPES)) {
|
||||
if (authType === "public") continue;
|
||||
|
||||
results[authType] = {
|
||||
valid: this.hasValidCredentials(authType),
|
||||
error: this.hasValidCredentials(authType)
|
||||
? null
|
||||
: `Invalid credentials for ${authType}`,
|
||||
};
|
||||
}
|
||||
return results;
|
||||
});
|
||||
|
||||
mockAuthManager.getCacheStats.mockImplementation(() => ({
|
||||
size: this.tokens.size,
|
||||
keys: Array.from(this.tokens.keys()),
|
||||
lastAccess: new Date().toISOString(),
|
||||
}));
|
||||
|
||||
return mockAuthManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a mock authentication token
|
||||
* @param {string} authType - Authentication type
|
||||
* @returns {string} Mock token
|
||||
*/
|
||||
generateMockToken(authType) {
|
||||
const timestamp = Date.now();
|
||||
const random = Math.random().toString(36).substring(2);
|
||||
return `${authType}_token_${timestamp}_${random}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set mock credentials for an authentication type
|
||||
* @param {string} authType - Authentication type
|
||||
* @param {Object} credentials - Mock credentials
|
||||
*/
|
||||
setMockCredentials(authType, credentials) {
|
||||
this.credentials.set(authType, credentials);
|
||||
this.authenticationCleared = false; // Authentication is now available
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if authentication should succeed
|
||||
* @param {string} authType - Authentication type
|
||||
* @param {Object} credentials - Provided credentials
|
||||
* @returns {boolean} Whether authentication should succeed
|
||||
*/
|
||||
shouldAuthenticationSucceed(authType, credentials) {
|
||||
const mockCredentials = this.credentials.get(authType);
|
||||
|
||||
if (!mockCredentials) {
|
||||
// Default success for test credentials
|
||||
return (
|
||||
credentials.username === `test_${authType}` &&
|
||||
credentials.password === "test_password"
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
credentials.username === mockCredentials.username &&
|
||||
credentials.password === mockCredentials.password
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if valid credentials exist for auth type
|
||||
* @param {string} authType - Authentication type
|
||||
* @returns {boolean} Whether valid credentials exist
|
||||
*/
|
||||
hasValidCredentials(authType) {
|
||||
return (
|
||||
this.credentials.has(authType) ||
|
||||
process.env[`${authType.toUpperCase()}_USERNAME`]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup default mock credentials for all auth types
|
||||
*/
|
||||
setupDefaultCredentials() {
|
||||
const authTypes = [
|
||||
"provider",
|
||||
"patient",
|
||||
"partner",
|
||||
"affiliate",
|
||||
"network",
|
||||
];
|
||||
|
||||
authTypes.forEach((authType) => {
|
||||
this.setMockCredentials(authType, {
|
||||
username: `test_${authType}`,
|
||||
password: "test_password",
|
||||
email: `test@${authType}.example.com`,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock Sanctum token authentication
|
||||
* @param {string} token - Bearer token
|
||||
* @returns {Object} Mock user data
|
||||
*/
|
||||
mockSanctumAuth(token) {
|
||||
if (!token || !token.startsWith("Bearer ")) {
|
||||
throw new Error("Invalid token format");
|
||||
}
|
||||
|
||||
const actualToken = token.replace("Bearer ", "");
|
||||
|
||||
// Find auth type from token
|
||||
let authType = "provider";
|
||||
for (const [type, storedToken] of this.tokens.entries()) {
|
||||
if (storedToken === actualToken) {
|
||||
authType = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: `mock_${authType}_user_123`,
|
||||
email: `test@${authType}.example.com`,
|
||||
role: authType,
|
||||
permissions: this.getMockPermissions(authType),
|
||||
tokenType: "Bearer",
|
||||
expiresAt: new Date(Date.now() + 3600000).toISOString(), // 1 hour from now
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mock permissions for auth type
|
||||
* @param {string} authType - Authentication type
|
||||
* @returns {Array} Array of permissions
|
||||
*/
|
||||
getMockPermissions(authType) {
|
||||
const permissions = {
|
||||
provider: [
|
||||
"read:patients",
|
||||
"write:patients",
|
||||
"read:prescriptions",
|
||||
"write:prescriptions",
|
||||
],
|
||||
patient: ["read:own_data", "write:own_data"],
|
||||
partner: ["read:business_data", "write:business_data"],
|
||||
affiliate: ["read:affiliate_data", "write:affiliate_data"],
|
||||
network: ["read:network_data", "write:network_data"],
|
||||
};
|
||||
|
||||
return permissions[authType] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create mock HIPAA-compliant authentication context
|
||||
* @param {string} authType - Authentication type
|
||||
* @returns {Object} HIPAA-compliant auth context
|
||||
*/
|
||||
createHIPAAAuthContext(authType) {
|
||||
return {
|
||||
userId: `mock_${authType}_user_123`,
|
||||
role: authType,
|
||||
permissions: this.getMockPermissions(authType),
|
||||
sessionId: `session_${Date.now()}`,
|
||||
ipAddress: "127.0.0.1",
|
||||
userAgent: "Jest Test Suite",
|
||||
loginTime: new Date().toISOString(),
|
||||
lastActivity: new Date().toISOString(),
|
||||
hipaaCompliant: true,
|
||||
auditTrail: {
|
||||
enabled: true,
|
||||
logLevel: "detailed",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authentication history
|
||||
* @returns {Array} Array of authentication events
|
||||
*/
|
||||
getAuthHistory() {
|
||||
return [...this.authHistory];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear authentication history
|
||||
*/
|
||||
clearHistory() {
|
||||
this.authHistory = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all authentication mocks
|
||||
*/
|
||||
reset() {
|
||||
this.tokens.clear();
|
||||
this.credentials.clear();
|
||||
this.authHistory = [];
|
||||
this.authenticationCleared = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if authentication has been cleared
|
||||
*/
|
||||
isAuthenticationCleared() {
|
||||
return this.authenticationCleared;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate token expiration
|
||||
* @param {string} authType - Authentication type
|
||||
*/
|
||||
expireToken(authType) {
|
||||
this.tokens.delete(authType);
|
||||
this.authHistory.push({
|
||||
action: "token_expired",
|
||||
authType,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const authMockManager = new AuthMockManager();
|
371
tests/mocks/healthcareDataMocks.js
Normal file
371
tests/mocks/healthcareDataMocks.js
Normal file
@@ -0,0 +1,371 @@
|
||||
/**
|
||||
* @fileoverview Healthcare data mocking utilities for Laravel Healthcare MCP Server tests
|
||||
* Provides HIPAA-compliant mock data and validation utilities for healthcare testing
|
||||
*/
|
||||
|
||||
import { jest } from '@jest/globals';
|
||||
|
||||
/**
|
||||
* Healthcare Data Mock Manager for handling healthcare-specific mock data
|
||||
*/
|
||||
export class HealthcareDataMockManager {
|
||||
constructor() {
|
||||
this.patientData = new Map();
|
||||
this.providerData = new Map();
|
||||
this.prescriptionData = new Map();
|
||||
this.appointmentData = new Map();
|
||||
this.medicalRecords = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate comprehensive mock patient data
|
||||
* @param {Object} overrides - Optional field overrides
|
||||
* @returns {Object} Mock patient data
|
||||
*/
|
||||
generateMockPatient(overrides = {}) {
|
||||
const basePatient = {
|
||||
id: `patient_${Date.now()}_${Math.random().toString(36).substring(2)}`,
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
email: 'john.doe@test.example.com',
|
||||
dateOfBirth: '1990-01-01',
|
||||
genderIdentity: 'Male',
|
||||
preferredPhone: '555-0123',
|
||||
address: '123 Test St',
|
||||
city: 'Test City',
|
||||
state: 'TS',
|
||||
zipcode: '12345',
|
||||
status: 'active',
|
||||
isPortalAccess: true,
|
||||
emergencyContact: {
|
||||
name: 'Jane Doe',
|
||||
relationship: 'Spouse',
|
||||
phone: '555-0124'
|
||||
},
|
||||
insurance: {
|
||||
provider: 'Test Insurance',
|
||||
policyNumber: 'TEST123456',
|
||||
groupNumber: 'GRP789'
|
||||
},
|
||||
medicalHistory: {
|
||||
allergies: ['Penicillin'],
|
||||
conditions: ['Hypertension'],
|
||||
medications: ['Lisinopril 10mg']
|
||||
},
|
||||
hipaaConsent: {
|
||||
signed: true,
|
||||
signedDate: '2025-01-01',
|
||||
version: '1.0'
|
||||
},
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
return { ...basePatient, ...overrides };
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate comprehensive mock provider data
|
||||
* @param {Object} overrides - Optional field overrides
|
||||
* @returns {Object} Mock provider data
|
||||
*/
|
||||
generateMockProvider(overrides = {}) {
|
||||
const baseProvider = {
|
||||
id: `provider_${Date.now()}_${Math.random().toString(36).substring(2)}`,
|
||||
firstName: 'Dr. Jane',
|
||||
lastName: 'Smith',
|
||||
emailAddress: 'dr.smith@test.example.com',
|
||||
textMessageNumber: '555-0456',
|
||||
username: 'drsmith',
|
||||
company_name: 'Test Medical Center',
|
||||
npiNumber: '1234567890',
|
||||
licenseNumber: 'MD123456',
|
||||
specialty: 'Internal Medicine',
|
||||
accessRights: {
|
||||
admin: true,
|
||||
practitioner: true,
|
||||
patientPortal: false
|
||||
},
|
||||
credentials: {
|
||||
degree: 'MD',
|
||||
boardCertifications: ['Internal Medicine'],
|
||||
yearsExperience: 10
|
||||
},
|
||||
workSchedule: {
|
||||
monday: { start: '09:00', end: '17:00' },
|
||||
tuesday: { start: '09:00', end: '17:00' },
|
||||
wednesday: { start: '09:00', end: '17:00' },
|
||||
thursday: { start: '09:00', end: '17:00' },
|
||||
friday: { start: '09:00', end: '17:00' }
|
||||
},
|
||||
hipaaTraining: {
|
||||
completed: true,
|
||||
completedDate: '2025-01-01',
|
||||
expirationDate: '2026-01-01'
|
||||
},
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
return { ...baseProvider, ...overrides };
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate comprehensive mock prescription data
|
||||
* @param {Object} overrides - Optional field overrides
|
||||
* @returns {Object} Mock prescription data
|
||||
*/
|
||||
generateMockPrescription(overrides = {}) {
|
||||
const basePrescription = {
|
||||
id: `prescription_${Date.now()}_${Math.random().toString(36).substring(2)}`,
|
||||
patientId: 'test-patient-123',
|
||||
providerId: 'test-provider-456',
|
||||
medication: {
|
||||
name: 'Lisinopril',
|
||||
genericName: 'Lisinopril',
|
||||
strength: '10mg',
|
||||
form: 'Tablet'
|
||||
},
|
||||
dosage: '10mg',
|
||||
frequency: 'Once daily',
|
||||
duration: '30 days',
|
||||
quantity: 30,
|
||||
refills: 2,
|
||||
instructions: 'Take with food',
|
||||
status: 'active',
|
||||
prescribedDate: new Date().toISOString(),
|
||||
startDate: new Date().toISOString(),
|
||||
endDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
pharmacy: {
|
||||
name: 'Test Pharmacy',
|
||||
phone: '555-0789',
|
||||
address: '456 Pharmacy St'
|
||||
},
|
||||
interactions: [],
|
||||
contraindications: [],
|
||||
sideEffects: ['Dizziness', 'Dry cough'],
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
return { ...basePrescription, ...overrides };
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate comprehensive mock appointment data
|
||||
* @param {Object} overrides - Optional field overrides
|
||||
* @returns {Object} Mock appointment data
|
||||
*/
|
||||
generateMockAppointment(overrides = {}) {
|
||||
const baseAppointment = {
|
||||
id: `appointment_${Date.now()}_${Math.random().toString(36).substring(2)}`,
|
||||
patientId: 'test-patient-123',
|
||||
providerId: 'test-provider-456',
|
||||
date: '2025-07-15',
|
||||
time: '10:00',
|
||||
duration: 30,
|
||||
type: 'consultation',
|
||||
status: 'scheduled',
|
||||
reason: 'Annual checkup',
|
||||
notes: 'Patient reports feeling well',
|
||||
location: {
|
||||
room: 'Room 101',
|
||||
building: 'Main Building',
|
||||
address: '123 Medical Center Dr'
|
||||
},
|
||||
reminders: {
|
||||
email: true,
|
||||
sms: true,
|
||||
sentAt: null
|
||||
},
|
||||
telehealth: {
|
||||
enabled: false,
|
||||
platform: null,
|
||||
meetingId: null
|
||||
},
|
||||
billing: {
|
||||
cptCodes: ['99213'],
|
||||
estimatedCost: 150.00,
|
||||
insuranceCovered: true
|
||||
},
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
return { ...baseAppointment, ...overrides };
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate mock medical record data
|
||||
* @param {Object} overrides - Optional field overrides
|
||||
* @returns {Object} Mock medical record data
|
||||
*/
|
||||
generateMockMedicalRecord(overrides = {}) {
|
||||
const baseRecord = {
|
||||
id: `record_${Date.now()}_${Math.random().toString(36).substring(2)}`,
|
||||
patientId: 'test-patient-123',
|
||||
providerId: 'test-provider-456',
|
||||
appointmentId: 'test-appointment-101',
|
||||
type: 'progress_note',
|
||||
date: new Date().toISOString(),
|
||||
chiefComplaint: 'Annual physical examination',
|
||||
historyOfPresentIllness: 'Patient reports feeling well with no acute concerns',
|
||||
physicalExam: {
|
||||
vitals: {
|
||||
bloodPressure: '120/80',
|
||||
heartRate: 72,
|
||||
temperature: 98.6,
|
||||
weight: 150,
|
||||
height: 68
|
||||
},
|
||||
general: 'Well-appearing, no acute distress',
|
||||
cardiovascular: 'Regular rate and rhythm, no murmurs',
|
||||
respiratory: 'Clear to auscultation bilaterally',
|
||||
neurological: 'Alert and oriented x3'
|
||||
},
|
||||
assessment: 'Healthy adult, no acute issues',
|
||||
plan: 'Continue current medications, return in 1 year',
|
||||
medications: ['Lisinopril 10mg daily'],
|
||||
allergies: ['Penicillin'],
|
||||
diagnosis: {
|
||||
primary: 'Z00.00 - Encounter for general adult medical examination',
|
||||
secondary: []
|
||||
},
|
||||
labResults: [],
|
||||
imagingResults: [],
|
||||
followUp: {
|
||||
required: true,
|
||||
timeframe: '1 year',
|
||||
provider: 'same'
|
||||
},
|
||||
hipaaAccess: {
|
||||
accessedBy: ['test-provider-456'],
|
||||
accessLog: [
|
||||
{
|
||||
userId: 'test-provider-456',
|
||||
action: 'view',
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
]
|
||||
},
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
return { ...baseRecord, ...overrides };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create HIPAA-compliant mock data with proper access controls
|
||||
* @param {string} dataType - Type of data to create
|
||||
* @param {string} userRole - Role of the accessing user
|
||||
* @param {Object} overrides - Optional field overrides
|
||||
* @returns {Object} HIPAA-compliant mock data
|
||||
*/
|
||||
createHIPAACompliantData(dataType, userRole, overrides = {}) {
|
||||
let data;
|
||||
|
||||
switch (dataType) {
|
||||
case 'patient':
|
||||
data = this.generateMockPatient(overrides);
|
||||
break;
|
||||
case 'provider':
|
||||
data = this.generateMockProvider(overrides);
|
||||
break;
|
||||
case 'prescription':
|
||||
data = this.generateMockPrescription(overrides);
|
||||
break;
|
||||
case 'appointment':
|
||||
data = this.generateMockAppointment(overrides);
|
||||
break;
|
||||
case 'medical_record':
|
||||
data = this.generateMockMedicalRecord(overrides);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown data type: ${dataType}`);
|
||||
}
|
||||
|
||||
// Add HIPAA compliance metadata
|
||||
data.hipaaMetadata = {
|
||||
accessLevel: this.getAccessLevel(userRole),
|
||||
encryptionStatus: 'encrypted',
|
||||
auditTrail: {
|
||||
created: new Date().toISOString(),
|
||||
createdBy: `mock_${userRole}_user`,
|
||||
lastAccessed: new Date().toISOString(),
|
||||
accessCount: 1
|
||||
},
|
||||
dataClassification: 'PHI', // Protected Health Information
|
||||
retentionPolicy: {
|
||||
retainUntil: new Date(Date.now() + 7 * 365 * 24 * 60 * 60 * 1000).toISOString(), // 7 years
|
||||
autoDelete: true
|
||||
}
|
||||
};
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access level based on user role
|
||||
* @param {string} userRole - User role
|
||||
* @returns {string} Access level
|
||||
*/
|
||||
getAccessLevel(userRole) {
|
||||
const accessLevels = {
|
||||
provider: 'full',
|
||||
patient: 'own_data_only',
|
||||
partner: 'business_data_only',
|
||||
affiliate: 'limited',
|
||||
network: 'network_data_only'
|
||||
};
|
||||
|
||||
return accessLevels[userRole] || 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate HIPAA compliance for mock data
|
||||
* @param {Object} data - Data to validate
|
||||
* @param {string} userRole - User role requesting access
|
||||
* @returns {Object} Validation result
|
||||
*/
|
||||
validateHIPAACompliance(data, userRole) {
|
||||
const validation = {
|
||||
isCompliant: true,
|
||||
violations: [],
|
||||
warnings: []
|
||||
};
|
||||
|
||||
// Check if data has HIPAA metadata
|
||||
if (!data.hipaaMetadata) {
|
||||
validation.isCompliant = false;
|
||||
validation.violations.push('Missing HIPAA metadata');
|
||||
}
|
||||
|
||||
// Check access level
|
||||
const requiredAccessLevel = this.getAccessLevel(userRole);
|
||||
if (data.hipaaMetadata && data.hipaaMetadata.accessLevel !== requiredAccessLevel) {
|
||||
validation.warnings.push(`Access level mismatch: expected ${requiredAccessLevel}, got ${data.hipaaMetadata.accessLevel}`);
|
||||
}
|
||||
|
||||
// Check for PHI in logs
|
||||
if (data.hipaaMetadata && data.hipaaMetadata.dataClassification === 'PHI') {
|
||||
validation.warnings.push('PHI data detected - ensure proper handling');
|
||||
}
|
||||
|
||||
return validation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all healthcare data mocks
|
||||
*/
|
||||
reset() {
|
||||
this.patientData.clear();
|
||||
this.providerData.clear();
|
||||
this.prescriptionData.clear();
|
||||
this.appointmentData.clear();
|
||||
this.medicalRecords.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const healthcareDataMockManager = new HealthcareDataMockManager();
|
283
tests/mocks/httpMocks.js
Normal file
283
tests/mocks/httpMocks.js
Normal file
@@ -0,0 +1,283 @@
|
||||
/**
|
||||
* @fileoverview HTTP mocking utilities for Laravel Healthcare MCP Server tests
|
||||
* Provides comprehensive mocking for axios requests and API responses
|
||||
*/
|
||||
|
||||
import { jest } from '@jest/globals';
|
||||
|
||||
/**
|
||||
* HTTP Mock Manager for handling axios mocks
|
||||
*/
|
||||
export class HttpMockManager {
|
||||
constructor() {
|
||||
this.mocks = new Map();
|
||||
this.defaultResponses = new Map();
|
||||
this.requestHistory = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mock axios instance
|
||||
* @returns {Object} Mock axios instance
|
||||
*/
|
||||
createMockAxios() {
|
||||
const mockAxios = {
|
||||
get: jest.fn(),
|
||||
post: jest.fn(),
|
||||
put: jest.fn(),
|
||||
patch: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
request: jest.fn(),
|
||||
defaults: {
|
||||
headers: {
|
||||
common: {},
|
||||
get: {},
|
||||
post: {},
|
||||
put: {},
|
||||
patch: {},
|
||||
delete: {}
|
||||
},
|
||||
timeout: 5000,
|
||||
baseURL: ''
|
||||
},
|
||||
interceptors: {
|
||||
request: {
|
||||
use: jest.fn(),
|
||||
eject: jest.fn()
|
||||
},
|
||||
response: {
|
||||
use: jest.fn(),
|
||||
eject: jest.fn()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Track all requests
|
||||
const trackRequest = (method, url, config = {}) => {
|
||||
this.requestHistory.push({
|
||||
method: method.toUpperCase(),
|
||||
url,
|
||||
config,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
};
|
||||
|
||||
// Setup method implementations
|
||||
mockAxios.get.mockImplementation((url, config) => {
|
||||
trackRequest('GET', url, config);
|
||||
return this.handleRequest('GET', url, config);
|
||||
});
|
||||
|
||||
mockAxios.post.mockImplementation((url, data, config) => {
|
||||
trackRequest('POST', url, { ...config, data });
|
||||
return this.handleRequest('POST', url, { ...config, data });
|
||||
});
|
||||
|
||||
mockAxios.put.mockImplementation((url, data, config) => {
|
||||
trackRequest('PUT', url, { ...config, data });
|
||||
return this.handleRequest('PUT', url, { ...config, data });
|
||||
});
|
||||
|
||||
mockAxios.patch.mockImplementation((url, data, config) => {
|
||||
trackRequest('PATCH', url, { ...config, data });
|
||||
return this.handleRequest('PATCH', url, { ...config, data });
|
||||
});
|
||||
|
||||
mockAxios.delete.mockImplementation((url, config) => {
|
||||
trackRequest('DELETE', url, config);
|
||||
return this.handleRequest('DELETE', url, config);
|
||||
});
|
||||
|
||||
return mockAxios;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle HTTP request and return appropriate mock response
|
||||
* @param {string} method - HTTP method
|
||||
* @param {string} url - Request URL
|
||||
* @param {Object} config - Request configuration
|
||||
* @returns {Promise} Promise resolving to mock response
|
||||
*/
|
||||
async handleRequest(method, url, config = {}) {
|
||||
const key = `${method}:${url}`;
|
||||
|
||||
// Check for specific mock
|
||||
if (this.mocks.has(key)) {
|
||||
const mockConfig = this.mocks.get(key);
|
||||
|
||||
if (mockConfig.shouldFail) {
|
||||
throw mockConfig.error || new Error(`Mock error for ${key}`);
|
||||
}
|
||||
|
||||
return mockConfig.response;
|
||||
}
|
||||
|
||||
// Check for default response
|
||||
if (this.defaultResponses.has(method)) {
|
||||
return this.defaultResponses.get(method);
|
||||
}
|
||||
|
||||
// Default success response
|
||||
return {
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
data: { success: true, message: 'Mock response' },
|
||||
headers: { 'content-type': 'application/json' }
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock a specific HTTP request
|
||||
* @param {string} method - HTTP method
|
||||
* @param {string} url - Request URL
|
||||
* @param {Object} response - Mock response
|
||||
* @param {boolean} shouldFail - Whether the request should fail
|
||||
* @param {Error} error - Error to throw if shouldFail is true
|
||||
*/
|
||||
mockRequest(method, url, response, shouldFail = false, error = null) {
|
||||
const key = `${method.toUpperCase()}:${url}`;
|
||||
this.mocks.set(key, {
|
||||
response,
|
||||
shouldFail,
|
||||
error
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock authentication login requests
|
||||
* @param {string} authType - Authentication type
|
||||
* @param {boolean} shouldSucceed - Whether login should succeed
|
||||
*/
|
||||
mockAuthLogin(authType, shouldSucceed = true) {
|
||||
const endpoints = {
|
||||
public: '/api/login',
|
||||
provider: '/api/login',
|
||||
patient: '/api/frontend/login',
|
||||
partner: '/api/login-partner-api',
|
||||
affiliate: '/api/affiliate-login-api',
|
||||
network: '/api/network/login'
|
||||
};
|
||||
|
||||
const endpoint = endpoints[authType] || '/api/login';
|
||||
|
||||
if (shouldSucceed) {
|
||||
this.mockRequest('POST', endpoint, {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
token: `mock_${authType}_token_${Date.now()}`,
|
||||
user: {
|
||||
id: `mock_${authType}_user_123`,
|
||||
email: `test@${authType}.example.com`,
|
||||
role: authType
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.mockRequest('POST', endpoint, null, true, {
|
||||
response: {
|
||||
status: 401,
|
||||
data: { error: 'Invalid credentials' }
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock healthcare data endpoints
|
||||
*/
|
||||
mockHealthcareEndpoints() {
|
||||
// Patient data endpoints
|
||||
this.mockRequest('GET', '/api/emr/patients', {
|
||||
status: 200,
|
||||
data: {
|
||||
patients: [
|
||||
global.testUtils.createMockPatientData(),
|
||||
{ ...global.testUtils.createMockPatientData(), id: 'test-patient-456' }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
this.mockRequest('POST', '/api/emr/patients', {
|
||||
status: 201,
|
||||
data: {
|
||||
success: true,
|
||||
patient: global.testUtils.createMockPatientData()
|
||||
}
|
||||
});
|
||||
|
||||
// Provider data endpoints
|
||||
this.mockRequest('GET', '/api/emr/providers', {
|
||||
status: 200,
|
||||
data: {
|
||||
providers: [
|
||||
global.testUtils.createMockProviderData(),
|
||||
{ ...global.testUtils.createMockProviderData(), id: 'test-provider-789' }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
// Prescription endpoints
|
||||
this.mockRequest('GET', '/api/emr/prescriptions', {
|
||||
status: 200,
|
||||
data: {
|
||||
prescriptions: [
|
||||
global.testUtils.createMockPrescriptionData()
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
this.mockRequest('POST', '/api/emr/prescriptions', {
|
||||
status: 201,
|
||||
data: {
|
||||
success: true,
|
||||
prescription: global.testUtils.createMockPrescriptionData()
|
||||
}
|
||||
});
|
||||
|
||||
// Appointment endpoints
|
||||
this.mockRequest('GET', '/api/emr/appointments', {
|
||||
status: 200,
|
||||
data: {
|
||||
appointments: [
|
||||
global.testUtils.createMockAppointmentData()
|
||||
]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get request history
|
||||
* @returns {Array} Array of request objects
|
||||
*/
|
||||
getRequestHistory() {
|
||||
return [...this.requestHistory];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear request history
|
||||
*/
|
||||
clearHistory() {
|
||||
this.requestHistory = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all mocks
|
||||
*/
|
||||
reset() {
|
||||
this.mocks.clear();
|
||||
this.defaultResponses.clear();
|
||||
this.requestHistory = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default response for a method
|
||||
* @param {string} method - HTTP method
|
||||
* @param {Object} response - Default response
|
||||
*/
|
||||
setDefaultResponse(method, response) {
|
||||
this.defaultResponses.set(method.toUpperCase(), response);
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const httpMockManager = new HttpMockManager();
|
3066
tests/mocks/mockFactory.js
Normal file
3066
tests/mocks/mockFactory.js
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user