feat(#161): admin peut créer gestionnaire et administrateur.

Assouplit POST /gestionnaires, PATCH /gestionnaires/:id et POST /users/admin
(+ check createAdmin) pour ADMINISTRATEUR. Masque « Ajouter » staff sur le
dashboard gestionnaire. Tests droits Roles + createAdmin.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-10 22:54:49 +02:00
co-authored by Cursor
parent ca07d2e111
commit 9cd180bf6a
9 changed files with 146 additions and 51 deletions
+78 -9
View File
@@ -1,18 +1,87 @@
import { Test, TestingModule } from '@nestjs/testing';
import { BadRequestException, ForbiddenException } from '@nestjs/common';
import { UserService } from './user.service';
import { RoleType, StatutUtilisateurType } from 'src/entities/users.entity';
describe('UserService.createAdmin (#161)', () => {
const usersRepository = {
findOneBy: jest.fn(),
create: jest.fn(),
save: jest.fn(),
};
describe('UserService', () => {
let service: UserService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UserService],
}).compile();
const dto = {
email: 'nouveau.admin@ptits-pas.fr',
password: 'Password1!',
prenom: 'Nina',
nom: 'Admin',
telephone: '0601020304',
};
service = module.get<UserService>(UserService);
beforeEach(() => {
jest.clearAllMocks();
service = new UserService(
usersRepository as never,
{} as never,
{} as never,
{} as never,
{} as never,
{} as never,
);
});
it('should be defined', () => {
expect(service).toBeDefined();
it('autorise un administrateur à créer un admin', async () => {
usersRepository.findOneBy.mockResolvedValue(null);
usersRepository.create.mockImplementation((data) => data);
usersRepository.save.mockImplementation(async (entity) => ({
id: 'new-admin',
...entity,
}));
const result = await service.createAdmin(dto as never, {
id: 'admin-1',
role: RoleType.ADMINISTRATEUR,
} as never);
expect(result.role).toBe(RoleType.ADMINISTRATEUR);
expect(result.statut).toBe(StatutUtilisateurType.ACTIF);
expect(usersRepository.save).toHaveBeenCalled();
});
it('autorise un super_admin à créer un admin', async () => {
usersRepository.findOneBy.mockResolvedValue(null);
usersRepository.create.mockImplementation((data) => data);
usersRepository.save.mockImplementation(async (entity) => ({
id: 'new-admin',
...entity,
}));
await expect(
service.createAdmin(dto as never, {
id: 'sa-1',
role: RoleType.SUPER_ADMIN,
} as never),
).resolves.toMatchObject({ role: RoleType.ADMINISTRATEUR });
});
it('refuse un gestionnaire (403 métier)', async () => {
await expect(
service.createAdmin(dto as never, {
id: 'gest-1',
role: RoleType.GESTIONNAIRE,
} as never),
).rejects.toBeInstanceOf(ForbiddenException);
expect(usersRepository.save).not.toHaveBeenCalled();
});
it('refuse un email déjà utilisé', async () => {
usersRepository.findOneBy.mockResolvedValue({ id: 'exists' });
await expect(
service.createAdmin(dto as never, {
id: 'admin-1',
role: RoleType.ADMINISTRATEUR,
} as never),
).rejects.toBeInstanceOf(BadRequestException);
});
});