package handler import ( "baron-sso-backend/internal/domain" "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/gofiber/fiber/v2" "github.com/stretchr/testify/assert" ) // Mock services type mockEmailService struct{} func (m *mockEmailService) SendEmail(to, subject, body string) error { return nil } type mockSmsService struct{} func (m *mockSmsService) SendSms(to, content string) error { return nil } func TestEnchantedLinkFlow_Email_Success(t *testing.T) { redis := &mockRedisRepo{data: make(map[string]string)} // Force "Not Supported" for InitiateLinkLogin only to trigger custom Enchanted Link logic idp := &mockIdpProvider{ userExists: true, initiateLinkErr: domain.ErrNotSupported, } h := &AuthHandler{ RedisService: redis, IdpProvider: idp, EmailService: &mockEmailService{}, SmsService: &mockSmsService{}, } app := fiber.New() app.Post("/api/v1/auth/enchanted-link/init", h.InitEnchantedLink) app.Post("/api/v1/auth/enchanted-link/poll", h.PollEnchantedLink) app.Post("/api/v1/auth/magic-link/verify", h.VerifyMagicLink) t.Setenv("USERFRONT_URL", "http://userfront.test") // 1. Init Enchanted Link (Email) body, _ := json.Marshal(map[string]string{ "loginId": "user@example.com", "method": "email", }) req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/enchanted-link/init", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") resp, _ := app.Test(req, -1) assert.Equal(t, http.StatusOK, resp.StatusCode) var initResp map[string]interface{} json.NewDecoder(resp.Body).Decode(&initResp) pendingRef := initResp["pendingRef"].(string) assert.NotEmpty(t, pendingRef) // Find the token key "enchanted_token:..." in mock redis var token string for k := range redis.data { if len(k) > 16 && k[:16] == "enchanted_token:" { token = k[16:] break } } assert.NotEmpty(t, token) // 2. Verify Magic Link verifyBody, _ := json.Marshal(map[string]interface{}{ "token": token, "verifyOnly": true, }) req = httptest.NewRequest(http.MethodPost, "/api/v1/auth/magic-link/verify", bytes.NewReader(verifyBody)) req.Header.Set("Content-Type", "application/json") resp, _ = app.Test(req, -1) assert.Equal(t, http.StatusOK, resp.StatusCode) // 3. Poll (Success) pollBody, _ := json.Marshal(map[string]string{"pendingRef": pendingRef}) req = httptest.NewRequest(http.MethodPost, "/api/v1/auth/enchanted-link/poll", bytes.NewReader(pollBody)) req.Header.Set("Content-Type", "application/json") resp, _ = app.Test(req, -1) assert.Equal(t, http.StatusOK, resp.StatusCode) var pollResp map[string]interface{} json.NewDecoder(resp.Body).Decode(&pollResp) assert.Equal(t, "ok", pollResp["status"]) assert.Equal(t, "valid-jwt", pollResp["sessionJwt"]) } func TestEnchantedLinkFlow_Sms_Success(t *testing.T) { redis := &mockRedisRepo{data: make(map[string]string)} idp := &mockIdpProvider{ userExists: true, initiateLinkErr: domain.ErrNotSupported, } h := &AuthHandler{ RedisService: redis, IdpProvider: idp, SmsService: &mockSmsService{}, } app := fiber.New() app.Post("/api/v1/auth/enchanted-link/init", h.InitEnchantedLink) // 1. Init Enchanted Link (SMS) body, _ := json.Marshal(map[string]string{ "loginId": "010-1234-5678", "method": "sms", }) req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/enchanted-link/init", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") resp, _ := app.Test(req, -1) assert.Equal(t, http.StatusOK, resp.StatusCode) var initResp map[string]interface{} json.NewDecoder(resp.Body).Decode(&initResp) assert.NotEmpty(t, initResp["userCode"]) }