canina/backend/src/orders/orders.service.spec.ts
2026-08-06 22:27:56 +03:30

157 lines
4.9 KiB
TypeScript

import { Test, TestingModule } from '@nestjs/testing';
import { OrdersService } from './orders.service';
import { PrismaService } from '../prisma/prisma.service';
import { SmsService } from '../common/services/sms.service';
import { NotFoundException, BadRequestException } from '@nestjs/common';
import { Prisma } from '@prisma/client';
describe('OrdersService', () => {
let service: OrdersService;
let prisma: PrismaService;
const mockPrisma = {
product: {
findUnique: jest.fn(),
findMany: jest.fn(),
},
order: {
create: jest.fn(),
findMany: jest.fn(),
findFirst: jest.fn(),
count: jest.fn(),
},
user: {
findUnique: jest.fn(),
update: jest.fn(),
},
walletTransaction: {
create: jest.fn(),
},
};
const mockSmsService = {
sendOrderConfirmation: jest.fn().mockResolvedValue(true),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
OrdersService,
{ provide: PrismaService, useValue: mockPrisma },
{ provide: SmsService, useValue: mockSmsService },
],
}).compile();
service = module.get<OrdersService>(OrdersService);
prisma = module.get<PrismaService>(PrismaService);
});
afterEach(() => {
jest.clearAllMocks();
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('create', () => {
it('should throw BadRequestException if items are empty', async () => {
const dto = { items: [] };
await expect(service.create('user-id', dto)).rejects.toThrow(
BadRequestException,
);
});
it('should throw BadRequestException for duplicate product IDs in order items', async () => {
const dto = {
items: [
{ productId: 'prod-1', quantity: 1 },
{ productId: 'prod-1', quantity: 2 },
],
};
await expect(service.create('user-id', dto)).rejects.toThrow(
BadRequestException,
);
});
it('should throw BadRequestException for non-positive or non-integer quantities', async () => {
const dtoZero = { items: [{ productId: 'prod-1', quantity: 0 }] };
await expect(service.create('user-id', dtoZero)).rejects.toThrow(
BadRequestException,
);
const dtoFloat = { items: [{ productId: 'prod-1', quantity: 1.5 }] };
await expect(service.create('user-id', dtoFloat)).rejects.toThrow(
BadRequestException,
);
});
it('should throw NotFoundException if any product is not found in batched query', async () => {
mockPrisma.product.findMany.mockResolvedValue([
{ id: 'prod-1', priceValue: new Prisma.Decimal('1000') },
]);
const dto = {
items: [
{ productId: 'prod-1', quantity: 1 },
{ productId: 'prod-missing', quantity: 2 },
],
};
await expect(service.create('user-id', dto)).rejects.toThrow(
NotFoundException,
);
});
it('should successfully create order using batched findMany and precise Decimal calculations', async () => {
const products = [
{ id: 'prod-1', priceValue: new Prisma.Decimal('32.49') },
{ id: 'prod-2', priceValue: new Prisma.Decimal('15.50') },
];
mockPrisma.product.findMany.mockResolvedValue(products);
mockPrisma.order.create.mockResolvedValue({
id: 'order-1',
totalAmount: new Prisma.Decimal('80.48'),
});
const dto = {
items: [
{ productId: 'prod-1', quantity: 2 }, // 32.49 * 2 = 64.98
{ productId: 'prod-2', quantity: 1 }, // 15.50 * 1 = 15.50 Total = 80.48
],
};
const result = await service.create('user-id', dto);
expect(prisma.product.findMany).toHaveBeenCalledWith({
where: { id: { in: ['prod-1', 'prod-2'] } },
});
expect(prisma.order.create).toHaveBeenCalled();
expect(result.id).toBe('order-1');
});
});
describe('findAllByUser', () => {
it('should find all orders of a user', async () => {
mockPrisma.order.findMany.mockResolvedValue([{ id: 'order-1' }]);
mockPrisma.order.count.mockResolvedValue(1);
const result = await service.findAllByUser('user-id', {});
expect(prisma.order.findMany).toHaveBeenCalled();
expect(result.data).toHaveLength(1);
});
});
describe('findOne', () => {
it('should throw NotFoundException if order does not exist', async () => {
mockPrisma.order.findFirst.mockResolvedValue(null);
await expect(service.findOne('order-id', 'user-id')).rejects.toThrow(
NotFoundException,
);
});
it('should return order if found', async () => {
const order = { id: 'order-1', userId: 'user-id' };
mockPrisma.order.findFirst.mockResolvedValue(order);
const result = await service.findOne('order-1', 'user-id');
expect(result).toEqual(order);
});
});
});