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); prisma = module.get(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); }); }); });