import { NotFoundException } from '@nestjs/common'; import { ProjectService } from './project.service'; describe('ProjectService domain writes', () => { const makeService = () => { const prisma = { product: { findUnique: jest.fn(), }, project: { create: jest.fn(), delete: jest.fn(), findFirst: jest.fn(), findMany: jest.fn(), update: jest.fn(), }, }; return { prisma, service: new ProjectService(prisma as any), }; }; it('creates projects directly under a product relation row', async () => { const { prisma, service } = makeService(); prisma.product.findUnique.mockResolvedValue({ id: 'product-1' }); prisma.project.create.mockResolvedValue({ id: 'project-1', productId: 'product-1' }); await service.create('product-1', { name: 'CRM', description: 'Customer system' }); expect(prisma.project.create).toHaveBeenCalledWith({ data: { productId: 'product-1', name: 'CRM', description: 'Customer system', }, }); }); it('lists projects by product id', async () => { const { prisma, service } = makeService(); prisma.project.findMany.mockResolvedValue([]); await service.findAll('product-1'); expect(prisma.project.findMany).toHaveBeenCalledWith({ where: { productId: 'product-1' }, orderBy: { createdAt: 'desc' }, }); }); it('updates projects only inside their product scope', async () => { const { prisma, service } = makeService(); prisma.project.findFirst.mockResolvedValue({ id: 'project-1', productId: 'product-1' }); prisma.project.update.mockResolvedValue({ id: 'project-1', name: 'CRM v2' }); await service.update('product-1', 'project-1', { name: 'CRM v2' }); expect(prisma.project.update).toHaveBeenCalledWith({ where: { id: 'project-1' }, data: { name: 'CRM v2' }, }); }); it('throws when updating a project outside the product scope', async () => { const { prisma, service } = makeService(); prisma.project.findFirst.mockResolvedValue(null); await expect(service.update('product-1', 'project-404', { name: 'Ghost' })).rejects.toBeInstanceOf(NotFoundException); expect(prisma.project.update).not.toHaveBeenCalled(); }); it('deletes projects only inside their product scope', async () => { const { prisma, service } = makeService(); prisma.project.findFirst.mockResolvedValue({ id: 'project-1', productId: 'product-1' }); prisma.project.delete.mockResolvedValue({ id: 'project-1' }); await service.remove('product-1', 'project-1'); expect(prisma.project.delete).toHaveBeenCalledWith({ where: { id: 'project-1' } }); }); });