157 lines
4.9 KiB
TypeScript
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);
|
|
});
|
|
});
|
|
});
|