- Created comprehensive unit tests for marketplaceService (11 tests) - Created comprehensive unit tests for profileService (12 tests) - Created comprehensive unit tests for avatarService (9 tests) - Created comprehensive unit tests for 2fa-service (8 tests) - All 40 tests pass successfully - Tests cover success cases, error handling, edge cases, and validation scenarios Files modified: - apps/web/src/services/marketplaceService.test.ts (new) - apps/web/src/features/profile/services/profileService.test.ts (new) - apps/web/src/features/profile/services/avatarService.test.ts (new) - apps/web/src/services/2fa-service.test.ts (new) - VEZA_COMPLETE_MVP_TODOLIST.json
274 lines
7.4 KiB
TypeScript
274 lines
7.4 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { AxiosError } from 'axios';
|
|
import { marketplaceService } from './marketplaceService';
|
|
import { apiClient } from './api/client';
|
|
import type { Product, Order, ProductStatus } from '../types/marketplace';
|
|
|
|
// Mock apiClient
|
|
vi.mock('./api/client', () => ({
|
|
apiClient: {
|
|
get: vi.fn(),
|
|
post: vi.fn(),
|
|
},
|
|
}));
|
|
|
|
const mockedApiClient = apiClient as {
|
|
get: ReturnType<typeof vi.fn>;
|
|
post: ReturnType<typeof vi.fn>;
|
|
};
|
|
|
|
describe('marketplaceService', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('fetchProducts', () => {
|
|
it('should fetch products without filters', async () => {
|
|
const mockProducts: Product[] = [
|
|
{
|
|
id: '1',
|
|
name: 'Test Product',
|
|
description: 'Test Description',
|
|
price: 10.99,
|
|
status: 'active' as ProductStatus,
|
|
seller_id: 'seller-1',
|
|
created_at: '2024-01-01T00:00:00Z',
|
|
},
|
|
];
|
|
|
|
mockedApiClient.get.mockResolvedValue({
|
|
data: {
|
|
products: mockProducts,
|
|
total: 1,
|
|
page: 1,
|
|
limit: 20,
|
|
total_pages: 1,
|
|
},
|
|
});
|
|
|
|
const result = await marketplaceService.fetchProducts();
|
|
|
|
expect(result.products).toEqual(mockProducts);
|
|
expect(result.total).toBe(1);
|
|
expect(mockedApiClient.get).toHaveBeenCalledWith('/marketplace/products');
|
|
});
|
|
|
|
it('should fetch products with filters', async () => {
|
|
const mockProducts: Product[] = [];
|
|
|
|
mockedApiClient.get.mockResolvedValue({
|
|
data: {
|
|
products: mockProducts,
|
|
total: 0,
|
|
page: 1,
|
|
limit: 20,
|
|
total_pages: 0,
|
|
},
|
|
});
|
|
|
|
await marketplaceService.fetchProducts(
|
|
{
|
|
status: 'active' as ProductStatus,
|
|
seller_id: 'seller-1',
|
|
min_price: 10,
|
|
max_price: 100,
|
|
search: 'test',
|
|
},
|
|
{ page: 1, limit: 20 },
|
|
);
|
|
|
|
expect(mockedApiClient.get).toHaveBeenCalledWith(
|
|
'/marketplace/products?status=active&seller_id=seller-1&min_price=10&max_price=100&search=test&page=1&limit=20',
|
|
);
|
|
});
|
|
|
|
it('should handle array response format (backward compatibility)', async () => {
|
|
const mockProducts: Product[] = [
|
|
{
|
|
id: '1',
|
|
name: 'Test Product',
|
|
description: 'Test Description',
|
|
price: 10.99,
|
|
status: 'active' as ProductStatus,
|
|
seller_id: 'seller-1',
|
|
created_at: '2024-01-01T00:00:00Z',
|
|
},
|
|
];
|
|
|
|
mockedApiClient.get.mockResolvedValue({
|
|
data: mockProducts,
|
|
});
|
|
|
|
const result = await marketplaceService.fetchProducts();
|
|
|
|
expect(result.products).toEqual(mockProducts);
|
|
expect(result.total).toBe(1);
|
|
expect(result.page).toBe(1);
|
|
});
|
|
|
|
it('should throw error on fetch failure', async () => {
|
|
const mockError = new AxiosError('Fetch failed');
|
|
mockError.response = {
|
|
status: 500,
|
|
data: { error: 'Internal server error' },
|
|
} as any;
|
|
|
|
mockedApiClient.get.mockRejectedValue(mockError);
|
|
|
|
await expect(marketplaceService.fetchProducts()).rejects.toThrow();
|
|
});
|
|
});
|
|
|
|
describe('createProduct', () => {
|
|
it('should create a product successfully', async () => {
|
|
const mockProduct: Product = {
|
|
id: '1',
|
|
name: 'New Product',
|
|
description: 'New Description',
|
|
price: 19.99,
|
|
status: 'active' as ProductStatus,
|
|
seller_id: 'seller-1',
|
|
created_at: '2024-01-01T00:00:00Z',
|
|
};
|
|
|
|
mockedApiClient.post.mockResolvedValue({
|
|
data: mockProduct,
|
|
});
|
|
|
|
const result = await marketplaceService.createProduct({
|
|
name: 'New Product',
|
|
description: 'New Description',
|
|
price: 19.99,
|
|
product_type: 'track',
|
|
});
|
|
|
|
expect(result).toEqual(mockProduct);
|
|
expect(mockedApiClient.post).toHaveBeenCalledWith(
|
|
'/marketplace/products',
|
|
{
|
|
name: 'New Product',
|
|
description: 'New Description',
|
|
price: 19.99,
|
|
product_type: 'track',
|
|
},
|
|
);
|
|
});
|
|
|
|
it('should throw error on creation failure', async () => {
|
|
const mockError = new AxiosError('Creation failed');
|
|
mockError.response = {
|
|
status: 403,
|
|
data: { error: 'Permission denied' },
|
|
} as any;
|
|
|
|
mockedApiClient.post.mockRejectedValue(mockError);
|
|
|
|
await expect(
|
|
marketplaceService.createProduct({
|
|
name: 'New Product',
|
|
description: 'New Description',
|
|
price: 19.99,
|
|
product_type: 'track',
|
|
}),
|
|
).rejects.toThrow();
|
|
});
|
|
});
|
|
|
|
describe('createOrder', () => {
|
|
it('should create an order successfully', async () => {
|
|
const mockOrder: Order = {
|
|
id: 'order-1',
|
|
user_id: 'user-1',
|
|
items: [{ product_id: 'product-1', quantity: 1 }],
|
|
total: 19.99,
|
|
status: 'pending',
|
|
created_at: '2024-01-01T00:00:00Z',
|
|
};
|
|
|
|
mockedApiClient.post.mockResolvedValue({
|
|
data: mockOrder,
|
|
});
|
|
|
|
const result = await marketplaceService.createOrder([
|
|
{ product_id: 'product-1' },
|
|
]);
|
|
|
|
expect(result).toEqual(mockOrder);
|
|
expect(mockedApiClient.post).toHaveBeenCalledWith(
|
|
'/marketplace/orders',
|
|
{ items: [{ product_id: 'product-1' }] },
|
|
);
|
|
});
|
|
|
|
it('should throw error on order creation failure', async () => {
|
|
const mockError = new AxiosError('Order creation failed');
|
|
mockError.response = {
|
|
status: 400,
|
|
data: { error: 'Invalid product' },
|
|
} as any;
|
|
|
|
mockedApiClient.post.mockRejectedValue(mockError);
|
|
|
|
await expect(
|
|
marketplaceService.createOrder([{ product_id: 'invalid-product' }]),
|
|
).rejects.toThrow();
|
|
});
|
|
});
|
|
|
|
describe('purchaseProduct', () => {
|
|
it('should purchase a single product successfully', async () => {
|
|
const mockOrder: Order = {
|
|
id: 'order-1',
|
|
user_id: 'user-1',
|
|
items: [{ product_id: 'product-1', quantity: 1 }],
|
|
total: 19.99,
|
|
status: 'pending',
|
|
created_at: '2024-01-01T00:00:00Z',
|
|
};
|
|
|
|
mockedApiClient.post.mockResolvedValue({
|
|
data: mockOrder,
|
|
});
|
|
|
|
const result = await marketplaceService.purchaseProduct('product-1');
|
|
|
|
expect(result).toEqual(mockOrder);
|
|
expect(mockedApiClient.post).toHaveBeenCalledWith(
|
|
'/marketplace/orders',
|
|
{ items: [{ product_id: 'product-1' }] },
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('getDownloadLink', () => {
|
|
it('should get download link successfully', async () => {
|
|
const mockResponse = { url: 'https://example.com/download/product-1' };
|
|
|
|
mockedApiClient.get.mockResolvedValue({
|
|
data: mockResponse,
|
|
});
|
|
|
|
const result = await marketplaceService.getDownloadLink('product-1');
|
|
|
|
expect(result).toBe('https://example.com/download/product-1');
|
|
expect(mockedApiClient.get).toHaveBeenCalledWith(
|
|
'/marketplace/download/product-1',
|
|
);
|
|
});
|
|
|
|
it('should throw error on download link failure', async () => {
|
|
const mockError = new AxiosError('Download link failed');
|
|
mockError.response = {
|
|
status: 403,
|
|
data: { error: 'No license found' },
|
|
} as any;
|
|
|
|
mockedApiClient.get.mockRejectedValue(mockError);
|
|
|
|
await expect(
|
|
marketplaceService.getDownloadLink('product-1'),
|
|
).rejects.toThrow();
|
|
});
|
|
});
|
|
});
|
|
|