Files
Classeo/backend/tests/Unit/Administration/Application/Command/RemoveRole/RemoveRoleHandlerTest.php
Mathias STRASSER 44ebe5e511 feat: Liaison parents-enfants avec gestion des tuteurs
Les parents doivent pouvoir suivre la scolarité de leurs enfants (notes,
emploi du temps, devoirs). Cela nécessite un lien formalisé entre le
compte parent et le compte élève, géré par les administrateurs.

Le lien est établi soit manuellement via l'interface d'administration,
soit automatiquement lors de l'activation du compte parent lorsque
l'invitation inclut un élève cible. Ce lien conditionne l'accès aux
données scolaires de l'enfant (autorisations vérifiées par un voter
dédié).
2026-02-12 08:38:19 +01:00

195 lines
5.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests\Unit\Administration\Application\Command\RemoveRole;
use App\Administration\Application\Command\RemoveRole\RemoveRoleCommand;
use App\Administration\Application\Command\RemoveRole\RemoveRoleHandler;
use App\Administration\Domain\Exception\DernierRoleNonRetirableException;
use App\Administration\Domain\Exception\RoleNonAttribueException;
use App\Administration\Domain\Exception\UserNotFoundException;
use App\Administration\Domain\Model\User\Email;
use App\Administration\Domain\Model\User\Role;
use App\Administration\Domain\Model\User\User;
use App\Administration\Infrastructure\Persistence\InMemory\InMemoryUserRepository;
use App\Shared\Domain\Clock;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;
use InvalidArgumentException;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
final class RemoveRoleHandlerTest extends TestCase
{
private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440002';
private const string SCHOOL_NAME = 'École Alpha';
private InMemoryUserRepository $userRepository;
private Clock $clock;
private RemoveRoleHandler $handler;
protected function setUp(): void
{
$this->userRepository = new InMemoryUserRepository();
$this->clock = new class implements Clock {
public function now(): DateTimeImmutable
{
return new DateTimeImmutable('2026-02-07 10:00:00');
}
};
$this->handler = new RemoveRoleHandler($this->userRepository, $this->clock);
}
#[Test]
public function removesRoleSuccessfully(): void
{
$user = $this->createUserWithMultipleRoles();
$command = new RemoveRoleCommand(
userId: (string) $user->id,
role: Role::VIE_SCOLAIRE->value,
);
$result = ($this->handler)($command);
self::assertTrue($result->aLeRole(Role::PROF));
self::assertFalse($result->aLeRole(Role::VIE_SCOLAIRE));
self::assertCount(1, $result->roles);
}
#[Test]
public function savesUserAfterRemoval(): void
{
$user = $this->createUserWithMultipleRoles();
$command = new RemoveRoleCommand(
userId: (string) $user->id,
role: Role::VIE_SCOLAIRE->value,
);
($this->handler)($command);
$found = $this->userRepository->get($user->id);
self::assertFalse($found->aLeRole(Role::VIE_SCOLAIRE));
}
#[Test]
public function throwsWhenRemovingLastRole(): void
{
$user = $this->createAndSaveUser(Role::PROF);
$command = new RemoveRoleCommand(
userId: (string) $user->id,
role: Role::PROF->value,
);
$this->expectException(DernierRoleNonRetirableException::class);
($this->handler)($command);
}
#[Test]
public function throwsWhenRoleNotAssigned(): void
{
$user = $this->createAndSaveUser(Role::PROF);
$command = new RemoveRoleCommand(
userId: (string) $user->id,
role: Role::ADMIN->value,
);
$this->expectException(RoleNonAttribueException::class);
($this->handler)($command);
}
#[Test]
public function throwsWhenUserNotFound(): void
{
$command = new RemoveRoleCommand(
userId: '550e8400-e29b-41d4-a716-446655440099',
role: Role::PROF->value,
);
$this->expectException(UserNotFoundException::class);
($this->handler)($command);
}
#[Test]
public function throwsWhenRoleIsInvalid(): void
{
$user = $this->createAndSaveUser(Role::PROF);
$command = new RemoveRoleCommand(
userId: (string) $user->id,
role: 'ROLE_INEXISTANT',
);
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Rôle invalide');
($this->handler)($command);
}
#[Test]
public function throwsWhenTenantIdDoesNotMatch(): void
{
$user = $this->createUserWithMultipleRoles();
$command = new RemoveRoleCommand(
userId: (string) $user->id,
role: Role::VIE_SCOLAIRE->value,
tenantId: '550e8400-e29b-41d4-a716-446655440099',
);
$this->expectException(UserNotFoundException::class);
($this->handler)($command);
}
#[Test]
public function allowsRemovalWhenTenantIdMatches(): void
{
$user = $this->createUserWithMultipleRoles();
$command = new RemoveRoleCommand(
userId: (string) $user->id,
role: Role::VIE_SCOLAIRE->value,
tenantId: self::TENANT_ID,
);
$result = ($this->handler)($command);
self::assertFalse($result->aLeRole(Role::VIE_SCOLAIRE));
}
private function createAndSaveUser(Role $role): User
{
$user = User::inviter(
email: new Email('user@example.com'),
role: $role,
tenantId: TenantId::fromString(self::TENANT_ID),
schoolName: self::SCHOOL_NAME,
firstName: 'Jean',
lastName: 'Dupont',
invitedAt: new DateTimeImmutable('2026-02-01 10:00:00'),
);
$user->pullDomainEvents();
$this->userRepository->save($user);
return $user;
}
private function createUserWithMultipleRoles(): User
{
$user = $this->createAndSaveUser(Role::PROF);
$user->attribuerRole(Role::VIE_SCOLAIRE, new DateTimeImmutable('2026-02-02 10:00:00'));
$user->pullDomainEvents();
$this->userRepository->save($user);
return $user;
}
}