From 16a9ff7ffe60e4c076475407538a9d46a96a66f3 Mon Sep 17 00:00:00 2001 From: Tiago Yamamoto Date: Sat, 20 Dec 2025 08:21:25 -0300 Subject: [PATCH] test(handler): expand handler test coverage 6.6% -> 44.9% Added 40+ new handler tests covering: - Auth: Register, Login (invalid JSON, missing company) - Company: Get, Update, Delete, Verify, Rating, MyCompany - Product: Get, Update, Delete (not found, invalid UUID) - Inventory: List, Adjust (invalid params) - Order: Create, Get, Update, Delete (validation) - Payment: Preference, Webhook, Shipment - Dashboard: Seller, Admin (authorization) - User: CRUD operations (admin/seller scoping) - Cart: Add, Get, Delete (context validation) - Review: Create (validation) Fixed MockRepository to return errors for not found entities --- backend/internal/http/handler/handler_test.go | 422 +++++++++++++++++- 1 file changed, 418 insertions(+), 4 deletions(-) diff --git a/backend/internal/http/handler/handler_test.go b/backend/internal/http/handler/handler_test.go index be42db7..070b7b8 100644 --- a/backend/internal/http/handler/handler_test.go +++ b/backend/internal/http/handler/handler_test.go @@ -52,7 +52,7 @@ func (m *MockRepository) GetCompany(ctx context.Context, id uuid.UUID) (*domain. return &c, nil } } - return nil, nil + return nil, errors.New("company not found") } func (m *MockRepository) UpdateCompany(ctx context.Context, company *domain.Company) error { @@ -95,7 +95,7 @@ func (m *MockRepository) GetProduct(ctx context.Context, id uuid.UUID) (*domain. return &p, nil } } - return nil, nil + return nil, errors.New("product not found") } func (m *MockRepository) UpdateProduct(ctx context.Context, product *domain.Product) error { @@ -144,7 +144,7 @@ func (m *MockRepository) GetOrder(ctx context.Context, id uuid.UUID) (*domain.Or return &o, nil } } - return nil, nil + return nil, errors.New("order not found") } func (m *MockRepository) UpdateOrderStatus(ctx context.Context, id uuid.UUID, status domain.OrderStatus) error { @@ -180,7 +180,7 @@ func (m *MockRepository) GetUser(ctx context.Context, id uuid.UUID) (*domain.Use return &u, nil } } - return nil, nil + return nil, errors.New("user not found") } func (m *MockRepository) GetUserByEmail(ctx context.Context, email string) (*domain.User, error) { @@ -338,3 +338,417 @@ func TestListOrders(t *testing.T) { t.Errorf("expected status %d, got %d", http.StatusOK, rec.Code) } } + +// --- Auth Handler Tests --- + +func TestLogin_InvalidJSON(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewReader([]byte("invalid"))) + rec := httptest.NewRecorder() + h.Login(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestRegister_InvalidJSON(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/register", bytes.NewReader([]byte("{"))) + rec := httptest.NewRecorder() + h.Register(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestRegister_MissingCompany(t *testing.T) { + h := newTestHandler() + payload := `{"role":"admin","name":"Test","email":"test@test.com","password":"pass123"}` + req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/register", bytes.NewReader([]byte(payload))) + rec := httptest.NewRecorder() + h.Register(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +// --- Company Handler Tests --- + +func TestGetCompany_NotFound(t *testing.T) { + h := newTestHandler() + id, _ := uuid.NewV4() + req := httptest.NewRequest(http.MethodGet, "/api/v1/companies/"+id.String(), nil) + rec := httptest.NewRecorder() + h.GetCompany(rec, req) + if rec.Code != http.StatusNotFound { + t.Errorf("expected %d, got %d", http.StatusNotFound, rec.Code) + } +} + +func TestGetCompany_InvalidUUID(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodGet, "/api/v1/companies/invalid", nil) + rec := httptest.NewRecorder() + h.GetCompany(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestUpdateCompany_InvalidJSON(t *testing.T) { + h := newTestHandler() + id, _ := uuid.NewV4() + req := httptest.NewRequest(http.MethodPatch, "/api/v1/companies/"+id.String(), bytes.NewReader([]byte("{"))) + rec := httptest.NewRecorder() + h.UpdateCompany(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestDeleteCompany_InvalidUUID(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodDelete, "/api/v1/companies/invalid", nil) + rec := httptest.NewRecorder() + h.DeleteCompany(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestVerifyCompany_InvalidPath(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodPatch, "/api/v1/companies/something", nil) + rec := httptest.NewRecorder() + h.VerifyCompany(rec, req) + if rec.Code != http.StatusNotFound { + t.Errorf("expected %d, got %d", http.StatusNotFound, rec.Code) + } +} + +// --- Product Handler Tests --- + +func TestGetProduct_NotFound(t *testing.T) { + h := newTestHandler() + id, _ := uuid.NewV4() + req := httptest.NewRequest(http.MethodGet, "/api/v1/products/"+id.String(), nil) + rec := httptest.NewRecorder() + h.GetProduct(rec, req) + if rec.Code != http.StatusNotFound { + t.Errorf("expected %d, got %d", http.StatusNotFound, rec.Code) + } +} + +func TestUpdateProduct_InvalidJSON(t *testing.T) { + h := newTestHandler() + id, _ := uuid.NewV4() + req := httptest.NewRequest(http.MethodPatch, "/api/v1/products/"+id.String(), bytes.NewReader([]byte("{"))) + rec := httptest.NewRecorder() + h.UpdateProduct(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestDeleteProduct_InvalidUUID(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodDelete, "/api/v1/products/invalid", nil) + rec := httptest.NewRecorder() + h.DeleteProduct(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +// --- Inventory Handler Tests --- + +func TestListInventory_Success(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodGet, "/api/v1/inventory", nil) + rec := httptest.NewRecorder() + h.ListInventory(rec, req) + if rec.Code != http.StatusOK { + t.Errorf("expected %d, got %d", http.StatusOK, rec.Code) + } +} + +func TestListInventory_InvalidDays(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodGet, "/api/v1/inventory?expires_in_days=abc", nil) + rec := httptest.NewRecorder() + h.ListInventory(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestAdjustInventory_InvalidJSON(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodPost, "/api/v1/inventory/adjust", bytes.NewReader([]byte("{"))) + rec := httptest.NewRecorder() + h.AdjustInventory(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestAdjustInventory_ZeroDelta(t *testing.T) { + h := newTestHandler() + id, _ := uuid.NewV4() + payload := `{"product_id":"` + id.String() + `","delta":0,"reason":"test"}` + req := httptest.NewRequest(http.MethodPost, "/api/v1/inventory/adjust", bytes.NewReader([]byte(payload))) + rec := httptest.NewRecorder() + h.AdjustInventory(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +// --- Order Handler Tests --- + +func TestCreateOrder_InvalidJSON(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodPost, "/api/v1/orders", bytes.NewReader([]byte("{"))) + rec := httptest.NewRecorder() + h.CreateOrder(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestGetOrder_NotFound(t *testing.T) { + h := newTestHandler() + id, _ := uuid.NewV4() + req := httptest.NewRequest(http.MethodGet, "/api/v1/orders/"+id.String(), nil) + rec := httptest.NewRecorder() + h.GetOrder(rec, req) + if rec.Code != http.StatusNotFound { + t.Errorf("expected %d, got %d", http.StatusNotFound, rec.Code) + } +} + +func TestUpdateOrderStatus_InvalidStatus(t *testing.T) { + h := newTestHandler() + id, _ := uuid.NewV4() + payload := `{"status":"invalid_status"}` + req := httptest.NewRequest(http.MethodPatch, "/api/v1/orders/"+id.String()+"/status", bytes.NewReader([]byte(payload))) + rec := httptest.NewRecorder() + h.UpdateOrderStatus(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestDeleteOrder_InvalidUUID(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodDelete, "/api/v1/orders/invalid", nil) + rec := httptest.NewRecorder() + h.DeleteOrder(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +// --- Payment Handler Tests --- + +func TestCreatePaymentPreference_InvalidPath(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodPost, "/api/v1/orders/something/other", nil) + rec := httptest.NewRecorder() + h.CreatePaymentPreference(rec, req) + if rec.Code != http.StatusNotFound { + t.Errorf("expected %d, got %d", http.StatusNotFound, rec.Code) + } +} + +func TestHandlePaymentWebhook_InvalidJSON(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodPost, "/api/v1/payments/webhook", bytes.NewReader([]byte("{"))) + rec := httptest.NewRecorder() + h.HandlePaymentWebhook(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestCreateShipment_InvalidJSON(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodPost, "/api/v1/shipments", bytes.NewReader([]byte("{"))) + rec := httptest.NewRecorder() + h.CreateShipment(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestGetShipmentByOrderID_InvalidUUID(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodGet, "/api/v1/shipments/invalid", nil) + rec := httptest.NewRecorder() + h.GetShipmentByOrderID(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +// --- Dashboard Handler Tests --- + +func TestGetSellerDashboard_NoContext(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodGet, "/api/v1/dashboard/seller", nil) + rec := httptest.NewRecorder() + h.GetSellerDashboard(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestGetAdminDashboard_NotAdmin(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodGet, "/api/v1/dashboard/admin", nil) + req.Header.Set("X-User-Role", "Seller") + rec := httptest.NewRecorder() + h.GetAdminDashboard(rec, req) + if rec.Code != http.StatusForbidden { + t.Errorf("expected %d, got %d", http.StatusForbidden, rec.Code) + } +} + +func TestGetAdminDashboard_Success(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodGet, "/api/v1/dashboard/admin", nil) + req.Header.Set("X-User-Role", "Admin") + rec := httptest.NewRecorder() + h.GetAdminDashboard(rec, req) + if rec.Code != http.StatusOK { + t.Errorf("expected %d, got %d", http.StatusOK, rec.Code) + } +} + +// --- User Handler Tests --- + +func TestListUsers_Success(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodGet, "/api/v1/users", nil) + req.Header.Set("X-User-Role", "Admin") + rec := httptest.NewRecorder() + h.ListUsers(rec, req) + if rec.Code != http.StatusOK { + t.Errorf("expected %d, got %d", http.StatusOK, rec.Code) + } +} + +func TestGetUser_NotFound(t *testing.T) { + h := newTestHandler() + id, _ := uuid.NewV4() + req := httptest.NewRequest(http.MethodGet, "/api/v1/users/"+id.String(), nil) + req.Header.Set("X-User-Role", "Admin") + rec := httptest.NewRecorder() + h.GetUser(rec, req) + if rec.Code != http.StatusNotFound { + t.Errorf("expected %d, got %d", http.StatusNotFound, rec.Code) + } +} + +func TestCreateUser_InvalidJSON(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodPost, "/api/v1/users", bytes.NewReader([]byte("{"))) + req.Header.Set("X-User-Role", "Admin") + rec := httptest.NewRecorder() + h.CreateUser(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestUpdateUser_InvalidJSON(t *testing.T) { + h := newTestHandler() + id, _ := uuid.NewV4() + req := httptest.NewRequest(http.MethodPut, "/api/v1/users/"+id.String(), bytes.NewReader([]byte("{"))) + req.Header.Set("X-User-Role", "Admin") + rec := httptest.NewRecorder() + h.UpdateUser(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestDeleteUser_InvalidUUID(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodDelete, "/api/v1/users/invalid", nil) + req.Header.Set("X-User-Role", "Admin") + rec := httptest.NewRecorder() + h.DeleteUser(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +// --- Cart Handler Tests --- + +func TestGetCart_NoContext(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodGet, "/api/v1/cart", nil) + rec := httptest.NewRecorder() + h.GetCart(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestAddToCart_InvalidJSON(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodPost, "/api/v1/cart", bytes.NewReader([]byte("{"))) + rec := httptest.NewRecorder() + h.AddToCart(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +func TestDeleteCartItem_NoContext(t *testing.T) { + h := newTestHandler() + id, _ := uuid.NewV4() + req := httptest.NewRequest(http.MethodDelete, "/api/v1/cart/"+id.String(), nil) + rec := httptest.NewRecorder() + h.DeleteCartItem(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +// --- Review Handler Tests --- + +func TestCreateReview_InvalidJSON(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodPost, "/api/v1/reviews", bytes.NewReader([]byte("{"))) + rec := httptest.NewRecorder() + h.CreateReview(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +} + +// --- GetCompanyRating Handler Tests --- + +func TestGetCompanyRating_InvalidPath(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodGet, "/api/v1/companies/something", nil) + rec := httptest.NewRecorder() + h.GetCompanyRating(rec, req) + if rec.Code != http.StatusNotFound { + t.Errorf("expected %d, got %d", http.StatusNotFound, rec.Code) + } +} + +// --- GetMyCompany Handler Tests --- + +func TestGetMyCompany_NoContext(t *testing.T) { + h := newTestHandler() + req := httptest.NewRequest(http.MethodGet, "/api/v1/companies/me", nil) + rec := httptest.NewRecorder() + h.GetMyCompany(rec, req) + if rec.Code != http.StatusBadRequest { + t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code) + } +}