/** * @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"); }); }); });