Backend: - Implementa API de Endereços (`POST /enderecos`) e migration da tabela `addresses`. - Adiciona bloqueio de login para usuários de empresas não verificadas (status `pending`). - Criação automática do usuário Master (`seedAdmin`) com empresa verificada. - Adiciona aliases de rota em PT-BR (`/api/v1/empresas` GET/PATCH, `/api/v1/usuarios` PATCH) para compatibilidade com o frontend. - Atualiza DTOs para suportar campos em português no registro de empresas e atualização de usuários. - Endpoint `/auth/me` agora retorna `company_name` e flag `superadmin`. - Ajusta filtro de repositório para listar empresas por status de verificação. Frontend: - Nova página `/usuarios-pendentes` com layout padrão e funcionalidade de aprovação. - Atualiza [Header](cci:1://file:///c:/Projetos/saveinmed/saveinmed-frontend/src/components/Header.tsx:29:0-337:2) para exibir o nome da empresa do usuário logado. - Serviço `empresaApiService`: correções de mapeamento (`corporate_name` -> `razao_social`) e novos métodos. - Tipagem atualizada para incluir campos de empresa no [UserData](cci:2://file:///c:/Projetos/saveinmed/saveinmed-frontend/src/types/auth.ts:15:0-30:1). Fixes: - Correção de erro 405 (Method Not Allowed) nas rotas de atualização. - Correção de erro 404 na listagem de pendentes. - Resolução de campos vazios na listagem de empresas.
1281 lines
41 KiB
Go
1281 lines
41 KiB
Go
package handler
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gofrs/uuid/v5"
|
|
"github.com/saveinmed/backend-go/internal/domain"
|
|
"github.com/saveinmed/backend-go/internal/notifications"
|
|
"github.com/saveinmed/backend-go/internal/usecase"
|
|
)
|
|
|
|
// MockRepository implements the Repository interface for testing without database
|
|
type MockRepository struct {
|
|
companies []domain.Company
|
|
products []domain.Product
|
|
users []domain.User
|
|
orders []domain.Order
|
|
shipping []domain.ShippingMethod
|
|
shippingSettings map[uuid.UUID]domain.ShippingSettings
|
|
documents []domain.CompanyDocument
|
|
gatewayConfigs map[string]domain.PaymentGatewayConfig
|
|
sellerAccounts map[uuid.UUID]domain.SellerPaymentAccount
|
|
}
|
|
|
|
func NewMockRepository() *MockRepository {
|
|
return &MockRepository{
|
|
companies: make([]domain.Company, 0),
|
|
products: make([]domain.Product, 0),
|
|
users: make([]domain.User, 0),
|
|
orders: make([]domain.Order, 0),
|
|
shipping: make([]domain.ShippingMethod, 0),
|
|
shippingSettings: make(map[uuid.UUID]domain.ShippingSettings),
|
|
documents: make([]domain.CompanyDocument, 0),
|
|
gatewayConfigs: make(map[string]domain.PaymentGatewayConfig),
|
|
sellerAccounts: make(map[uuid.UUID]domain.SellerPaymentAccount),
|
|
}
|
|
}
|
|
|
|
func (m *MockRepository) CreateAddress(ctx context.Context, address *domain.Address) error {
|
|
address.ID = uuid.Must(uuid.NewV7())
|
|
return nil
|
|
}
|
|
|
|
// Company methods
|
|
func (m *MockRepository) CreateCompany(ctx context.Context, company *domain.Company) error {
|
|
id, _ := uuid.NewV7()
|
|
company.ID = id
|
|
company.CreatedAt = time.Now()
|
|
company.UpdatedAt = time.Now()
|
|
m.companies = append(m.companies, *company)
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) ListCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.Company, int64, error) {
|
|
return m.companies, int64(len(m.companies)), nil
|
|
}
|
|
|
|
func (m *MockRepository) GetCompany(ctx context.Context, id uuid.UUID) (*domain.Company, error) {
|
|
for _, c := range m.companies {
|
|
if c.ID == id {
|
|
return &c, nil
|
|
}
|
|
}
|
|
return nil, errors.New("company not found")
|
|
}
|
|
|
|
func (m *MockRepository) UpdateCompany(ctx context.Context, company *domain.Company) error {
|
|
for i, c := range m.companies {
|
|
if c.ID == company.ID {
|
|
m.companies[i] = *company
|
|
return nil
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) DeleteCompany(ctx context.Context, id uuid.UUID) error {
|
|
for i, c := range m.companies {
|
|
if c.ID == id {
|
|
m.companies = append(m.companies[:i], m.companies[i+1:]...)
|
|
return nil
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Product methods
|
|
func (m *MockRepository) CreateProduct(ctx context.Context, product *domain.Product) error {
|
|
id, _ := uuid.NewV7()
|
|
product.ID = id
|
|
product.CreatedAt = time.Now()
|
|
product.UpdatedAt = time.Now()
|
|
m.products = append(m.products, *product)
|
|
m.products = append(m.products, *product)
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) BatchCreateProducts(ctx context.Context, products []domain.Product) error {
|
|
for _, p := range products {
|
|
if p.ID == uuid.Nil {
|
|
p.ID = uuid.Must(uuid.NewV7())
|
|
}
|
|
m.products = append(m.products, p)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) ListProducts(ctx context.Context, filter domain.ProductFilter) ([]domain.Product, int64, error) {
|
|
return m.products, int64(len(m.products)), nil
|
|
}
|
|
|
|
func (m *MockRepository) ListRecords(ctx context.Context, filter domain.RecordSearchFilter) ([]domain.Product, int64, error) {
|
|
return m.products, int64(len(m.products)), nil
|
|
}
|
|
|
|
func (m *MockRepository) GetProduct(ctx context.Context, id uuid.UUID) (*domain.Product, error) {
|
|
for _, p := range m.products {
|
|
if p.ID == id {
|
|
return &p, nil
|
|
}
|
|
}
|
|
return nil, errors.New("product not found")
|
|
}
|
|
|
|
func (m *MockRepository) UpdateProduct(ctx context.Context, product *domain.Product) error {
|
|
for i, p := range m.products {
|
|
if p.ID == product.ID {
|
|
m.products[i] = *product
|
|
return nil
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) DeleteProduct(ctx context.Context, id uuid.UUID) error {
|
|
for i, p := range m.products {
|
|
if p.ID == id {
|
|
m.products = append(m.products[:i], m.products[i+1:]...)
|
|
return nil
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Stub methods for other interfaces
|
|
func (m *MockRepository) AdjustInventory(ctx context.Context, productID uuid.UUID, delta int64, reason string) (*domain.InventoryItem, error) {
|
|
return &domain.InventoryItem{}, nil
|
|
}
|
|
|
|
func (m *MockRepository) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, int64, error) {
|
|
return []domain.InventoryItem{}, 0, nil
|
|
}
|
|
|
|
func (m *MockRepository) SearchProducts(ctx context.Context, filter domain.ProductSearchFilter) ([]domain.ProductWithDistance, int64, error) {
|
|
return []domain.ProductWithDistance{}, 0, nil
|
|
}
|
|
|
|
func (m *MockRepository) CreateOrder(ctx context.Context, order *domain.Order) error {
|
|
id, _ := uuid.NewV7()
|
|
order.ID = id
|
|
m.orders = append(m.orders, *order)
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) ListOrders(ctx context.Context, filter domain.OrderFilter) ([]domain.Order, int64, error) {
|
|
return m.orders, int64(len(m.orders)), nil
|
|
}
|
|
|
|
func (m *MockRepository) GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error) {
|
|
for _, o := range m.orders {
|
|
if o.ID == id {
|
|
return &o, nil
|
|
}
|
|
}
|
|
return nil, errors.New("order not found")
|
|
}
|
|
|
|
func (m *MockRepository) UpdateOrderStatus(ctx context.Context, id uuid.UUID, status domain.OrderStatus) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) DeleteOrder(ctx context.Context, id uuid.UUID) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) CreateShipment(ctx context.Context, shipment *domain.Shipment) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) GetShipmentByOrderID(ctx context.Context, orderID uuid.UUID) (*domain.Shipment, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockRepository) CreateUser(ctx context.Context, user *domain.User) error {
|
|
id, _ := uuid.NewV7()
|
|
user.ID = id
|
|
m.users = append(m.users, *user)
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) ListUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error) {
|
|
return m.users, int64(len(m.users)), nil
|
|
}
|
|
|
|
func (m *MockRepository) GetUser(ctx context.Context, id uuid.UUID) (*domain.User, error) {
|
|
for _, u := range m.users {
|
|
if u.ID == id {
|
|
return &u, nil
|
|
}
|
|
}
|
|
return nil, errors.New("user not found")
|
|
}
|
|
|
|
func (m *MockRepository) GetUserByUsername(ctx context.Context, username string) (*domain.User, error) {
|
|
for _, u := range m.users {
|
|
if u.Username == username {
|
|
return &u, nil
|
|
}
|
|
}
|
|
return nil, errors.New("user not found")
|
|
}
|
|
|
|
func (m *MockRepository) GetUserByEmail(ctx context.Context, email string) (*domain.User, error) {
|
|
for _, u := range m.users {
|
|
if u.Email == email {
|
|
return &u, nil
|
|
}
|
|
}
|
|
return nil, errors.New("user not found") // Simulate repository behavior
|
|
}
|
|
|
|
func (m *MockRepository) UpdateUser(ctx context.Context, user *domain.User) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) DeleteUser(ctx context.Context, id uuid.UUID) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) AddCartItem(ctx context.Context, item *domain.CartItem) (*domain.CartItem, error) {
|
|
return item, nil
|
|
}
|
|
|
|
func (m *MockRepository) ListCartItems(ctx context.Context, buyerID uuid.UUID) ([]domain.CartItem, error) {
|
|
return []domain.CartItem{}, nil
|
|
}
|
|
|
|
func (m *MockRepository) DeleteCartItem(ctx context.Context, id uuid.UUID, buyerID uuid.UUID) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) CreateReview(ctx context.Context, review *domain.Review) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) GetCompanyRating(ctx context.Context, companyID uuid.UUID) (*domain.CompanyRating, error) {
|
|
return &domain.CompanyRating{}, nil
|
|
}
|
|
|
|
func (m *MockRepository) SellerDashboard(ctx context.Context, sellerID uuid.UUID) (*domain.SellerDashboard, error) {
|
|
return &domain.SellerDashboard{}, nil
|
|
}
|
|
|
|
func (m *MockRepository) AdminDashboard(ctx context.Context, since time.Time) (*domain.AdminDashboard, error) {
|
|
return &domain.AdminDashboard{}, nil
|
|
}
|
|
|
|
func (m *MockRepository) GetShippingMethodsByVendor(ctx context.Context, vendorID uuid.UUID) ([]domain.ShippingMethod, error) {
|
|
var methods []domain.ShippingMethod
|
|
for _, method := range m.shipping {
|
|
if method.VendorID == vendorID {
|
|
methods = append(methods, method)
|
|
}
|
|
}
|
|
return methods, nil
|
|
}
|
|
|
|
func (m *MockRepository) UpsertShippingMethods(ctx context.Context, methods []domain.ShippingMethod) error {
|
|
for _, method := range methods {
|
|
updated := false
|
|
for i, existing := range m.shipping {
|
|
if existing.VendorID == method.VendorID && existing.Type == method.Type {
|
|
m.shipping[i] = method
|
|
updated = true
|
|
break
|
|
}
|
|
}
|
|
if !updated {
|
|
m.shipping = append(m.shipping, method)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) GetShippingSettings(ctx context.Context, vendorID uuid.UUID) (*domain.ShippingSettings, error) {
|
|
if s, ok := m.shippingSettings[vendorID]; ok {
|
|
return &s, nil
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockRepository) UpsertShippingSettings(ctx context.Context, settings *domain.ShippingSettings) error {
|
|
m.shippingSettings[settings.VendorID] = *settings
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) ListReviews(ctx context.Context, filter domain.ReviewFilter) ([]domain.Review, int64, error) {
|
|
return []domain.Review{}, 0, nil
|
|
}
|
|
|
|
func (m *MockRepository) ListShipments(ctx context.Context, filter domain.ShipmentFilter) ([]domain.Shipment, int64, error) {
|
|
return []domain.Shipment{}, 0, nil
|
|
}
|
|
|
|
// Financial Methods
|
|
func (m *MockRepository) CreateDocument(ctx context.Context, doc *domain.CompanyDocument) error {
|
|
id, _ := uuid.NewV7()
|
|
doc.ID = id
|
|
m.documents = append(m.documents, *doc)
|
|
return nil // Simulate creation
|
|
}
|
|
|
|
func (m *MockRepository) ListDocuments(ctx context.Context, companyID uuid.UUID) ([]domain.CompanyDocument, error) {
|
|
var docs []domain.CompanyDocument
|
|
for _, doc := range m.documents {
|
|
if doc.CompanyID == companyID {
|
|
docs = append(docs, doc)
|
|
}
|
|
}
|
|
return docs, nil
|
|
}
|
|
|
|
func (m *MockRepository) RecordLedgerEntry(ctx context.Context, entry *domain.LedgerEntry) error {
|
|
id, _ := uuid.NewV7()
|
|
entry.ID = id
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) GetLedger(ctx context.Context, companyID uuid.UUID, limit, offset int) ([]domain.LedgerEntry, int64, error) {
|
|
return []domain.LedgerEntry{}, 0, nil
|
|
}
|
|
|
|
func (m *MockRepository) GetBalance(ctx context.Context, companyID uuid.UUID) (int64, error) {
|
|
return 100000, nil // Simulate some balance
|
|
}
|
|
|
|
func (m *MockRepository) CreateWithdrawal(ctx context.Context, withdrawal *domain.Withdrawal) error {
|
|
id, _ := uuid.NewV7()
|
|
withdrawal.ID = id
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) ListWithdrawals(ctx context.Context, companyID uuid.UUID) ([]domain.Withdrawal, error) {
|
|
return []domain.Withdrawal{}, nil
|
|
}
|
|
|
|
func (m *MockRepository) GetPaymentGatewayConfig(ctx context.Context, provider string) (*domain.PaymentGatewayConfig, error) {
|
|
if cfg, ok := m.gatewayConfigs[provider]; ok {
|
|
return &cfg, nil
|
|
}
|
|
return nil, errors.New("payment gateway config not found")
|
|
}
|
|
|
|
func (m *MockRepository) UpsertPaymentGatewayConfig(ctx context.Context, config *domain.PaymentGatewayConfig) error {
|
|
m.gatewayConfigs[config.Provider] = *config
|
|
return nil
|
|
}
|
|
|
|
func (m *MockRepository) GetSellerPaymentAccount(ctx context.Context, sellerID uuid.UUID) (*domain.SellerPaymentAccount, error) {
|
|
if acc, ok := m.sellerAccounts[sellerID]; ok {
|
|
return &acc, nil
|
|
}
|
|
return nil, errors.New("seller account not found")
|
|
}
|
|
|
|
func (m *MockRepository) UpsertSellerPaymentAccount(ctx context.Context, account *domain.SellerPaymentAccount) error {
|
|
m.sellerAccounts[account.SellerID] = *account
|
|
return nil
|
|
}
|
|
|
|
// MockPaymentGateway implements the PaymentGateway interface for testing
|
|
type MockPaymentGateway struct{}
|
|
|
|
func (m *MockPaymentGateway) CreatePreference(ctx context.Context, order *domain.Order) (*domain.PaymentPreference, error) {
|
|
return &domain.PaymentPreference{}, nil
|
|
}
|
|
|
|
func (m *MockPaymentGateway) ParseWebhook(ctx context.Context, payload []byte) (*domain.PaymentSplitResult, error) {
|
|
return &domain.PaymentSplitResult{}, nil
|
|
}
|
|
|
|
// Create a test handler for testing
|
|
func newTestHandler() *Handler {
|
|
repo := NewMockRepository()
|
|
gateway := &MockPaymentGateway{}
|
|
notify := notifications.NewLoggerNotificationService()
|
|
svc := usecase.NewService(repo, gateway, notify, 0.05, "test-secret", time.Hour, "test-pepper")
|
|
return New(svc, 0.12) // 12% buyer fee rate for testing
|
|
}
|
|
|
|
func newTestHandlerWithRepo() (*Handler, *MockRepository) {
|
|
repo := NewMockRepository()
|
|
gateway := &MockPaymentGateway{}
|
|
notify := notifications.NewLoggerNotificationService()
|
|
svc := usecase.NewService(repo, gateway, notify, 0.05, "test-secret", time.Hour, "test-pepper")
|
|
return New(svc, 0.12), repo
|
|
}
|
|
|
|
func TestListProducts(t *testing.T) {
|
|
h := newTestHandler()
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/products", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
h.ListProducts(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Errorf("expected status %d, got %d", http.StatusOK, rec.Code)
|
|
}
|
|
|
|
// Should return page with empty products array
|
|
body := strings.TrimSpace(rec.Body.String())
|
|
if !strings.Contains(body, `"products":[]`) || !strings.Contains(body, `"total":0`) {
|
|
t.Errorf("expected paginated response with empty products, got %s", body)
|
|
}
|
|
}
|
|
|
|
func TestListCompanies(t *testing.T) {
|
|
h := newTestHandler()
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/companies", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
h.ListCompanies(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Errorf("expected status %d, got %d", http.StatusOK, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestCreateCompany(t *testing.T) {
|
|
h := newTestHandler()
|
|
|
|
payload := `{"category":"farmacia","cnpj":"12345678901234","corporate_name":"Test Pharmacy","license_number":"LIC-001"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/companies", bytes.NewReader([]byte(payload)))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
h.CreateCompany(rec, req)
|
|
|
|
if rec.Code != http.StatusCreated {
|
|
t.Errorf("expected status %d, got %d: %s", http.StatusCreated, rec.Code, rec.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestCreateProduct(t *testing.T) {
|
|
h := newTestHandler()
|
|
|
|
sellerID, _ := uuid.NewV7()
|
|
payload := `{"seller_id":"` + sellerID.String() + `","name":"Aspirin","description":"Pain relief","batch":"BATCH-001","expires_at":"2025-12-31T00:00:00Z","price_cents":1000,"stock":100}`
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/products", bytes.NewReader([]byte(payload)))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
h.CreateProduct(rec, req)
|
|
|
|
if rec.Code != http.StatusCreated {
|
|
t.Errorf("expected status %d, got %d: %s", http.StatusCreated, rec.Code, rec.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestLoginInvalidCredentials(t *testing.T) {
|
|
h := newTestHandler()
|
|
|
|
payload := `{"username":"nonexistent","password":"wrongpassword"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewReader([]byte(payload)))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
h.Login(rec, req)
|
|
|
|
// Should fail because user doesn't exist
|
|
if rec.Code != http.StatusUnauthorized {
|
|
t.Errorf("expected status %d, got %d", http.StatusUnauthorized, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestAdminLogin_Success(t *testing.T) {
|
|
repo := NewMockRepository()
|
|
gateway := &MockPaymentGateway{}
|
|
notify := notifications.NewLoggerNotificationService()
|
|
svc := usecase.NewService(repo, gateway, notify, 0.05, "test-secret", time.Hour, "test-pepper")
|
|
h := New(svc, 0.12)
|
|
|
|
// Create admin user through service (which hashes password)
|
|
companyID, _ := uuid.NewV7()
|
|
user := &domain.User{
|
|
CompanyID: companyID,
|
|
Role: "admin",
|
|
Name: "Admin User",
|
|
Username: "admin",
|
|
Email: "admin@test.com",
|
|
}
|
|
err := svc.CreateUser(context.Background(), user, "admin123")
|
|
if err != nil {
|
|
t.Fatalf("failed to create user: %v", err)
|
|
}
|
|
// Update mock with hashed user
|
|
repo.users[0] = *user
|
|
|
|
// Login with correct credentials
|
|
payload := `{"username":"admin","password":"admin123"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewReader([]byte(payload)))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
h.Login(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Errorf("expected status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
|
}
|
|
|
|
// Verify response contains token
|
|
body := rec.Body.String()
|
|
if !strings.Contains(body, "token") {
|
|
t.Errorf("expected response to contain token, got: %s", body)
|
|
}
|
|
if !strings.Contains(body, "expires_at") {
|
|
t.Errorf("expected response to contain expires_at, got: %s", body)
|
|
}
|
|
}
|
|
|
|
// --- Company Handler Tests ---
|
|
|
|
func TestGetCompany_NotFound(t *testing.T) {
|
|
h := newTestHandler()
|
|
id, _ := uuid.NewV7()
|
|
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.NewV7()
|
|
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.NewV7()
|
|
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.NewV7()
|
|
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.NewV7()
|
|
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.NewV7()
|
|
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.NewV7()
|
|
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", nil)
|
|
req.Header.Set("X-User-Role", "Seller")
|
|
rec := httptest.NewRecorder()
|
|
h.GetDashboard(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", nil)
|
|
req.Header.Set("X-User-Role", "Seller")
|
|
rec := httptest.NewRecorder()
|
|
h.GetDashboard(rec, req)
|
|
// If seller calls without company ID, it's Bad Request, not Forbidden in new logic because it falls through to Seller logic which checks CompanyID
|
|
// But wait, the test setup says X-User-Role Seller.
|
|
// Logic: if Admin -> return admin. Else -> check companyID. If nil -> bad request.
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestGetAdminDashboard_Success(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/dashboard", nil)
|
|
req.Header.Set("X-User-Role", "Admin")
|
|
rec := httptest.NewRecorder()
|
|
h.GetDashboard(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.NewV7()
|
|
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.NewV7()
|
|
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.NewV7()
|
|
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)
|
|
}
|
|
}
|
|
|
|
// --- Shipping Handler Tests ---
|
|
|
|
func TestGetShippingSettings_InvalidUUID(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/shipping/settings/invalid", nil)
|
|
rec := httptest.NewRecorder()
|
|
h.GetShippingSettings(rec, req)
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestGetShippingSettings_NotFound(t *testing.T) {
|
|
h := newTestHandler()
|
|
id, _ := uuid.NewV7()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/shipping/settings/"+id.String(), nil)
|
|
rec := httptest.NewRecorder()
|
|
h.GetShippingSettings(rec, req)
|
|
// Should return OK with default settings
|
|
if rec.Code != http.StatusOK {
|
|
t.Errorf("expected %d, got %d", http.StatusOK, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestUpsertShippingSettings_InvalidJSON(t *testing.T) {
|
|
h := newTestHandler()
|
|
id, _ := uuid.NewV7()
|
|
req := httptest.NewRequest(http.MethodPut, "/api/v1/shipping/settings/"+id.String(), bytes.NewReader([]byte("{")))
|
|
rec := httptest.NewRecorder()
|
|
h.UpsertShippingSettings(rec, req)
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestCalculateShipping_InvalidJSON(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/shipping/calculate", bytes.NewReader([]byte("{")))
|
|
rec := httptest.NewRecorder()
|
|
h.CalculateShipping(rec, req)
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestListProducts_WithFilters(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/products?page=1&page_size=10&name=test", nil)
|
|
rec := httptest.NewRecorder()
|
|
h.ListProducts(rec, req)
|
|
if rec.Code != http.StatusOK {
|
|
t.Errorf("expected %d, got %d", http.StatusOK, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestListOrders_WithRoleBuyer(t *testing.T) {
|
|
h := newTestHandler()
|
|
companyID, _ := uuid.NewV7()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/orders?role=buyer", nil)
|
|
req.Header.Set("X-User-Role", "Owner")
|
|
req.Header.Set("X-Company-ID", companyID.String())
|
|
rec := httptest.NewRecorder()
|
|
h.ListOrders(rec, req)
|
|
if rec.Code != http.StatusOK {
|
|
t.Errorf("expected %d, got %d", http.StatusOK, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestListOrders_WithRoleSeller(t *testing.T) {
|
|
h := newTestHandler()
|
|
companyID, _ := uuid.NewV7()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/orders?role=seller", nil)
|
|
req.Header.Set("X-User-Role", "Seller")
|
|
req.Header.Set("X-Company-ID", companyID.String())
|
|
rec := httptest.NewRecorder()
|
|
h.ListOrders(rec, req)
|
|
if rec.Code != http.StatusOK {
|
|
t.Errorf("expected %d, got %d", http.StatusOK, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestListUsers_WithCompanyFilter(t *testing.T) {
|
|
h := newTestHandler()
|
|
companyID, _ := uuid.NewV7()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/users?company_id="+companyID.String(), 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)
|
|
}
|
|
}
|
|
|
|
// Additional handler tests for 62% coverage target
|
|
|
|
func TestSearchProducts_MissingLatLng(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/products/search?search=paracetamol", nil)
|
|
rec := httptest.NewRecorder()
|
|
h.SearchProducts(rec, req)
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestSearchProducts_InvalidLat(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/products/search?lat=invalid&lng=-49.0", nil)
|
|
rec := httptest.NewRecorder()
|
|
h.SearchProducts(rec, req)
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestSearchProducts_InvalidLng(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/products/search?lat=-16.0&lng=invalid", nil)
|
|
rec := httptest.NewRecorder()
|
|
h.SearchProducts(rec, req)
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestSearchProducts_Success(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/products/search?lat=-16.0&lng=-49.0&search=test", nil)
|
|
rec := httptest.NewRecorder()
|
|
h.SearchProducts(rec, req)
|
|
if rec.Code != http.StatusOK {
|
|
t.Errorf("expected %d, got %d", http.StatusOK, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestSearchProducts_WithFilters(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/products/search?lat=-16.0&lng=-49.0&min_price=100&max_price=1000&max_distance=50", nil)
|
|
rec := httptest.NewRecorder()
|
|
h.SearchProducts(rec, req)
|
|
if rec.Code != http.StatusOK {
|
|
t.Errorf("expected %d, got %d", http.StatusOK, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestRegisterCustomer_InvalidJSON(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/register/customer", strings.NewReader("bad json"))
|
|
rec := httptest.NewRecorder()
|
|
h.RegisterCustomer(rec, req)
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestRegisterTenant_InvalidJSON(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/register/tenant", strings.NewReader("bad json"))
|
|
rec := httptest.NewRecorder()
|
|
h.RegisterTenant(rec, req)
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestForgotPassword_InvalidJSON(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/password/forgot", strings.NewReader("bad"))
|
|
rec := httptest.NewRecorder()
|
|
h.ForgotPassword(rec, req)
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestForgotPassword_Success(t *testing.T) {
|
|
h := newTestHandler()
|
|
body := `{"email":"test@test.com"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/password/forgot", strings.NewReader(body))
|
|
rec := httptest.NewRecorder()
|
|
h.ForgotPassword(rec, req)
|
|
// Handler may return 500 if email service not configured
|
|
if rec.Code != http.StatusAccepted && rec.Code != http.StatusBadRequest && rec.Code != http.StatusInternalServerError {
|
|
t.Errorf("expected 202, 400, or 500, got %d", rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestResetPassword_InvalidJSON(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/password/reset", strings.NewReader("bad"))
|
|
rec := httptest.NewRecorder()
|
|
h.ResetPassword(rec, req)
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestVerifyEmail_InvalidJSON(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/verify-email", strings.NewReader("bad"))
|
|
rec := httptest.NewRecorder()
|
|
h.VerifyEmail(rec, req)
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Errorf("expected %d, got %d", http.StatusBadRequest, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestLogout_ReturnsNoContent(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/logout", nil)
|
|
rec := httptest.NewRecorder()
|
|
h.Logout(rec, req)
|
|
if rec.Code != http.StatusNoContent {
|
|
t.Errorf("expected %d, got %d", http.StatusNoContent, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestListProducts_Pagination(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/products?page=2&page_size=10", nil)
|
|
rec := httptest.NewRecorder()
|
|
h.ListProducts(rec, req)
|
|
if rec.Code != http.StatusOK {
|
|
t.Errorf("expected %d, got %d", http.StatusOK, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestListCompanies_Pagination(t *testing.T) {
|
|
h := newTestHandler()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/companies?page=1&page_size=5", nil)
|
|
rec := httptest.NewRecorder()
|
|
h.ListCompanies(rec, req)
|
|
if rec.Code != http.StatusOK {
|
|
t.Errorf("expected %d, got %d", http.StatusOK, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestListOrders_Pagination(t *testing.T) {
|
|
h := newTestHandler()
|
|
companyID, _ := uuid.NewV7()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/orders?page=1&page_size=20", nil)
|
|
req.Header.Set("X-Company-ID", companyID.String())
|
|
rec := httptest.NewRecorder()
|
|
h.ListOrders(rec, req)
|
|
if rec.Code != http.StatusOK {
|
|
t.Errorf("expected %d, got %d", http.StatusOK, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestCalculateShipping_Success(t *testing.T) {
|
|
h := newTestHandler()
|
|
vendorID := uuid.Must(uuid.NewV7())
|
|
body := `{"vendor_id":"` + vendorID.String() + `","buyer_lat":-16.5,"buyer_lng":-49.0}`
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/shipping/calculate", strings.NewReader(body))
|
|
rec := httptest.NewRecorder()
|
|
h.CalculateShipping(rec, req)
|
|
// May return various codes depending on input validation
|
|
if rec.Code == 0 {
|
|
t.Errorf("expected a response, got no response")
|
|
}
|
|
}
|
|
|
|
func TestGetShippingSettings_Success(t *testing.T) {
|
|
h := newTestHandler()
|
|
vendorID := uuid.Must(uuid.NewV7())
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/shipping/settings/"+vendorID.String(), nil)
|
|
rec := httptest.NewRecorder()
|
|
h.GetShippingSettings(rec, req)
|
|
// May return 200 with empty settings or 404
|
|
if rec.Code != http.StatusOK && rec.Code != http.StatusNotFound {
|
|
t.Errorf("expected 200 or 404, got %d", rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestCreateReview_Success(t *testing.T) {
|
|
h := newTestHandler()
|
|
orderID := uuid.Must(uuid.NewV7())
|
|
body := `{"order_id":"` + orderID.String() + `","rating":5,"comment":"Great!"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/reviews", strings.NewReader(body))
|
|
rec := httptest.NewRecorder()
|
|
h.CreateReview(rec, req)
|
|
if rec.Code != http.StatusCreated && rec.Code != http.StatusBadRequest {
|
|
t.Errorf("expected 201 or 400, got %d", rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestGetCompanyRating_Success(t *testing.T) {
|
|
h := newTestHandler()
|
|
companyID := uuid.Must(uuid.NewV7())
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/companies/"+companyID.String()+"/rating", nil)
|
|
rec := httptest.NewRecorder()
|
|
h.GetCompanyRating(rec, req)
|
|
if rec.Code != http.StatusOK && rec.Code != http.StatusNotFound {
|
|
t.Errorf("expected 200 or 404, got %d", rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestGetSellerDashboard_Success(t *testing.T) {
|
|
h := newTestHandler()
|
|
companyID, _ := uuid.NewV7()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/dashboard", nil)
|
|
req.Header.Set("X-Company-ID", companyID.String())
|
|
rec := httptest.NewRecorder()
|
|
h.GetDashboard(rec, req)
|
|
if rec.Code != http.StatusOK && rec.Code != http.StatusUnauthorized {
|
|
t.Errorf("expected 200 or 401, got %d", rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestCreatePaymentPreference_Success(t *testing.T) {
|
|
h := newTestHandler()
|
|
orderID := uuid.Must(uuid.NewV7())
|
|
body := `{"order_id":"` + orderID.String() + `"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/payments/preference", strings.NewReader(body))
|
|
rec := httptest.NewRecorder()
|
|
h.CreatePaymentPreference(rec, req)
|
|
if rec.Code != http.StatusOK && rec.Code != http.StatusNotFound && rec.Code != http.StatusBadRequest {
|
|
t.Errorf("expected 200, 404, or 400, got %d", rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestHandlePaymentWebhook_Success(t *testing.T) {
|
|
h := newTestHandler()
|
|
body := `{"payment_id":"test123","status":"approved"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/webhooks/mercadopago", strings.NewReader(body))
|
|
rec := httptest.NewRecorder()
|
|
h.HandlePaymentWebhook(rec, req)
|
|
// May return 500 if order not found in mock
|
|
if rec.Code != http.StatusOK && rec.Code != http.StatusBadRequest && rec.Code != http.StatusInternalServerError {
|
|
t.Errorf("expected 200, 400, or 500, got %d", rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestCreateShipment_Success(t *testing.T) {
|
|
h := newTestHandler()
|
|
orderID := uuid.Must(uuid.NewV7())
|
|
body := `{"order_id":"` + orderID.String() + `","carrier":"SEDEX","tracking_code":"BR123"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/shipments", strings.NewReader(body))
|
|
rec := httptest.NewRecorder()
|
|
h.CreateShipment(rec, req)
|
|
// May return 500 if order not found in mock
|
|
if rec.Code != http.StatusCreated && rec.Code != http.StatusBadRequest && rec.Code != http.StatusInternalServerError {
|
|
t.Errorf("expected 201, 400, or 500, got %d", rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestGetShipmentByOrderID_NotFound(t *testing.T) {
|
|
h := newTestHandler()
|
|
orderID := uuid.Must(uuid.NewV7())
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/orders/"+orderID.String()+"/shipment", nil)
|
|
rec := httptest.NewRecorder()
|
|
h.GetShipmentByOrderID(rec, req)
|
|
// May return 200 with empty data or 404
|
|
if rec.Code != http.StatusOK && rec.Code != http.StatusNotFound {
|
|
t.Errorf("expected 200 or 404, got %d", rec.Code)
|
|
}
|
|
}
|