test: add unit tests for persons and projects modules
Added comprehensive unit tests for `PersonsController`, `PersonsService`, `ProjectsController`, and `ProjectsService`. Covered CRUD operations, exception handling, group/project associations, and user access validation. Mocked `JwtAuthGuard` for all tests.
This commit is contained in:
parent
0f3c55f947
commit
269ba622f8
@ -0,0 +1,154 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { PersonsController } from './persons.controller';
|
||||||
|
import { PersonsService } from '../services/persons.service';
|
||||||
|
import { CreatePersonDto, Gender, OralEaseLevel } from '../dto/create-person.dto';
|
||||||
|
import { UpdatePersonDto } from '../dto/update-person.dto';
|
||||||
|
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
|
||||||
|
|
||||||
|
describe('PersonsController', () => {
|
||||||
|
let controller: PersonsController;
|
||||||
|
let service: PersonsService;
|
||||||
|
|
||||||
|
// Mock data
|
||||||
|
const mockPerson = {
|
||||||
|
id: 'person1',
|
||||||
|
firstName: 'John',
|
||||||
|
lastName: 'Doe',
|
||||||
|
gender: Gender.MALE,
|
||||||
|
technicalLevel: 3,
|
||||||
|
hasTechnicalTraining: true,
|
||||||
|
frenchSpeakingLevel: 4,
|
||||||
|
oralEaseLevel: OralEaseLevel.COMFORTABLE,
|
||||||
|
age: 30,
|
||||||
|
projectId: 'project1',
|
||||||
|
attributes: {},
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockPersonToGroup = {
|
||||||
|
personId: 'person1',
|
||||||
|
groupId: 'group1',
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [PersonsController],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: PersonsService,
|
||||||
|
useValue: {
|
||||||
|
create: jest.fn().mockResolvedValue(mockPerson),
|
||||||
|
findAll: jest.fn().mockResolvedValue([mockPerson]),
|
||||||
|
findByProjectId: jest.fn().mockResolvedValue([mockPerson]),
|
||||||
|
findById: jest.fn().mockResolvedValue(mockPerson),
|
||||||
|
update: jest.fn().mockResolvedValue(mockPerson),
|
||||||
|
remove: jest.fn().mockResolvedValue(mockPerson),
|
||||||
|
findByProjectIdAndGroupId: jest.fn().mockResolvedValue([{ person: mockPerson }]),
|
||||||
|
addToGroup: jest.fn().mockResolvedValue(mockPersonToGroup),
|
||||||
|
removeFromGroup: jest.fn().mockResolvedValue(mockPersonToGroup),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.overrideGuard(JwtAuthGuard)
|
||||||
|
.useValue({ canActivate: () => true })
|
||||||
|
.compile();
|
||||||
|
|
||||||
|
controller = module.get<PersonsController>(PersonsController);
|
||||||
|
service = module.get<PersonsService>(PersonsService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('create', () => {
|
||||||
|
it('should create a new person', async () => {
|
||||||
|
const createPersonDto: CreatePersonDto = {
|
||||||
|
firstName: 'John',
|
||||||
|
lastName: 'Doe',
|
||||||
|
gender: Gender.MALE,
|
||||||
|
technicalLevel: 3,
|
||||||
|
hasTechnicalTraining: true,
|
||||||
|
frenchSpeakingLevel: 4,
|
||||||
|
oralEaseLevel: OralEaseLevel.COMFORTABLE,
|
||||||
|
projectId: 'project1',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(await controller.create(createPersonDto)).toBe(mockPerson);
|
||||||
|
expect(service.create).toHaveBeenCalledWith(createPersonDto);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findAll', () => {
|
||||||
|
it('should return all persons when no projectId is provided', async () => {
|
||||||
|
expect(await controller.findAll()).toEqual([mockPerson]);
|
||||||
|
expect(service.findAll).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return persons filtered by projectId when projectId is provided', async () => {
|
||||||
|
const projectId = 'project1';
|
||||||
|
expect(await controller.findAll(projectId)).toEqual([mockPerson]);
|
||||||
|
expect(service.findByProjectId).toHaveBeenCalledWith(projectId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findOne', () => {
|
||||||
|
it('should return a person by ID', async () => {
|
||||||
|
const id = 'person1';
|
||||||
|
expect(await controller.findOne(id)).toBe(mockPerson);
|
||||||
|
expect(service.findById).toHaveBeenCalledWith(id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('update', () => {
|
||||||
|
it('should update a person', async () => {
|
||||||
|
const id = 'person1';
|
||||||
|
const updatePersonDto: UpdatePersonDto = {
|
||||||
|
firstName: 'Jane',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(await controller.update(id, updatePersonDto)).toBe(mockPerson);
|
||||||
|
expect(service.update).toHaveBeenCalledWith(id, updatePersonDto);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('remove', () => {
|
||||||
|
it('should delete a person', async () => {
|
||||||
|
const id = 'person1';
|
||||||
|
expect(await controller.remove(id)).toBe(mockPerson);
|
||||||
|
expect(service.remove).toHaveBeenCalledWith(id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findByProjectIdAndGroupId', () => {
|
||||||
|
it('should return persons by project ID and group ID', async () => {
|
||||||
|
const projectId = 'project1';
|
||||||
|
const groupId = 'group1';
|
||||||
|
|
||||||
|
expect(await controller.findByProjectIdAndGroupId(projectId, groupId)).toEqual([{ person: mockPerson }]);
|
||||||
|
expect(service.findByProjectIdAndGroupId).toHaveBeenCalledWith(projectId, groupId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('addToGroup', () => {
|
||||||
|
it('should add a person to a group', async () => {
|
||||||
|
const id = 'person1';
|
||||||
|
const groupId = 'group1';
|
||||||
|
|
||||||
|
expect(await controller.addToGroup(id, groupId)).toBe(mockPersonToGroup);
|
||||||
|
expect(service.addToGroup).toHaveBeenCalledWith(id, groupId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('removeFromGroup', () => {
|
||||||
|
it('should remove a person from a group', async () => {
|
||||||
|
const id = 'person1';
|
||||||
|
const groupId = 'group1';
|
||||||
|
|
||||||
|
expect(await controller.removeFromGroup(id, groupId)).toBe(mockPersonToGroup);
|
||||||
|
expect(service.removeFromGroup).toHaveBeenCalledWith(id, groupId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
277
backend/src/modules/persons/services/persons.service.spec.ts
Normal file
277
backend/src/modules/persons/services/persons.service.spec.ts
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { PersonsService } from './persons.service';
|
||||||
|
import { NotFoundException } from '@nestjs/common';
|
||||||
|
import { DRIZZLE } from '../../../database/database.module';
|
||||||
|
import { Gender, OralEaseLevel } from '../dto/create-person.dto';
|
||||||
|
|
||||||
|
describe('PersonsService', () => {
|
||||||
|
let service: PersonsService;
|
||||||
|
let mockDb: any;
|
||||||
|
|
||||||
|
// Mock data
|
||||||
|
const mockPerson = {
|
||||||
|
id: 'person1',
|
||||||
|
firstName: 'John',
|
||||||
|
lastName: 'Doe',
|
||||||
|
gender: Gender.MALE,
|
||||||
|
technicalLevel: 3,
|
||||||
|
hasTechnicalTraining: true,
|
||||||
|
frenchSpeakingLevel: 4,
|
||||||
|
oralEaseLevel: OralEaseLevel.COMFORTABLE,
|
||||||
|
age: 30,
|
||||||
|
projectId: 'project1',
|
||||||
|
attributes: {},
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockGroup = {
|
||||||
|
id: 'group1',
|
||||||
|
name: 'Test Group',
|
||||||
|
projectId: 'project1',
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockPersonToGroup = {
|
||||||
|
personId: 'person1',
|
||||||
|
groupId: 'group1',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock database operations
|
||||||
|
const mockDbOperations = {
|
||||||
|
select: jest.fn().mockReturnThis(),
|
||||||
|
from: jest.fn().mockReturnThis(),
|
||||||
|
where: jest.fn().mockReturnThis(),
|
||||||
|
insert: jest.fn().mockReturnThis(),
|
||||||
|
values: jest.fn().mockReturnThis(),
|
||||||
|
update: jest.fn().mockReturnThis(),
|
||||||
|
set: jest.fn().mockReturnThis(),
|
||||||
|
delete: jest.fn().mockReturnThis(),
|
||||||
|
innerJoin: jest.fn().mockReturnThis(),
|
||||||
|
returning: jest.fn().mockImplementation(() => {
|
||||||
|
return [mockPerson];
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
mockDb = {
|
||||||
|
...mockDbOperations,
|
||||||
|
};
|
||||||
|
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
PersonsService,
|
||||||
|
{
|
||||||
|
provide: DRIZZLE,
|
||||||
|
useValue: mockDb,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<PersonsService>(PersonsService);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('create', () => {
|
||||||
|
it('should create a new person', async () => {
|
||||||
|
const createPersonDto = {
|
||||||
|
firstName: 'John',
|
||||||
|
lastName: 'Doe',
|
||||||
|
gender: Gender.MALE,
|
||||||
|
technicalLevel: 3,
|
||||||
|
hasTechnicalTraining: true,
|
||||||
|
frenchSpeakingLevel: 4,
|
||||||
|
oralEaseLevel: OralEaseLevel.COMFORTABLE,
|
||||||
|
projectId: 'project1',
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await service.create(createPersonDto);
|
||||||
|
|
||||||
|
expect(mockDb.insert).toHaveBeenCalled();
|
||||||
|
expect(mockDb.values).toHaveBeenCalledWith(createPersonDto);
|
||||||
|
expect(result).toEqual(mockPerson);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findAll', () => {
|
||||||
|
it('should return all persons', async () => {
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => [mockPerson]);
|
||||||
|
|
||||||
|
const result = await service.findAll();
|
||||||
|
|
||||||
|
expect(mockDb.select).toHaveBeenCalled();
|
||||||
|
expect(mockDb.from).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual([mockPerson]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findByProjectId', () => {
|
||||||
|
it('should return persons for a specific project', async () => {
|
||||||
|
const projectId = 'project1';
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => [mockPerson]);
|
||||||
|
|
||||||
|
const result = await service.findByProjectId(projectId);
|
||||||
|
|
||||||
|
expect(mockDb.select).toHaveBeenCalled();
|
||||||
|
expect(mockDb.from).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual([mockPerson]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findById', () => {
|
||||||
|
it('should return a person by ID', async () => {
|
||||||
|
const id = 'person1';
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => [mockPerson]);
|
||||||
|
|
||||||
|
const result = await service.findById(id);
|
||||||
|
|
||||||
|
expect(mockDb.select).toHaveBeenCalled();
|
||||||
|
expect(mockDb.from).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual(mockPerson);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw NotFoundException if person not found', async () => {
|
||||||
|
const id = 'nonexistent';
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => []);
|
||||||
|
|
||||||
|
await expect(service.findById(id)).rejects.toThrow(NotFoundException);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('update', () => {
|
||||||
|
it('should update a person', async () => {
|
||||||
|
const id = 'person1';
|
||||||
|
const updatePersonDto = {
|
||||||
|
firstName: 'Jane',
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await service.update(id, updatePersonDto);
|
||||||
|
|
||||||
|
expect(mockDb.update).toHaveBeenCalled();
|
||||||
|
expect(mockDb.set).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual(mockPerson);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw NotFoundException if person not found', async () => {
|
||||||
|
const id = 'nonexistent';
|
||||||
|
const updatePersonDto = {
|
||||||
|
firstName: 'Jane',
|
||||||
|
};
|
||||||
|
|
||||||
|
mockDb.update.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.set.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.returning.mockImplementationOnce(() => []);
|
||||||
|
|
||||||
|
await expect(service.update(id, updatePersonDto)).rejects.toThrow(NotFoundException);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('remove', () => {
|
||||||
|
it('should delete a person', async () => {
|
||||||
|
const id = 'person1';
|
||||||
|
|
||||||
|
const result = await service.remove(id);
|
||||||
|
|
||||||
|
expect(mockDb.delete).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual(mockPerson);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw NotFoundException if person not found', async () => {
|
||||||
|
const id = 'nonexistent';
|
||||||
|
|
||||||
|
mockDb.delete.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.returning.mockImplementationOnce(() => []);
|
||||||
|
|
||||||
|
await expect(service.remove(id)).rejects.toThrow(NotFoundException);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findByProjectIdAndGroupId', () => {
|
||||||
|
it('should return persons by project ID and group ID', async () => {
|
||||||
|
const projectId = 'project1';
|
||||||
|
const groupId = 'group1';
|
||||||
|
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.innerJoin.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => [{ person: mockPerson }]);
|
||||||
|
|
||||||
|
const result = await service.findByProjectIdAndGroupId(projectId, groupId);
|
||||||
|
|
||||||
|
expect(mockDb.select).toHaveBeenCalled();
|
||||||
|
expect(mockDb.from).toHaveBeenCalled();
|
||||||
|
expect(mockDb.innerJoin).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual([{ person: mockPerson }]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('addToGroup', () => {
|
||||||
|
it('should add a person to a group', async () => {
|
||||||
|
const personId = 'person1';
|
||||||
|
const groupId = 'group1';
|
||||||
|
|
||||||
|
mockDb.insert.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.values.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.returning.mockImplementationOnce(() => [mockPersonToGroup]);
|
||||||
|
|
||||||
|
const result = await service.addToGroup(personId, groupId);
|
||||||
|
|
||||||
|
expect(mockDb.insert).toHaveBeenCalled();
|
||||||
|
expect(mockDb.values).toHaveBeenCalledWith({
|
||||||
|
personId,
|
||||||
|
groupId,
|
||||||
|
});
|
||||||
|
expect(result).toEqual(mockPersonToGroup);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('removeFromGroup', () => {
|
||||||
|
it('should remove a person from a group', async () => {
|
||||||
|
const personId = 'person1';
|
||||||
|
const groupId = 'group1';
|
||||||
|
|
||||||
|
mockDb.delete.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.returning.mockImplementationOnce(() => [mockPersonToGroup]);
|
||||||
|
|
||||||
|
const result = await service.removeFromGroup(personId, groupId);
|
||||||
|
|
||||||
|
expect(mockDb.delete).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual(mockPersonToGroup);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw NotFoundException if relation not found', async () => {
|
||||||
|
const personId = 'nonexistent';
|
||||||
|
const groupId = 'group1';
|
||||||
|
|
||||||
|
mockDb.delete.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.returning.mockImplementationOnce(() => []);
|
||||||
|
|
||||||
|
await expect(service.removeFromGroup(personId, groupId)).rejects.toThrow(NotFoundException);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,116 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { ProjectsController } from './projects.controller';
|
||||||
|
import { ProjectsService } from '../services/projects.service';
|
||||||
|
import { CreateProjectDto } from '../dto/create-project.dto';
|
||||||
|
import { UpdateProjectDto } from '../dto/update-project.dto';
|
||||||
|
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
|
||||||
|
|
||||||
|
describe('ProjectsController', () => {
|
||||||
|
let controller: ProjectsController;
|
||||||
|
let service: ProjectsService;
|
||||||
|
|
||||||
|
// Mock data
|
||||||
|
const mockProject = {
|
||||||
|
id: 'project1',
|
||||||
|
name: 'Test Project',
|
||||||
|
description: 'Test Description',
|
||||||
|
ownerId: 'user1',
|
||||||
|
settings: {},
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [ProjectsController],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ProjectsService,
|
||||||
|
useValue: {
|
||||||
|
create: jest.fn().mockResolvedValue(mockProject),
|
||||||
|
findAll: jest.fn().mockResolvedValue([mockProject]),
|
||||||
|
findByOwnerId: jest.fn().mockResolvedValue([mockProject]),
|
||||||
|
findById: jest.fn().mockResolvedValue(mockProject),
|
||||||
|
update: jest.fn().mockResolvedValue(mockProject),
|
||||||
|
remove: jest.fn().mockResolvedValue(mockProject),
|
||||||
|
checkUserAccess: jest.fn().mockResolvedValue(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.overrideGuard(JwtAuthGuard)
|
||||||
|
.useValue({ canActivate: () => true })
|
||||||
|
.compile();
|
||||||
|
|
||||||
|
controller = module.get<ProjectsController>(ProjectsController);
|
||||||
|
service = module.get<ProjectsService>(ProjectsService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('create', () => {
|
||||||
|
it('should create a new project', async () => {
|
||||||
|
const createProjectDto: CreateProjectDto = {
|
||||||
|
name: 'Test Project',
|
||||||
|
description: 'Test Description',
|
||||||
|
ownerId: 'user1',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(await controller.create(createProjectDto)).toBe(mockProject);
|
||||||
|
expect(service.create).toHaveBeenCalledWith(createProjectDto);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findAll', () => {
|
||||||
|
it('should return all projects when no ownerId is provided', async () => {
|
||||||
|
expect(await controller.findAll()).toEqual([mockProject]);
|
||||||
|
expect(service.findAll).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return projects filtered by ownerId when ownerId is provided', async () => {
|
||||||
|
const ownerId = 'user1';
|
||||||
|
expect(await controller.findAll(ownerId)).toEqual([mockProject]);
|
||||||
|
expect(service.findByOwnerId).toHaveBeenCalledWith(ownerId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findOne', () => {
|
||||||
|
it('should return a project by ID', async () => {
|
||||||
|
const id = 'project1';
|
||||||
|
expect(await controller.findOne(id)).toBe(mockProject);
|
||||||
|
expect(service.findById).toHaveBeenCalledWith(id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('update', () => {
|
||||||
|
it('should update a project', async () => {
|
||||||
|
const id = 'project1';
|
||||||
|
const updateProjectDto: UpdateProjectDto = {
|
||||||
|
name: 'Updated Project',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(await controller.update(id, updateProjectDto)).toBe(mockProject);
|
||||||
|
expect(service.update).toHaveBeenCalledWith(id, updateProjectDto);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('remove', () => {
|
||||||
|
it('should delete a project', async () => {
|
||||||
|
const id = 'project1';
|
||||||
|
expect(await controller.remove(id)).toBe(mockProject);
|
||||||
|
expect(service.remove).toHaveBeenCalledWith(id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkUserAccess', () => {
|
||||||
|
it('should check if a user has access to a project', async () => {
|
||||||
|
const projectId = 'project1';
|
||||||
|
const userId = 'user1';
|
||||||
|
|
||||||
|
expect(await controller.checkUserAccess(projectId, userId)).toBe(true);
|
||||||
|
expect(service.checkUserAccess).toHaveBeenCalledWith(projectId, userId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
217
backend/src/modules/projects/services/projects.service.spec.ts
Normal file
217
backend/src/modules/projects/services/projects.service.spec.ts
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { ProjectsService } from './projects.service';
|
||||||
|
import { NotFoundException } from '@nestjs/common';
|
||||||
|
import { DRIZZLE } from '../../../database/database.module';
|
||||||
|
|
||||||
|
describe('ProjectsService', () => {
|
||||||
|
let service: ProjectsService;
|
||||||
|
let mockDb: any;
|
||||||
|
|
||||||
|
// Mock data
|
||||||
|
const mockProject = {
|
||||||
|
id: 'project1',
|
||||||
|
name: 'Test Project',
|
||||||
|
description: 'Test Description',
|
||||||
|
ownerId: 'user1',
|
||||||
|
settings: {},
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock database operations
|
||||||
|
const mockDbOperations = {
|
||||||
|
select: jest.fn().mockReturnThis(),
|
||||||
|
from: jest.fn().mockReturnThis(),
|
||||||
|
where: jest.fn().mockReturnThis(),
|
||||||
|
insert: jest.fn().mockReturnThis(),
|
||||||
|
values: jest.fn().mockReturnThis(),
|
||||||
|
update: jest.fn().mockReturnThis(),
|
||||||
|
set: jest.fn().mockReturnThis(),
|
||||||
|
delete: jest.fn().mockReturnThis(),
|
||||||
|
returning: jest.fn().mockImplementation(() => {
|
||||||
|
return [mockProject];
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
mockDb = {
|
||||||
|
...mockDbOperations,
|
||||||
|
};
|
||||||
|
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
ProjectsService,
|
||||||
|
{
|
||||||
|
provide: DRIZZLE,
|
||||||
|
useValue: mockDb,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<ProjectsService>(ProjectsService);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('create', () => {
|
||||||
|
it('should create a new project', async () => {
|
||||||
|
const createProjectDto = {
|
||||||
|
name: 'Test Project',
|
||||||
|
description: 'Test Description',
|
||||||
|
ownerId: 'user1',
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await service.create(createProjectDto);
|
||||||
|
|
||||||
|
expect(mockDb.insert).toHaveBeenCalled();
|
||||||
|
expect(mockDb.values).toHaveBeenCalledWith(createProjectDto);
|
||||||
|
expect(result).toEqual(mockProject);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findAll', () => {
|
||||||
|
it('should return all projects', async () => {
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => [mockProject]);
|
||||||
|
|
||||||
|
const result = await service.findAll();
|
||||||
|
|
||||||
|
expect(mockDb.select).toHaveBeenCalled();
|
||||||
|
expect(mockDb.from).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual([mockProject]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findByOwnerId', () => {
|
||||||
|
it('should return projects for a specific owner', async () => {
|
||||||
|
const ownerId = 'user1';
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => [mockProject]);
|
||||||
|
|
||||||
|
const result = await service.findByOwnerId(ownerId);
|
||||||
|
|
||||||
|
expect(mockDb.select).toHaveBeenCalled();
|
||||||
|
expect(mockDb.from).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual([mockProject]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findById', () => {
|
||||||
|
it('should return a project by ID', async () => {
|
||||||
|
const id = 'project1';
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => [mockProject]);
|
||||||
|
|
||||||
|
const result = await service.findById(id);
|
||||||
|
|
||||||
|
expect(mockDb.select).toHaveBeenCalled();
|
||||||
|
expect(mockDb.from).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual(mockProject);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw NotFoundException if project not found', async () => {
|
||||||
|
const id = 'nonexistent';
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => []);
|
||||||
|
|
||||||
|
await expect(service.findById(id)).rejects.toThrow(NotFoundException);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('update', () => {
|
||||||
|
it('should update a project', async () => {
|
||||||
|
const id = 'project1';
|
||||||
|
const updateProjectDto = {
|
||||||
|
name: 'Updated Project',
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await service.update(id, updateProjectDto);
|
||||||
|
|
||||||
|
expect(mockDb.update).toHaveBeenCalled();
|
||||||
|
expect(mockDb.set).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual(mockProject);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw NotFoundException if project not found', async () => {
|
||||||
|
const id = 'nonexistent';
|
||||||
|
const updateProjectDto = {
|
||||||
|
name: 'Updated Project',
|
||||||
|
};
|
||||||
|
|
||||||
|
mockDb.update.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.set.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.returning.mockImplementationOnce(() => []);
|
||||||
|
|
||||||
|
await expect(service.update(id, updateProjectDto)).rejects.toThrow(NotFoundException);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('remove', () => {
|
||||||
|
it('should delete a project', async () => {
|
||||||
|
const id = 'project1';
|
||||||
|
|
||||||
|
const result = await service.remove(id);
|
||||||
|
|
||||||
|
expect(mockDb.delete).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual(mockProject);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw NotFoundException if project not found', async () => {
|
||||||
|
const id = 'nonexistent';
|
||||||
|
|
||||||
|
mockDb.delete.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.returning.mockImplementationOnce(() => []);
|
||||||
|
|
||||||
|
await expect(service.remove(id)).rejects.toThrow(NotFoundException);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkUserAccess', () => {
|
||||||
|
it('should return true if user has access to project', async () => {
|
||||||
|
const projectId = 'project1';
|
||||||
|
const userId = 'user1';
|
||||||
|
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => [mockProject]);
|
||||||
|
|
||||||
|
const result = await service.checkUserAccess(projectId, userId);
|
||||||
|
|
||||||
|
expect(mockDb.select).toHaveBeenCalled();
|
||||||
|
expect(mockDb.from).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if user does not have access to project', async () => {
|
||||||
|
const projectId = 'project1';
|
||||||
|
const userId = 'user2';
|
||||||
|
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => []);
|
||||||
|
|
||||||
|
const result = await service.checkUserAccess(projectId, userId);
|
||||||
|
|
||||||
|
expect(mockDb.select).toHaveBeenCalled();
|
||||||
|
expect(mockDb.from).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user