package services import ( "os" "strings" "testing" "veza-backend-api/internal/database" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" ) // setupTestEmailServiceForPasswordReset crée un EmailService de test func setupTestEmailServiceForPasswordReset(_ *testing.T) *EmailService { // Créer un Database wrapper minimal pour les tests // Note: On ne peut pas vraiment tester l'envoi d'email sans un serveur SMTP réel // Donc on va tester la construction de l'email et la logique, mais pas l'envoi réel testDB := &database.Database{} logger, _ := zap.NewDevelopment() // Définir des variables d'environnement de test si nécessaire os.Setenv("FRONTEND_URL", "http://localhost:5173") os.Setenv("SMTP_HOST", "localhost") os.Setenv("SMTP_PORT", "587") os.Setenv("FROM_EMAIL", "test@veza.com") os.Setenv("FROM_NAME", "Veza Test") return NewEmailService(testDB, logger) } // TestEmailService_SendPasswordResetEmail_URLGeneration tests URL generation func TestEmailService_SendPasswordResetEmail_URLGeneration(t *testing.T) { service := setupTestEmailServiceForPasswordReset(t) // Test avec FRONTEND_URL défini os.Setenv("FRONTEND_URL", "https://app.veza.com") resetURL := service.buildPasswordResetEmail("https://app.veza.com/reset-password?token=test-token-123") assert.Contains(t, resetURL, "https://app.veza.com/reset-password?token=test-token-123") assert.Contains(t, resetURL, "Reset Password") assert.Contains(t, resetURL, "This link will expire in 1 hour") } // TestEmailService_SendPasswordResetEmail_DefaultURL tests default URL when FRONTEND_URL is not set func TestEmailService_SendPasswordResetEmail_DefaultURL(t *testing.T) { service := setupTestEmailServiceForPasswordReset(t) // Supprimer FRONTEND_URL pour tester la valeur par défaut os.Unsetenv("FRONTEND_URL") // Construire l'URL manuellement pour tester resetURL := "http://localhost:5173/reset-password?token=test-token-456" emailBody := service.buildPasswordResetEmail(resetURL) assert.Contains(t, emailBody, "http://localhost:5173/reset-password?token=test-token-456") assert.Contains(t, emailBody, "Reset Password") assert.Contains(t, emailBody, "This link will expire in 1 hour") assert.Contains(t, emailBody, "If you didn't request this, please ignore this email") } // TestEmailService_BuildPasswordResetEmail_HTMLContent tests HTML email content func TestEmailService_BuildPasswordResetEmail_HTMLContent(t *testing.T) { service := setupTestEmailServiceForPasswordReset(t) resetURL := "https://example.com/reset-password?token=abc123" emailBody := service.buildPasswordResetEmail(resetURL) // Vérifier que le HTML contient les éléments requis assert.Contains(t, emailBody, "") assert.Contains(t, emailBody, "") assert.Contains(t, emailBody, "Reset your password") assert.Contains(t, emailBody, "Reset Password") assert.Contains(t, emailBody, resetURL) assert.Contains(t, emailBody, "This link will expire in 1 hour") assert.Contains(t, emailBody, "If you didn't request this, please ignore this email") assert.Contains(t, emailBody, "You requested to reset your Veza account password") } // TestEmailService_BuildPasswordResetEmail_ExpirationMessage tests expiration message func TestEmailService_BuildPasswordResetEmail_ExpirationMessage(t *testing.T) { service := setupTestEmailServiceForPasswordReset(t) resetURL := "https://example.com/reset-password?token=xyz789" emailBody := service.buildPasswordResetEmail(resetURL) // Vérifier que le message d'expiration est présent assert.Contains(t, emailBody, "This link will expire in 1 hour") // Vérifier que le message de sécurité est présent assert.Contains(t, emailBody, "If you didn't request this, please ignore this email") // Vérifier que le lien est présent deux fois (bouton et texte) resetCount := strings.Count(emailBody, resetURL) assert.GreaterOrEqual(t, resetCount, 2, "Reset URL should appear at least twice (button and text)") } // TestEmailService_BuildPasswordResetEmail_TemplateFallback tests template fallback on error func TestEmailService_BuildPasswordResetEmail_TemplateFallback(t *testing.T) { service := setupTestEmailServiceForPasswordReset(t) // Test avec une URL valide - le template devrait fonctionner resetURL := "https://example.com/reset-password?token=test-token" emailBody := service.buildPasswordResetEmail(resetURL) // Le template devrait être parsé correctement assert.Contains(t, emailBody, resetURL) assert.Contains(t, emailBody, "") // Vérifier que le fallback n'est pas utilisé (le template devrait être parsé) assert.NotContains(t, emailBody, "Click here to reset your password:") } // TestEmailService_BuildPasswordResetEmail_ContainsToken tests that token is included in URL func TestEmailService_BuildPasswordResetEmail_ContainsToken(t *testing.T) { service := setupTestEmailServiceForPasswordReset(t) testToken := "test-reset-token-12345" resetURL := "https://example.com/reset-password?token=" + testToken emailBody := service.buildPasswordResetEmail(resetURL) // Vérifier que le token est présent dans l'email assert.Contains(t, emailBody, testToken) assert.Contains(t, emailBody, "reset-password?token="+testToken) } // TestEmailService_SendPasswordResetEmail_Subject tests email subject func TestEmailService_SendPasswordResetEmail_Subject(t *testing.T) { // Cette méthode teste indirectement que le sujet est correct // En regardant le code, le sujet est "Reset your Veza password" // On ne peut pas tester directement l'envoi sans SMTP, mais on peut vérifier la logique service := setupTestEmailServiceForPasswordReset(t) // Vérifier que la méthode existe et peut être appelée // Note: On ne peut pas vraiment tester l'envoi sans mock SMTP // Mais on peut vérifier que buildPasswordResetEmail fonctionne resetURL := "https://example.com/reset-password?token=test" emailBody := service.buildPasswordResetEmail(resetURL) require.NotEmpty(t, emailBody, "Email body should not be empty") assert.Contains(t, emailBody, "Reset your password") }