Files
ftb-project-management/apps/server/src/modules/project/project.service.spec.ts
2026-07-08 12:07:35 +08:00

84 lines
2.7 KiB
TypeScript

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' } });
});
});