From c48666bf60eff9f3f2d58a482f055c2ea735b4c3 Mon Sep 17 00:00:00 2001 From: Tiago Yamamoto Date: Thu, 1 Jan 2026 15:06:55 -0300 Subject: [PATCH] Add backend and frontend test coverage --- backend/internal/domain/distance_test.go | 17 +++ backend/internal/usecase/usecase_test.go | 107 ++++++++++++++++ .../src/services/financialService.test.ts | 118 ++++++++++++++++++ 3 files changed, 242 insertions(+) create mode 100644 backend/internal/domain/distance_test.go create mode 100644 marketplace/src/services/financialService.test.ts diff --git a/backend/internal/domain/distance_test.go b/backend/internal/domain/distance_test.go new file mode 100644 index 0000000..b5ac6da --- /dev/null +++ b/backend/internal/domain/distance_test.go @@ -0,0 +1,17 @@ +package domain + +import "testing" + +func TestHaversineDistanceZero(t *testing.T) { + distance := HaversineDistance(-23.55, -46.63, -23.55, -46.63) + if distance != 0 { + t.Fatalf("expected zero distance, got %v", distance) + } +} + +func TestHaversineDistanceApproximate(t *testing.T) { + distance := HaversineDistance(0, 0, 0, 1) + if distance < 110 || distance > 112 { + t.Fatalf("expected distance around 111km, got %v", distance) + } +} diff --git a/backend/internal/usecase/usecase_test.go b/backend/internal/usecase/usecase_test.go index 86dfe3c..9aaf340 100644 --- a/backend/internal/usecase/usecase_test.go +++ b/backend/internal/usecase/usecase_test.go @@ -1079,6 +1079,113 @@ func TestGetAdminDashboard(t *testing.T) { } } +// --- Shipping Options Tests --- + +func TestCalculateShippingOptionsVendorNotFound(t *testing.T) { + svc, _ := newTestService() + + _, err := svc.CalculateShippingOptions(context.Background(), uuid.Must(uuid.NewV7()), -23.55, -46.63, 0) + if err == nil { + t.Fatal("expected error for missing vendor") + } +} + +func TestCalculateShippingOptionsNoSettings(t *testing.T) { + svc, repo := newTestService() + ctx := context.Background() + vendorID := uuid.Must(uuid.NewV7()) + + err := repo.CreateCompany(ctx, &domain.Company{ + ID: vendorID, + CorporateName: "Farmácia Central", + Latitude: -23.55, + Longitude: -46.63, + }) + if err != nil { + t.Fatalf("failed to create company: %v", err) + } + + options, err := svc.CalculateShippingOptions(ctx, vendorID, -23.55, -46.63, 0) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(options) != 0 { + t.Fatalf("expected no options, got %d", len(options)) + } +} + +func TestCalculateShippingOptionsDeliveryAndPickup(t *testing.T) { + svc, repo := newTestService() + ctx := context.Background() + vendorID := uuid.Must(uuid.NewV7()) + + err := repo.CreateCompany(ctx, &domain.Company{ + ID: vendorID, + CorporateName: "Farmácia Central", + Latitude: -23.55, + Longitude: -46.63, + }) + if err != nil { + t.Fatalf("failed to create company: %v", err) + } + + freeShipping := int64(1000) + err = repo.UpsertShippingSettings(ctx, &domain.ShippingSettings{ + VendorID: vendorID, + Active: true, + MaxRadiusKm: 10, + PricePerKmCents: 200, + MinFeeCents: 500, + FreeShippingThresholdCents: &freeShipping, + PickupActive: true, + PickupAddress: "Rua A, 123", + PickupHours: "9-18", + }) + if err != nil { + t.Fatalf("failed to upsert shipping settings: %v", err) + } + + options, err := svc.CalculateShippingOptions(ctx, vendorID, -23.55, -46.63, 1500) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if len(options) != 2 { + t.Fatalf("expected 2 options, got %d", len(options)) + } + + var deliveryOption *domain.ShippingOption + var pickupOption *domain.ShippingOption + for i := range options { + switch options[i].Type { + case domain.ShippingOptionTypeDelivery: + deliveryOption = &options[i] + case domain.ShippingOptionTypePickup: + pickupOption = &options[i] + } + } + + if deliveryOption == nil { + t.Fatal("expected delivery option") + } + if deliveryOption.ValueCents != 0 { + t.Fatalf("expected free delivery, got %d", deliveryOption.ValueCents) + } + if deliveryOption.EstimatedMinutes != 30 { + t.Fatalf("expected 30 minutes for delivery, got %d", deliveryOption.EstimatedMinutes) + } + + if pickupOption == nil { + t.Fatal("expected pickup option") + } + if pickupOption.Description != "Retirada em: Rua A, 123 (9-18)" { + t.Fatalf("unexpected pickup description: %s", pickupOption.Description) + } + if pickupOption.EstimatedMinutes != 60 { + t.Fatalf("expected 60 minutes for pickup, got %d", pickupOption.EstimatedMinutes) + } +} + // --- Payment Tests --- func TestCreatePaymentPreference(t *testing.T) { diff --git a/marketplace/src/services/financialService.test.ts b/marketplace/src/services/financialService.test.ts new file mode 100644 index 0000000..176df36 --- /dev/null +++ b/marketplace/src/services/financialService.test.ts @@ -0,0 +1,118 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest' +import { financialService } from './financialService' +import { apiClient } from './apiClient' + +vi.mock('./apiClient', () => ({ + apiClient: { + get: vi.fn(), + post: vi.fn() + } +})) + +describe('financialService', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + it('should fetch company data', async () => { + const mockCompany = { id: 'company-1', corporate_name: 'Farmácia Central' } + vi.mocked(apiClient.get).mockResolvedValue(mockCompany) + + const result = await financialService.getMyCompany() + + expect(apiClient.get).toHaveBeenCalledWith('/v1/companies/me') + expect(result).toEqual(mockCompany) + }) + + it('should upload a document', async () => { + const mockDocument = { + id: 'doc-1', + company_id: 'company-1', + type: 'CNES', + status: 'PENDING', + url: 'https://example.com/doc', + created_at: '2024-01-01T00:00:00Z' + } + + vi.mocked(apiClient.post).mockResolvedValue(mockDocument) + + const file = new File(['content'], 'doc.pdf', { type: 'application/pdf' }) + const result = await financialService.uploadDocument(file, 'CNES') + + expect(apiClient.post).toHaveBeenCalledWith('/v1/companies/documents', expect.any(FormData)) + expect(result).toEqual(mockDocument) + }) + + it('should list documents', async () => { + const mockDocuments = { + documents: [ + { + id: 'doc-1', + company_id: 'company-1', + type: 'CRF', + status: 'APPROVED', + url: 'https://example.com/doc', + created_at: '2024-01-01T00:00:00Z' + } + ] + } + + vi.mocked(apiClient.get).mockResolvedValue(mockDocuments) + + const result = await financialService.listDocuments() + + expect(apiClient.get).toHaveBeenCalledWith('/v1/companies/documents') + expect(result).toEqual(mockDocuments.documents) + }) + + it('should return balance', async () => { + vi.mocked(apiClient.get).mockResolvedValue({ balance: 12500 }) + + const result = await financialService.getBalance() + + expect(apiClient.get).toHaveBeenCalledWith('/v1/finance/balance') + expect(result).toBe(12500) + }) + + it('should fetch ledger with pagination', async () => { + const mockLedger = { + entries: [ + { + id: 'entry-1', + company_id: 'company-1', + amount: 1000, + balance_after: 2000, + description: 'Venda', + type: 'CREDIT', + reference_id: 'ref-1', + created_at: '2024-01-01T00:00:00Z' + } + ], + total: 1 + } + + vi.mocked(apiClient.get).mockResolvedValue(mockLedger) + + const result = await financialService.getLedger(2, 50) + + expect(apiClient.get).toHaveBeenCalledWith('/v1/finance/ledger?page=2&limit=50') + expect(result).toEqual(mockLedger) + }) + + it('should request withdrawal', async () => { + const mockWithdrawal = { + id: 'withdrawal-1', + company_id: 'company-1', + amount: 5000, + status: 'PENDING', + requested_at: '2024-01-02T00:00:00Z' + } + + vi.mocked(apiClient.post).mockResolvedValue(mockWithdrawal) + + const result = await financialService.requestWithdrawal(5000) + + expect(apiClient.post).toHaveBeenCalledWith('/v1/finance/withdrawals', { amount: 5000 }) + expect(result).toEqual(mockWithdrawal) + }) +})