test: add unit tests for users module
Added comprehensive unit tests for `UsersController` and `UsersService`, covering CRUD operations, GDPR consent updates, data export, and exception handling. Mocked `JwtAuthGuard` and database operations for all tests.
This commit is contained in:
parent
269ba622f8
commit
576d063e52
127
backend/src/modules/users/controllers/users.controller.spec.ts
Normal file
127
backend/src/modules/users/controllers/users.controller.spec.ts
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { UsersController } from './users.controller';
|
||||||
|
import { UsersService } from '../services/users.service';
|
||||||
|
import { CreateUserDto } from '../dto/create-user.dto';
|
||||||
|
import { UpdateUserDto } from '../dto/update-user.dto';
|
||||||
|
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
|
||||||
|
|
||||||
|
describe('UsersController', () => {
|
||||||
|
let controller: UsersController;
|
||||||
|
let service: UsersService;
|
||||||
|
|
||||||
|
// Mock data
|
||||||
|
const mockUser = {
|
||||||
|
id: 'user1',
|
||||||
|
name: 'Test User',
|
||||||
|
avatar: 'https://example.com/avatar.jpg',
|
||||||
|
githubId: '12345',
|
||||||
|
metadata: {},
|
||||||
|
gdprTimestamp: new Date(),
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockUserData = {
|
||||||
|
user: mockUser,
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
id: 'project1',
|
||||||
|
name: 'Test Project',
|
||||||
|
ownerId: 'user1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [UsersController],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: UsersService,
|
||||||
|
useValue: {
|
||||||
|
create: jest.fn().mockResolvedValue(mockUser),
|
||||||
|
findAll: jest.fn().mockResolvedValue([mockUser]),
|
||||||
|
findById: jest.fn().mockResolvedValue(mockUser),
|
||||||
|
update: jest.fn().mockResolvedValue(mockUser),
|
||||||
|
remove: jest.fn().mockResolvedValue(mockUser),
|
||||||
|
updateGdprConsent: jest.fn().mockResolvedValue(mockUser),
|
||||||
|
exportUserData: jest.fn().mockResolvedValue(mockUserData),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.overrideGuard(JwtAuthGuard)
|
||||||
|
.useValue({ canActivate: () => true })
|
||||||
|
.compile();
|
||||||
|
|
||||||
|
controller = module.get<UsersController>(UsersController);
|
||||||
|
service = module.get<UsersService>(UsersService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('create', () => {
|
||||||
|
it('should create a new user', async () => {
|
||||||
|
const createUserDto: CreateUserDto = {
|
||||||
|
name: 'Test User',
|
||||||
|
githubId: '12345',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(await controller.create(createUserDto)).toBe(mockUser);
|
||||||
|
expect(service.create).toHaveBeenCalledWith(createUserDto);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findAll', () => {
|
||||||
|
it('should return all users', async () => {
|
||||||
|
expect(await controller.findAll()).toEqual([mockUser]);
|
||||||
|
expect(service.findAll).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findOne', () => {
|
||||||
|
it('should return a user by ID', async () => {
|
||||||
|
const id = 'user1';
|
||||||
|
expect(await controller.findOne(id)).toBe(mockUser);
|
||||||
|
expect(service.findById).toHaveBeenCalledWith(id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('update', () => {
|
||||||
|
it('should update a user', async () => {
|
||||||
|
const id = 'user1';
|
||||||
|
const updateUserDto: UpdateUserDto = {
|
||||||
|
name: 'Updated User',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(await controller.update(id, updateUserDto)).toBe(mockUser);
|
||||||
|
expect(service.update).toHaveBeenCalledWith(id, updateUserDto);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('remove', () => {
|
||||||
|
it('should delete a user', async () => {
|
||||||
|
const id = 'user1';
|
||||||
|
expect(await controller.remove(id)).toBe(mockUser);
|
||||||
|
expect(service.remove).toHaveBeenCalledWith(id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('updateGdprConsent', () => {
|
||||||
|
it('should update GDPR consent timestamp', async () => {
|
||||||
|
const id = 'user1';
|
||||||
|
expect(await controller.updateGdprConsent(id)).toBe(mockUser);
|
||||||
|
expect(service.updateGdprConsent).toHaveBeenCalledWith(id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('exportUserData', () => {
|
||||||
|
it('should export user data', async () => {
|
||||||
|
const id = 'user1';
|
||||||
|
expect(await controller.exportUserData(id)).toBe(mockUserData);
|
||||||
|
expect(service.exportUserData).toHaveBeenCalledWith(id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
250
backend/src/modules/users/services/users.service.spec.ts
Normal file
250
backend/src/modules/users/services/users.service.spec.ts
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { UsersService } from './users.service';
|
||||||
|
import { NotFoundException } from '@nestjs/common';
|
||||||
|
import { DRIZZLE } from '../../../database/database.module';
|
||||||
|
|
||||||
|
describe('UsersService', () => {
|
||||||
|
let service: UsersService;
|
||||||
|
let mockDb: any;
|
||||||
|
|
||||||
|
// Mock data
|
||||||
|
const mockUser = {
|
||||||
|
id: 'user1',
|
||||||
|
name: 'Test User',
|
||||||
|
avatar: 'https://example.com/avatar.jpg',
|
||||||
|
githubId: '12345',
|
||||||
|
metadata: {},
|
||||||
|
gdprTimestamp: new Date(),
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockProject = {
|
||||||
|
id: 'project1',
|
||||||
|
name: 'Test Project',
|
||||||
|
ownerId: 'user1',
|
||||||
|
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 [mockUser];
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
mockDb = {
|
||||||
|
...mockDbOperations,
|
||||||
|
};
|
||||||
|
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
UsersService,
|
||||||
|
{
|
||||||
|
provide: DRIZZLE,
|
||||||
|
useValue: mockDb,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<UsersService>(UsersService);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('create', () => {
|
||||||
|
it('should create a new user', async () => {
|
||||||
|
const createUserDto = {
|
||||||
|
name: 'Test User',
|
||||||
|
githubId: '12345',
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await service.create(createUserDto);
|
||||||
|
|
||||||
|
expect(mockDb.insert).toHaveBeenCalled();
|
||||||
|
expect(mockDb.values).toHaveBeenCalledWith({
|
||||||
|
...createUserDto,
|
||||||
|
gdprTimestamp: expect.any(Date),
|
||||||
|
});
|
||||||
|
expect(result).toEqual(mockUser);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findAll', () => {
|
||||||
|
it('should return all users', async () => {
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => [mockUser]);
|
||||||
|
|
||||||
|
const result = await service.findAll();
|
||||||
|
|
||||||
|
expect(mockDb.select).toHaveBeenCalled();
|
||||||
|
expect(mockDb.from).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual([mockUser]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findById', () => {
|
||||||
|
it('should return a user by ID', async () => {
|
||||||
|
const id = 'user1';
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => [mockUser]);
|
||||||
|
|
||||||
|
const result = await service.findById(id);
|
||||||
|
|
||||||
|
expect(mockDb.select).toHaveBeenCalled();
|
||||||
|
expect(mockDb.from).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual(mockUser);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw NotFoundException if user 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('findByGithubId', () => {
|
||||||
|
it('should return a user by GitHub ID', async () => {
|
||||||
|
const githubId = '12345';
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => [mockUser]);
|
||||||
|
|
||||||
|
const result = await service.findByGithubId(githubId);
|
||||||
|
|
||||||
|
expect(mockDb.select).toHaveBeenCalled();
|
||||||
|
expect(mockDb.from).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual(mockUser);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined if user not found', async () => {
|
||||||
|
const githubId = 'nonexistent';
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => []);
|
||||||
|
|
||||||
|
const result = await service.findByGithubId(githubId);
|
||||||
|
|
||||||
|
expect(mockDb.select).toHaveBeenCalled();
|
||||||
|
expect(mockDb.from).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('update', () => {
|
||||||
|
it('should update a user', async () => {
|
||||||
|
const id = 'user1';
|
||||||
|
const updateUserDto = {
|
||||||
|
name: 'Updated User',
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await service.update(id, updateUserDto);
|
||||||
|
|
||||||
|
expect(mockDb.update).toHaveBeenCalled();
|
||||||
|
expect(mockDb.set).toHaveBeenCalledWith({
|
||||||
|
...updateUserDto,
|
||||||
|
updatedAt: expect.any(Date),
|
||||||
|
});
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual(mockUser);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw NotFoundException if user not found', async () => {
|
||||||
|
const id = 'nonexistent';
|
||||||
|
const updateUserDto = {
|
||||||
|
name: 'Updated User',
|
||||||
|
};
|
||||||
|
|
||||||
|
mockDb.update.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.set.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.returning.mockImplementationOnce(() => []);
|
||||||
|
|
||||||
|
await expect(service.update(id, updateUserDto)).rejects.toThrow(NotFoundException);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('remove', () => {
|
||||||
|
it('should delete a user', async () => {
|
||||||
|
const id = 'user1';
|
||||||
|
|
||||||
|
const result = await service.remove(id);
|
||||||
|
|
||||||
|
expect(mockDb.delete).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual(mockUser);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw NotFoundException if user 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('updateGdprConsent', () => {
|
||||||
|
it('should update GDPR consent timestamp', async () => {
|
||||||
|
const id = 'user1';
|
||||||
|
|
||||||
|
// Mock the update method
|
||||||
|
jest.spyOn(service, 'update').mockResolvedValueOnce(mockUser);
|
||||||
|
|
||||||
|
const result = await service.updateGdprConsent(id);
|
||||||
|
|
||||||
|
expect(service.update).toHaveBeenCalledWith(id, { gdprTimestamp: expect.any(Date) });
|
||||||
|
expect(result).toEqual(mockUser);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('exportUserData', () => {
|
||||||
|
it('should export user data', async () => {
|
||||||
|
const id = 'user1';
|
||||||
|
|
||||||
|
// Mock the findById method
|
||||||
|
jest.spyOn(service, 'findById').mockResolvedValueOnce(mockUser);
|
||||||
|
|
||||||
|
// Mock the database query for projects
|
||||||
|
mockDb.select.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.from.mockImplementationOnce(() => mockDbOperations);
|
||||||
|
mockDbOperations.where.mockImplementationOnce(() => [mockProject]);
|
||||||
|
|
||||||
|
const result = await service.exportUserData(id);
|
||||||
|
|
||||||
|
expect(service.findById).toHaveBeenCalledWith(id);
|
||||||
|
expect(mockDb.select).toHaveBeenCalled();
|
||||||
|
expect(mockDb.from).toHaveBeenCalled();
|
||||||
|
expect(mockDb.where).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual({
|
||||||
|
user: mockUser,
|
||||||
|
projects: [mockProject],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user