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();
|
Reference in New Issue
Block a user