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:
Mathis H (Avnyr) 2025-05-15 20:48:42 +02:00
parent 269ba622f8
commit 576d063e52
2 changed files with 377 additions and 0 deletions

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

View 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],
});
});
});
});