import { Test, TestingModule } from '@nestjs/testing'; import { BadRequestException, ConflictException, NotFoundException } from '@nestjs/common'; import { Prisma } from '@prisma/client'; import { RoutesService } from './routes.service'; import { PrismaService } from '../../prisma/prisma.service'; const mockRoute = { id: 'rt_1', sourceGroupId: 'grp_1', targetGroupId: 'grp_2', isActive: true, createdAt: new Date(), sourceGroup: { name: 'Alpha' }, targetGroup: { name: 'Beta' }, }; describe('RoutesService', () => { let service: RoutesService; const mockPrisma = { syncRoute: { findMany: jest.fn().mockResolvedValue([mockRoute]), create: jest.fn().mockResolvedValue(mockRoute), delete: jest.fn().mockResolvedValue(mockRoute), }, }; beforeEach(async () => { jest.clearAllMocks(); const module: TestingModule = await Test.createTestingModule({ providers: [ RoutesService, { provide: PrismaService, useValue: mockPrisma }, ], }).compile(); service = module.get(RoutesService); }); describe('list', () => { it('returns all routes with group names', async () => { const result = await service.list(); expect(result).toHaveLength(1); expect(result[0].sourceGroup.name).toBe('Alpha'); expect(mockPrisma.syncRoute.findMany).toHaveBeenCalledWith({ where: undefined, include: { sourceGroup: { select: { name: true } }, targetGroup: { select: { name: true } }, }, orderBy: { createdAt: 'desc' }, }); }); it('filters by sourceGroupId when provided', async () => { await service.list('grp_1'); expect(mockPrisma.syncRoute.findMany).toHaveBeenCalledWith( expect.objectContaining({ where: { sourceGroupId: 'grp_1' } }), ); }); }); describe('create', () => { it('creates a route and returns it with group names', async () => { const result = await service.create('grp_1', 'grp_2'); expect(result).toEqual(mockRoute); expect(mockPrisma.syncRoute.create).toHaveBeenCalledWith({ data: { sourceGroupId: 'grp_1', targetGroupId: 'grp_2' }, include: { sourceGroup: { select: { name: true } }, targetGroup: { select: { name: true } }, }, }); }); it('throws BadRequestException when sourceGroupId is empty', async () => { await expect(service.create('', 'grp_2')).rejects.toThrow(BadRequestException); }); it('throws BadRequestException when targetGroupId is empty', async () => { await expect(service.create('grp_1', '')).rejects.toThrow(BadRequestException); }); it('throws ConflictException when route already exists (Prisma P2002)', async () => { const p2002 = new Prisma.PrismaClientKnownRequestError('Unique constraint', { code: 'P2002', clientVersion: '6.0.0', }); mockPrisma.syncRoute.create.mockRejectedValueOnce(p2002); await expect(service.create('grp_1', 'grp_2')).rejects.toThrow(ConflictException); }); }); describe('remove', () => { it('deletes a route by id', async () => { await service.remove('rt_1'); expect(mockPrisma.syncRoute.delete).toHaveBeenCalledWith({ where: { id: 'rt_1' } }); }); it('throws NotFoundException when route does not exist (Prisma P2025)', async () => { const p2025 = new Prisma.PrismaClientKnownRequestError('Record not found', { code: 'P2025', clientVersion: '6.0.0', }); mockPrisma.syncRoute.delete.mockRejectedValueOnce(p2025); await expect(service.remove('bad_id')).rejects.toThrow(NotFoundException); }); }); });