Couverture des processors (RefreshToken, RequestPasswordReset, ResetPassword, SwitchRole, UpdateUserRoles), des query handlers (HasGradesInPeriod, HasStudentsInClass), des messaging handlers (SendActivationConfirmation, SendPasswordResetEmail), et côté frontend des modules auth, roles, monitoring, types et E2E tokens.
196 lines
5.8 KiB
PHP
196 lines
5.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Unit\Administration\Infrastructure\Messaging;
|
|
|
|
use App\Administration\Domain\Event\CompteActive;
|
|
use App\Administration\Domain\Model\User\Role;
|
|
use App\Administration\Infrastructure\Messaging\SendActivationConfirmationHandler;
|
|
use App\Shared\Domain\Tenant\TenantId;
|
|
use DateTimeImmutable;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Ramsey\Uuid\Uuid;
|
|
use Symfony\Component\Mailer\MailerInterface;
|
|
use Symfony\Component\Mime\Email;
|
|
use Twig\Environment;
|
|
|
|
/**
|
|
* Tests for SendActivationConfirmationHandler.
|
|
*
|
|
* Key invariants:
|
|
* - Sends email to the activated user's address
|
|
* - Uses the correct Twig template
|
|
* - Login URL is constructed from appUrl
|
|
* - Role label is resolved from Role enum
|
|
*/
|
|
final class SendActivationConfirmationHandlerTest extends TestCase
|
|
{
|
|
private const string APP_URL = 'https://ecole-alpha.classeo.fr';
|
|
private const string FROM_EMAIL = 'noreply@classeo.fr';
|
|
|
|
private MailerInterface $mailer;
|
|
private Environment $twig;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->mailer = $this->createMock(MailerInterface::class);
|
|
$this->twig = $this->createMock(Environment::class);
|
|
}
|
|
|
|
#[Test]
|
|
public function sendsEmailToActivatedUser(): void
|
|
{
|
|
$event = $this->createEvent('user@example.com', Role::PROF->value);
|
|
|
|
$this->twig->method('render')->willReturn('<p>Votre compte est actif.</p>');
|
|
|
|
$sentEmail = null;
|
|
$this->mailer->expects(self::once())
|
|
->method('send')
|
|
->with(self::callback(static function (Email $email) use (&$sentEmail): bool {
|
|
$sentEmail = $email;
|
|
|
|
return true;
|
|
}));
|
|
|
|
$handler = new SendActivationConfirmationHandler(
|
|
$this->mailer,
|
|
$this->twig,
|
|
self::APP_URL,
|
|
self::FROM_EMAIL,
|
|
);
|
|
|
|
($handler)($event);
|
|
|
|
self::assertNotNull($sentEmail);
|
|
self::assertSame('user@example.com', $sentEmail->getTo()[0]->getAddress());
|
|
self::assertSame(self::FROM_EMAIL, $sentEmail->getFrom()[0]->getAddress());
|
|
self::assertSame('Votre compte Classeo est activé', $sentEmail->getSubject());
|
|
}
|
|
|
|
#[Test]
|
|
public function rendersTemplateWithCorrectVariables(): void
|
|
{
|
|
$event = $this->createEvent('teacher@example.com', Role::PROF->value);
|
|
|
|
$this->twig->expects(self::once())
|
|
->method('render')
|
|
->with(
|
|
'emails/activation_confirmation.html.twig',
|
|
self::callback(static function (array $vars): bool {
|
|
return $vars['email'] === 'teacher@example.com'
|
|
&& $vars['role'] === 'Enseignant'
|
|
&& $vars['loginUrl'] === 'https://ecole-alpha.classeo.fr/login';
|
|
}),
|
|
)
|
|
->willReturn('<p>HTML</p>');
|
|
|
|
$this->mailer->method('send');
|
|
|
|
$handler = new SendActivationConfirmationHandler(
|
|
$this->mailer,
|
|
$this->twig,
|
|
self::APP_URL,
|
|
self::FROM_EMAIL,
|
|
);
|
|
|
|
($handler)($event);
|
|
}
|
|
|
|
#[Test]
|
|
public function handlesTrailingSlashInAppUrl(): void
|
|
{
|
|
$event = $this->createEvent('user@example.com', Role::PARENT->value);
|
|
|
|
$this->twig->expects(self::once())
|
|
->method('render')
|
|
->with(
|
|
self::anything(),
|
|
self::callback(static function (array $vars): bool {
|
|
// Should not have double slash
|
|
return $vars['loginUrl'] === 'https://ecole-alpha.classeo.fr/login';
|
|
}),
|
|
)
|
|
->willReturn('<p>HTML</p>');
|
|
|
|
$this->mailer->method('send');
|
|
|
|
$handler = new SendActivationConfirmationHandler(
|
|
$this->mailer,
|
|
$this->twig,
|
|
'https://ecole-alpha.classeo.fr/',
|
|
self::FROM_EMAIL,
|
|
);
|
|
|
|
($handler)($event);
|
|
}
|
|
|
|
#[Test]
|
|
public function usesRoleLabelForKnownRoles(): void
|
|
{
|
|
$event = $this->createEvent('admin@example.com', Role::ADMIN->value);
|
|
|
|
$this->twig->expects(self::once())
|
|
->method('render')
|
|
->with(
|
|
self::anything(),
|
|
self::callback(static function (array $vars): bool {
|
|
return $vars['role'] === 'Directeur';
|
|
}),
|
|
)
|
|
->willReturn('<p>HTML</p>');
|
|
|
|
$this->mailer->method('send');
|
|
|
|
$handler = new SendActivationConfirmationHandler(
|
|
$this->mailer,
|
|
$this->twig,
|
|
self::APP_URL,
|
|
self::FROM_EMAIL,
|
|
);
|
|
|
|
($handler)($event);
|
|
}
|
|
|
|
#[Test]
|
|
public function fallsBackToRawStringForUnknownRole(): void
|
|
{
|
|
$event = $this->createEvent('user@example.com', 'ROLE_CUSTOM');
|
|
|
|
$this->twig->expects(self::once())
|
|
->method('render')
|
|
->with(
|
|
self::anything(),
|
|
self::callback(static function (array $vars): bool {
|
|
return $vars['role'] === 'ROLE_CUSTOM';
|
|
}),
|
|
)
|
|
->willReturn('<p>HTML</p>');
|
|
|
|
$this->mailer->method('send');
|
|
|
|
$handler = new SendActivationConfirmationHandler(
|
|
$this->mailer,
|
|
$this->twig,
|
|
self::APP_URL,
|
|
self::FROM_EMAIL,
|
|
);
|
|
|
|
($handler)($event);
|
|
}
|
|
|
|
private function createEvent(string $email, string $role): CompteActive
|
|
{
|
|
return new CompteActive(
|
|
userId: '550e8400-e29b-41d4-a716-446655440001',
|
|
email: $email,
|
|
tenantId: TenantId::fromString('a1b2c3d4-e5f6-7890-abcd-ef1234567890'),
|
|
role: $role,
|
|
occurredOn: new DateTimeImmutable('2026-02-15 10:00:00'),
|
|
aggregateId: Uuid::uuid4(),
|
|
);
|
|
}
|
|
}
|