first
This commit is contained in:
455
tests/public/password-management.test.js
Normal file
455
tests/public/password-management.test.js
Normal file
@@ -0,0 +1,455 @@
|
||||
/**
|
||||
* @fileoverview Tests for public password management MCP tools
|
||||
* Tests password reset, forgot password, and set password functionality
|
||||
*/
|
||||
|
||||
import { describe, test, expect, beforeEach, afterEach } from "@jest/globals";
|
||||
import { mockFactory } from "../mocks/mockFactory.js";
|
||||
|
||||
describe("Public Password Management Tools", () => {
|
||||
let mockEnv;
|
||||
let toolGenerator;
|
||||
|
||||
beforeEach(() => {
|
||||
mockEnv = mockFactory.createMockEnvironment({
|
||||
authTypes: ["public"],
|
||||
enableHttpMocks: true,
|
||||
});
|
||||
|
||||
toolGenerator = mockEnv.toolGenerator;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFactory.resetAllMocks();
|
||||
});
|
||||
|
||||
describe("public_create_forgotPassword", () => {
|
||||
test("should successfully initiate password reset", async () => {
|
||||
// Setup
|
||||
const toolName = "public_create_forgotPassword";
|
||||
const parameters = {
|
||||
email: "user@test.com",
|
||||
};
|
||||
|
||||
// Mock successful forgot password response
|
||||
mockFactory.httpMocks.mockRequest("POST", "/api/forgot-password", {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
message: "Password reset email sent successfully",
|
||||
email: "user@test.com",
|
||||
},
|
||||
});
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.message).toContain("Password reset email sent");
|
||||
});
|
||||
|
||||
test("should validate email format", async () => {
|
||||
const toolName = "public_create_forgotPassword";
|
||||
const parameters = {
|
||||
email: "invalid-email-format",
|
||||
};
|
||||
|
||||
await expect(
|
||||
toolGenerator.executeTool(toolName, parameters)
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
test("should handle non-existent email gracefully", async () => {
|
||||
const toolName = "public_create_forgotPassword";
|
||||
const parameters = {
|
||||
email: "nonexistent@test.com",
|
||||
};
|
||||
|
||||
// Mock response for non-existent email (should still return success for security)
|
||||
mockFactory.httpMocks.mockRequest("POST", "/api/forgot-password", {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
message: "If the email exists, a reset link has been sent",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("public_create_frontendforgotPassword", () => {
|
||||
test("should successfully initiate patient password reset", async () => {
|
||||
// Setup
|
||||
const toolName = "public_create_frontendforgotPassword";
|
||||
const parameters = {
|
||||
email: "patient@test.com",
|
||||
};
|
||||
|
||||
// Mock successful patient forgot password response
|
||||
mockFactory.httpMocks.mockRequest(
|
||||
"POST",
|
||||
"/api/frontend/forgot-password",
|
||||
{
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
message: "Patient password reset email sent",
|
||||
email: "patient@test.com",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.message).toContain("Patient password reset");
|
||||
});
|
||||
});
|
||||
|
||||
describe("public_create_providerforgotPassword", () => {
|
||||
test("should successfully initiate provider password reset", async () => {
|
||||
// Setup
|
||||
const toolName = "public_create_providerforgotPassword";
|
||||
const parameters = {
|
||||
email: "provider@test.com",
|
||||
};
|
||||
|
||||
// Mock successful provider forgot password response
|
||||
mockFactory.httpMocks.mockRequest(
|
||||
"POST",
|
||||
"/api/emr/provider/forgot-password",
|
||||
{
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
message: "Provider password reset email sent",
|
||||
email: "provider@test.com",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.message).toContain("Provider password reset");
|
||||
});
|
||||
});
|
||||
|
||||
describe("public_create_passwordReset", () => {
|
||||
test("should successfully reset password with valid token", async () => {
|
||||
// Setup
|
||||
const toolName = "public_create_passwordReset";
|
||||
const parameters = {
|
||||
token: "valid_reset_token_123",
|
||||
email: "user@test.com",
|
||||
password: "NewSecurePass123!",
|
||||
password_confirmation: "NewSecurePass123!",
|
||||
};
|
||||
|
||||
// Mock successful password reset
|
||||
mockFactory.httpMocks.mockRequest("POST", "/api/password-reset", {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
message: "Password reset successfully",
|
||||
email: "user@test.com",
|
||||
},
|
||||
});
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.message).toContain("Password reset successfully");
|
||||
});
|
||||
|
||||
test("should validate password confirmation match", async () => {
|
||||
const toolName = "public_create_passwordReset";
|
||||
const parameters = {
|
||||
token: "valid_reset_token_123",
|
||||
email: "user@test.com",
|
||||
password: "NewSecurePass123!",
|
||||
password_confirmation: "DifferentPassword123!",
|
||||
};
|
||||
|
||||
await expect(
|
||||
toolGenerator.executeTool(toolName, parameters)
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
test("should handle invalid reset token", async () => {
|
||||
const toolName = "public_create_passwordReset";
|
||||
const parameters = {
|
||||
token: "invalid_token",
|
||||
email: "user@test.com",
|
||||
password: "NewSecurePass123!",
|
||||
password_confirmation: "NewSecurePass123!",
|
||||
};
|
||||
|
||||
// Mock invalid token response
|
||||
mockFactory.httpMocks.mockRequest(
|
||||
"POST",
|
||||
"/api/password-reset",
|
||||
null,
|
||||
true,
|
||||
{
|
||||
response: {
|
||||
status: 400,
|
||||
data: { error: "Invalid or expired reset token" },
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
await expect(
|
||||
toolGenerator.executeTool(toolName, parameters)
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
test("should handle expired reset token", async () => {
|
||||
const toolName = "public_create_passwordReset";
|
||||
const parameters = {
|
||||
token: "expired_token_456",
|
||||
email: "user@test.com",
|
||||
password: "NewSecurePass123!",
|
||||
password_confirmation: "NewSecurePass123!",
|
||||
};
|
||||
|
||||
// Mock expired token response
|
||||
mockFactory.httpMocks.mockRequest(
|
||||
"POST",
|
||||
"/api/password-reset",
|
||||
null,
|
||||
true,
|
||||
{
|
||||
response: {
|
||||
status: 410,
|
||||
data: { error: "Reset token has expired" },
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
await expect(
|
||||
toolGenerator.executeTool(toolName, parameters)
|
||||
).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe("public_create_frontendresetPassword", () => {
|
||||
test("should successfully reset patient password", async () => {
|
||||
// Setup
|
||||
const toolName = "public_create_frontendresetPassword";
|
||||
const parameters = {
|
||||
email: "patient@test.com",
|
||||
password: "NewPatientPass123!",
|
||||
password_confirmation: "NewPatientPass123!",
|
||||
token: "patient_reset_token_789",
|
||||
};
|
||||
|
||||
// Mock successful patient password reset
|
||||
mockFactory.httpMocks.mockRequest(
|
||||
"POST",
|
||||
"/api/frontend/reset-password",
|
||||
{
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
message: "Patient password reset successfully",
|
||||
email: "patient@test.com",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.message).toContain("Patient password reset");
|
||||
});
|
||||
});
|
||||
|
||||
describe("public_create_setPassword", () => {
|
||||
test("should successfully set password with valid token", async () => {
|
||||
// Setup
|
||||
const toolName = "public_create_setPassword";
|
||||
const parameters = {
|
||||
password: "NewPassword123!",
|
||||
password_confirmation: "NewPassword123!",
|
||||
token: "set_password_token_101",
|
||||
};
|
||||
|
||||
// Mock successful password set
|
||||
mockFactory.httpMocks.mockRequest("POST", "/api/set-password", {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
message: "Password set successfully",
|
||||
},
|
||||
});
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.message).toContain("Password set successfully");
|
||||
});
|
||||
|
||||
test("should validate password strength requirements", async () => {
|
||||
const toolName = "public_create_setPassword";
|
||||
|
||||
// Test weak passwords
|
||||
const weakPasswords = [
|
||||
"123", // Too short
|
||||
"password", // No numbers/special chars
|
||||
"12345678", // Only numbers
|
||||
"PASSWORD", // Only uppercase
|
||||
"password123", // No special characters
|
||||
];
|
||||
|
||||
for (const weakPassword of weakPasswords) {
|
||||
const parameters = {
|
||||
password: weakPassword,
|
||||
password_confirmation: weakPassword,
|
||||
token: "valid_token",
|
||||
};
|
||||
|
||||
await expect(
|
||||
toolGenerator.executeTool(toolName, parameters)
|
||||
).rejects.toThrow();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("public_create_emrsetPassword", () => {
|
||||
test("should successfully set EMR password", async () => {
|
||||
// Setup
|
||||
const toolName = "public_create_emrsetPassword";
|
||||
const parameters = {
|
||||
password: "EMRPassword123!",
|
||||
password_confirmation: "EMRPassword123!",
|
||||
token: "emr_token_202",
|
||||
};
|
||||
|
||||
// Mock successful EMR password set
|
||||
mockFactory.httpMocks.mockRequest("POST", "/api/emr/set-password", {
|
||||
status: 200,
|
||||
data: {
|
||||
success: true,
|
||||
message: "EMR password set successfully",
|
||||
},
|
||||
});
|
||||
|
||||
// Execute
|
||||
const result = await toolGenerator.executeTool(toolName, parameters);
|
||||
|
||||
// Assert
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.message).toContain("EMR password set");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Password Security Tests", () => {
|
||||
test("should enforce password complexity requirements", async () => {
|
||||
const toolName = "public_create_passwordReset";
|
||||
|
||||
// Test various password requirements
|
||||
const testCases = [
|
||||
{
|
||||
password: "short",
|
||||
description: "too short",
|
||||
},
|
||||
{
|
||||
password: "nouppercase123!",
|
||||
description: "no uppercase",
|
||||
},
|
||||
{
|
||||
password: "NOLOWERCASE123!",
|
||||
description: "no lowercase",
|
||||
},
|
||||
{
|
||||
password: "NoNumbers!",
|
||||
description: "no numbers",
|
||||
},
|
||||
{
|
||||
password: "NoSpecialChars123",
|
||||
description: "no special characters",
|
||||
},
|
||||
];
|
||||
|
||||
for (const testCase of testCases) {
|
||||
const parameters = {
|
||||
token: "valid_token",
|
||||
email: "test@test.com",
|
||||
password: testCase.password,
|
||||
password_confirmation: testCase.password,
|
||||
};
|
||||
|
||||
await expect(
|
||||
toolGenerator.executeTool(toolName, parameters)
|
||||
).rejects.toThrow();
|
||||
}
|
||||
});
|
||||
|
||||
test("should handle rate limiting for password reset attempts", async () => {
|
||||
const toolName = "public_create_forgotPassword";
|
||||
const parameters = {
|
||||
email: "ratelimited@test.com",
|
||||
};
|
||||
|
||||
// Mock rate limit response
|
||||
mockFactory.httpMocks.mockRequest(
|
||||
"POST",
|
||||
"/api/forgot-password",
|
||||
null,
|
||||
true,
|
||||
{
|
||||
response: {
|
||||
status: 429,
|
||||
data: { error: "Too many password reset attempts" },
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
await expect(
|
||||
toolGenerator.executeTool(toolName, parameters)
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
test("should not expose sensitive information in error messages", async () => {
|
||||
const toolName = "public_create_passwordReset";
|
||||
const parameters = {
|
||||
token: "invalid_token",
|
||||
email: "user@test.com",
|
||||
password: "ValidPass123!",
|
||||
password_confirmation: "ValidPass123!",
|
||||
};
|
||||
|
||||
// Mock generic error response
|
||||
mockFactory.httpMocks.mockRequest(
|
||||
"POST",
|
||||
"/api/password-reset",
|
||||
null,
|
||||
true,
|
||||
{
|
||||
response: {
|
||||
status: 400,
|
||||
data: { error: "Invalid request" }, // Generic error message
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
await expect(
|
||||
toolGenerator.executeTool(toolName, parameters)
|
||||
).rejects.toThrow("Invalid request");
|
||||
});
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user