fix(tests): fix failing tests and increase coverage

Backend:
- Fix TestCreateCompany (added Phone, OperatingHours, Is24Hours)
- Fix TestCreateProduct (added EANCode, Manufacturer, Category, etc)
- Add TestCreateUser, TestListUsers, TestListOrders, TestGetShippingSettings
- All 9 repository tests now pass

Frontend:
- Add shippingService.test.ts (4 tests)
- Add ordersService.test.ts (5 tests)
- Add format.test.ts (9 tests)
- Total tests increased from 54 to 72
This commit is contained in:
Tiago Yamamoto 2025-12-26 22:54:51 -03:00
parent 630bcc9da5
commit f0d64d1801
4 changed files with 428 additions and 19 deletions

View file

@ -38,6 +38,9 @@ func TestCreateCompany(t *testing.T) {
Longitude: -20.0, Longitude: -20.0,
City: "Test City", City: "Test City",
State: "TS", State: "TS",
Phone: "(11) 99999-9999",
OperatingHours: "08:00-18:00",
Is24Hours: false,
CreatedAt: time.Now(), CreatedAt: time.Now(),
UpdatedAt: time.Now(), UpdatedAt: time.Now(),
} }
@ -55,6 +58,9 @@ func TestCreateCompany(t *testing.T) {
company.Longitude, company.Longitude,
company.City, company.City,
company.State, company.State,
company.Phone,
company.OperatingHours,
company.Is24Hours,
sqlmock.AnyArg(), // CreatedAt sqlmock.AnyArg(), // CreatedAt
sqlmock.AnyArg(), // UpdatedAt sqlmock.AnyArg(), // UpdatedAt
). ).
@ -99,11 +105,17 @@ func TestCreateProduct(t *testing.T) {
product := &domain.Product{ product := &domain.Product{
ID: uuid.Must(uuid.NewV7()), ID: uuid.Must(uuid.NewV7()),
SellerID: uuid.Must(uuid.NewV7()), SellerID: uuid.Must(uuid.NewV7()),
EANCode: "7891234567890",
Name: "Test Product", Name: "Test Product",
Description: "Desc", Description: "Desc",
Manufacturer: "Test Manufacturer",
Category: "medicamento",
Subcategory: "analgésico",
Batch: "B1", Batch: "B1",
ExpiresAt: time.Now().AddDate(1, 0, 0),
PriceCents: 1000, PriceCents: 1000,
Stock: 10, Stock: 10,
Observations: "Test observations",
} }
query := `INSERT INTO products` query := `INSERT INTO products`
@ -113,12 +125,17 @@ func TestCreateProduct(t *testing.T) {
WithArgs( WithArgs(
product.ID, product.ID,
product.SellerID, product.SellerID,
product.EANCode,
product.Name, product.Name,
product.Description, product.Description,
product.Manufacturer,
product.Category,
product.Subcategory,
product.Batch, product.Batch,
product.ExpiresAt, product.ExpiresAt,
product.PriceCents, product.PriceCents,
product.Stock, product.Stock,
product.Observations,
). ).
WillReturnRows(rows) WillReturnRows(rows)
@ -141,3 +158,126 @@ func TestListProducts(t *testing.T) {
assert.Equal(t, int64(1), count) assert.Equal(t, int64(1), count)
assert.Len(t, list, 1) assert.Len(t, list, 1)
} }
func TestCreateUser(t *testing.T) {
repo, mock := newMockRepo(t)
defer repo.db.Close()
user := &domain.User{
ID: uuid.Must(uuid.NewV7()),
CompanyID: uuid.Must(uuid.NewV7()),
Role: "Colaborador",
Name: "Test User",
Username: "testuser",
Email: "test@example.com",
PasswordHash: "hashed_password",
}
query := `INSERT INTO users`
mock.ExpectExec(regexp.QuoteMeta(query)).
WithArgs(
user.ID,
user.CompanyID,
user.Role,
user.Name,
user.Username,
user.Email,
user.EmailVerified, // email_verified
user.PasswordHash, // password_hash
sqlmock.AnyArg(), // CreatedAt
sqlmock.AnyArg(), // UpdatedAt
).
WillReturnResult(sqlmock.NewResult(1, 1))
err := repo.CreateUser(context.Background(), user)
assert.NoError(t, err)
}
func TestListUsers(t *testing.T) {
repo, mock := newMockRepo(t)
defer repo.db.Close()
companyID := uuid.Must(uuid.NewV7())
userID := uuid.Must(uuid.NewV7())
rows := sqlmock.NewRows([]string{
"id", "company_id", "role", "name", "username", "email",
"email_verified", "password_hash", "created_at", "updated_at",
}).AddRow(
userID, companyID, "Owner", "Test", "test", "test@test.com",
true, "hash", time.Now(), time.Now(),
)
mock.ExpectQuery(`SELECT count\(\*\) FROM users`).
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
mock.ExpectQuery(`SELECT .* FROM users`).
WithArgs(20, 0).
WillReturnRows(rows)
list, count, err := repo.ListUsers(context.Background(), domain.UserFilter{Limit: 20})
assert.NoError(t, err)
assert.Equal(t, int64(1), count)
assert.Len(t, list, 1)
}
func TestListOrders(t *testing.T) {
repo, mock := newMockRepo(t)
defer repo.db.Close()
orderID := uuid.Must(uuid.NewV7())
buyerID := uuid.Must(uuid.NewV7())
sellerID := uuid.Must(uuid.NewV7())
rows := sqlmock.NewRows([]string{
"id", "buyer_id", "seller_id", "status", "total_cents", "payment_method",
"shipping_recipient_name", "shipping_street", "shipping_number", "shipping_complement",
"shipping_district", "shipping_city", "shipping_state", "shipping_zip_code",
"shipping_country", "created_at", "updated_at",
}).AddRow(
orderID, buyerID, sellerID, "Pendente", 10000, "pix",
"Test User", "Test Street", "123", "", "Centro", "City", "ST", "12345-678", "Brasil",
time.Now(), time.Now(),
)
mock.ExpectQuery(`SELECT count\(\*\) FROM orders`).
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
mock.ExpectQuery(`SELECT .* FROM orders`).
WithArgs(20, 0).
WillReturnRows(rows)
// Expect query for order items
mock.ExpectQuery(`SELECT .* FROM order_items WHERE order_id`).
WithArgs(orderID).
WillReturnRows(sqlmock.NewRows([]string{"id", "order_id", "product_id", "quantity", "unit_cents", "batch", "expires_at"}))
list, count, err := repo.ListOrders(context.Background(), domain.OrderFilter{Limit: 20})
assert.NoError(t, err)
assert.Equal(t, int64(1), count)
assert.Len(t, list, 1)
}
func TestGetShippingSettings(t *testing.T) {
repo, mock := newMockRepo(t)
defer repo.db.Close()
vendorID := uuid.Must(uuid.NewV7())
rows := sqlmock.NewRows([]string{
"vendor_id", "active", "max_radius_km", "price_per_km_cents", "min_fee_cents",
"free_shipping_threshold_cents", "pickup_active", "pickup_address", "pickup_hours",
"latitude", "longitude", "created_at", "updated_at",
}).AddRow(
vendorID, true, 50.0, 150, 1000, nil, true, "Rua Test, 123", "08:00-18:00",
-23.55, -46.63, time.Now(), time.Now(),
)
mock.ExpectQuery(`SELECT \* FROM shipping_settings WHERE vendor_id`).
WithArgs(vendorID).
WillReturnRows(rows)
settings, err := repo.GetShippingSettings(context.Background(), vendorID)
assert.NoError(t, err)
assert.NotNil(t, settings)
assert.Equal(t, vendorID, settings.VendorID)
assert.True(t, settings.Active)
}

View file

@ -0,0 +1,122 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { ordersService, CreateOrderRequest } from './ordersService'
import { apiClient } from './apiClient'
// Mock apiClient
vi.mock('./apiClient', () => ({
apiClient: {
get: vi.fn(),
post: vi.fn()
}
}))
describe('ordersService', () => {
beforeEach(() => {
vi.clearAllMocks()
})
describe('listOrders', () => {
it('should fetch orders list', async () => {
const mockOrders = {
orders: [
{ id: 'order-1', buyer_id: 'buyer-1', seller_id: 'seller-1', status: 'Pendente', total_cents: 10000 },
{ id: 'order-2', buyer_id: 'buyer-1', seller_id: 'seller-2', status: 'Pago', total_cents: 25000 }
],
total: 2,
page: 1,
page_size: 20
}
vi.mocked(apiClient.get).mockResolvedValue(mockOrders)
const result = await ordersService.listOrders()
expect(apiClient.get).toHaveBeenCalledWith('/v1/orders')
expect(result).toEqual(mockOrders)
})
it('should handle empty orders list', async () => {
const mockOrders = {
orders: [],
total: 0,
page: 1,
page_size: 20
}
vi.mocked(apiClient.get).mockResolvedValue(mockOrders)
const result = await ordersService.listOrders()
expect(result).toEqual(mockOrders)
})
it('should handle API error', async () => {
vi.mocked(apiClient.get).mockRejectedValue(new Error('Internal Server Error'))
await expect(ordersService.listOrders())
.rejects.toThrow('Internal Server Error')
})
})
describe('createOrder', () => {
it('should create an order successfully', async () => {
const orderData: CreateOrderRequest = {
buyer_id: 'buyer-1',
seller_id: 'seller-1',
items: [
{ product_id: 'prod-1', quantity: 2, unit_cents: 1500, batch: 'L001', expires_at: '2025-12-31' }
],
shipping: {
recipient_name: 'Test User',
street: 'Rua Test',
number: '123',
district: 'Centro',
city: 'City',
state: 'ST',
zip_code: '12345-678',
country: 'Brasil'
},
payment_method: 'pix'
}
const mockOrder = {
id: 'new-order-1',
...orderData,
status: 'Pendente',
total_cents: 3000,
created_at: new Date().toISOString()
}
vi.mocked(apiClient.post).mockResolvedValue(mockOrder)
const result = await ordersService.createOrder(orderData)
expect(apiClient.post).toHaveBeenCalledWith('/v1/orders', orderData)
expect(result).toEqual(mockOrder)
})
it('should handle order creation failure', async () => {
vi.mocked(apiClient.post).mockRejectedValue(new Error('Insufficient stock'))
const orderData: CreateOrderRequest = {
buyer_id: 'buyer-1',
seller_id: 'seller-1',
items: [],
shipping: {
recipient_name: '',
street: '',
number: '',
district: '',
city: '',
state: '',
zip_code: '',
country: ''
},
payment_method: 'pix'
}
await expect(ordersService.createOrder(orderData))
.rejects.toThrow('Insufficient stock')
})
})
})

View file

@ -0,0 +1,96 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { shippingService } from './shippingService'
import { apiClient } from './apiClient'
import type { ShippingSettings } from '../types/shipping'
// Mock apiClient
vi.mock('./apiClient', () => ({
apiClient: {
get: vi.fn(),
post: vi.fn()
}
}))
describe('shippingService', () => {
beforeEach(() => {
vi.clearAllMocks()
})
describe('getSettings', () => {
it('should fetch shipping settings for a vendor', async () => {
const mockSettings: ShippingSettings = {
vendor_id: 'vendor-123',
active: true,
max_radius_km: 50,
price_per_km_cents: 150,
min_fee_cents: 1000,
pickup_active: true,
pickup_address: 'Rua Test, 123',
pickup_hours: '08:00-18:00',
latitude: -23.55,
longitude: -46.63
}
vi.mocked(apiClient.get).mockResolvedValue(mockSettings)
const result = await shippingService.getSettings('vendor-123')
expect(apiClient.get).toHaveBeenCalledWith('/v1/shipping/settings/vendor-123')
expect(result).toEqual(mockSettings)
expect(result.active).toBe(true)
expect(result.pickup_active).toBe(true)
})
it('should handle vendor not found', async () => {
vi.mocked(apiClient.get).mockRejectedValue(new Error('Vendor not found'))
await expect(shippingService.getSettings('invalid-vendor'))
.rejects.toThrow('Vendor not found')
})
})
describe('calculate', () => {
it('should calculate shipping cost', async () => {
const mockCalculation = {
options: [
{
seller_id: 'seller-1',
delivery_fee_cents: 2500,
distance_km: 15.5,
estimated_days: 2,
pickup_available: true,
pickup_address: 'Rua Test, 123',
pickup_hours: '08:00-18:00'
}
]
}
vi.mocked(apiClient.post).mockResolvedValue(mockCalculation)
const result = await shippingService.calculate({
buyer_id: 'buyer-123',
order_total_cents: 15000,
items: [
{ seller_id: 'seller-1', product_id: 'prod-1', quantity: 2, price_cents: 7500 }
]
})
expect(apiClient.post).toHaveBeenCalledWith('/v1/shipping/calculate', expect.objectContaining({
buyer_id: 'buyer-123',
order_total_cents: 15000
}))
expect(result.options).toHaveLength(1)
expect(result.options[0].delivery_fee_cents).toBe(2500)
})
it('should handle API error', async () => {
vi.mocked(apiClient.post).mockRejectedValue(new Error('Server error'))
await expect(shippingService.calculate({
buyer_id: 'buyer-123',
order_total_cents: 15000,
items: []
})).rejects.toThrow('Server error')
})
})
})

View file

@ -0,0 +1,51 @@
import { describe, it, expect } from 'vitest'
import { formatCents, formatCurrency } from './format'
describe('format utilities', () => {
describe('formatCurrency', () => {
it('should format number to comma-separated string', () => {
expect(formatCurrency(10.00)).toBe('10,00')
expect(formatCurrency(15.99)).toBe('15,99')
expect(formatCurrency(1000.50)).toBe('1000,50')
})
it('should handle zero', () => {
expect(formatCurrency(0)).toBe('0,00')
})
it('should handle undefined/null', () => {
expect(formatCurrency(undefined)).toBe('0,00')
expect(formatCurrency(null)).toBe('0,00')
})
it('should handle NaN', () => {
expect(formatCurrency(NaN)).toBe('0,00')
})
})
describe('formatCents', () => {
it('should format cents to BRL currency', () => {
expect(formatCents(1000)).toBe('R$ 10,00')
expect(formatCents(1599)).toBe('R$ 15,99')
expect(formatCents(100000)).toBe('R$ 1000,00')
})
it('should handle zero', () => {
expect(formatCents(0)).toBe('R$ 0,00')
})
it('should handle undefined/null', () => {
expect(formatCents(undefined)).toBe('R$ 0,00')
expect(formatCents(null)).toBe('R$ 0,00')
})
it('should handle NaN', () => {
expect(formatCents(NaN)).toBe('R$ 0,00')
})
it('should handle small amounts', () => {
expect(formatCents(50)).toBe('R$ 0,50')
expect(formatCents(1)).toBe('R$ 0,01')
})
})
})