Migrate from Gin to Echo framework and add comprehensive integration tests
Major changes: - Migrate all handlers from Gin to Echo framework - Add new apperrors, echohelpers, and validator packages - Update middleware for Echo compatibility - Add ArchivedHandler to task categorization chain (archived tasks go to cancelled_tasks column) - Add 6 new integration tests: - RecurringTaskLifecycle: NextDueDate advancement for weekly/monthly tasks - MultiUserSharing: Complex sharing with user removal - TaskStateTransitions: All state transitions and kanban column changes - DateBoundaryEdgeCases: Threshold boundary testing - CascadeOperations: Residence deletion cascade effects - MultiUserOperations: Shared residence collaboration - Add single-purpose repository functions for kanban columns (GetOverdueTasks, GetDueSoonTasks, etc.) - Fix RemoveUser route param mismatch (userId -> user_id) - Fix determineExpectedColumn helper to correctly prioritize in_progress over overdue 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,14 +8,16 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
|
||||
"github.com/treytartt/casera-api/internal/apperrors"
|
||||
"github.com/treytartt/casera-api/internal/i18n"
|
||||
"github.com/treytartt/casera-api/internal/models"
|
||||
"github.com/treytartt/casera-api/internal/validator"
|
||||
)
|
||||
|
||||
var i18nOnce sync.Once
|
||||
@@ -68,14 +70,16 @@ func SetupTestDB(t *testing.T) *gorm.DB {
|
||||
return db
|
||||
}
|
||||
|
||||
// SetupTestRouter creates a test Gin router
|
||||
func SetupTestRouter() *gin.Engine {
|
||||
gin.SetMode(gin.TestMode)
|
||||
return gin.New()
|
||||
// SetupTestRouter creates a test Echo router with the custom error handler
|
||||
func SetupTestRouter() *echo.Echo {
|
||||
e := echo.New()
|
||||
e.Validator = validator.NewCustomValidator()
|
||||
e.HTTPErrorHandler = apperrors.HTTPErrorHandler
|
||||
return e
|
||||
}
|
||||
|
||||
// MakeRequest makes a test HTTP request and returns the response
|
||||
func MakeRequest(router *gin.Engine, method, path string, body interface{}, token string) *httptest.ResponseRecorder {
|
||||
func MakeRequest(router *echo.Echo, method, path string, body interface{}, token string) *httptest.ResponseRecorder {
|
||||
var reqBody *bytes.Buffer
|
||||
if body != nil {
|
||||
jsonBody, _ := json.Marshal(body)
|
||||
@@ -90,9 +94,9 @@ func MakeRequest(router *gin.Engine, method, path string, body interface{}, toke
|
||||
req.Header.Set("Authorization", "Token "+token)
|
||||
}
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
return w
|
||||
rec := httptest.NewRecorder()
|
||||
router.ServeHTTP(rec, req)
|
||||
return rec
|
||||
}
|
||||
|
||||
// ParseJSON parses JSON response body into a map
|
||||
@@ -287,11 +291,13 @@ func AssertStatusCode(t *testing.T, w *httptest.ResponseRecorder, expected int)
|
||||
}
|
||||
|
||||
// MockAuthMiddleware creates middleware that sets a test user in context
|
||||
func MockAuthMiddleware(user *models.User) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.Set("auth_user", user)
|
||||
c.Set("auth_token", "test-token")
|
||||
c.Next()
|
||||
func MockAuthMiddleware(user *models.User) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
c.Set("auth_user", user)
|
||||
c.Set("auth_token", "test-token")
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,3 +335,22 @@ func CreateTestDocument(t *testing.T, db *gorm.DB, residenceID, createdByID uint
|
||||
require.NoError(t, err)
|
||||
return doc
|
||||
}
|
||||
|
||||
// AssertAppError asserts that an error is an AppError with a specific status code and message key
|
||||
func AssertAppError(t *testing.T, err error, expectedCode int, expectedMessageKey string) {
|
||||
require.Error(t, err, "expected an error")
|
||||
|
||||
var appErr *apperrors.AppError
|
||||
require.ErrorAs(t, err, &appErr, "expected an AppError")
|
||||
require.Equal(t, expectedCode, appErr.Code, "unexpected status code")
|
||||
require.Equal(t, expectedMessageKey, appErr.MessageKey, "unexpected message key")
|
||||
}
|
||||
|
||||
// AssertAppErrorCode asserts that an error is an AppError with a specific status code
|
||||
func AssertAppErrorCode(t *testing.T, err error, expectedCode int) {
|
||||
require.Error(t, err, "expected an error")
|
||||
|
||||
var appErr *apperrors.AppError
|
||||
require.ErrorAs(t, err, &appErr, "expected an AppError")
|
||||
require.Equal(t, expectedCode, appErr.Code, "unexpected status code")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user